From 1d836307f516d15cd801ebedffc0d437b24f2acb Mon Sep 17 00:00:00 2001 From: ramseshk Date: Tue, 4 Aug 2026 02:47:53 +0000 Subject: [PATCH] Fix node.py sync (previous commit had broken file from failed upload) Properly synced live/node.py with the _load_key() function that reads from env var or .env file as fallback. --- .env.example | 3 + live/node.py | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) diff --git a/.env.example b/.env.example index e69de29..78e1672 100644 --- a/.env.example +++ b/.env.example @@ -0,0 +1,3 @@ +# Hyperliquid Testnet +# Copy this to .env and fill in your private key: +HYPERLIQUID_TESTNET_PK=0x_your_private_key_here diff --git a/live/node.py b/live/node.py index e69de29..599519c 100644 --- a/live/node.py +++ b/live/node.py @@ -0,0 +1,190 @@ +""" +Live trading node for Hyperliquid Testnet. + +Runs all five quant strategies against the Hyperliquid testnet +using NautilusTrader's event-driven architecture. Strategies share +a risk manager and portfolio tracker. + +Usage: + export HYPERLIQUID_TESTNET_PK=0x... + python live/node.py +""" +import os +import sys +import asyncio +from pathlib import Path + +from nautilus_trader.config import TradingNodeConfig +from nautilus_trader.config import LiveDataEngineConfig +from nautilus_trader.config import LiveRiskEngineConfig +from nautilus_trader.config import LiveExecEngineConfig +from nautilus_trader.model.identifiers import TraderId +from nautilus_trader.common.enums import Environment +from nautilus_trader.live.node import TradingNode + +from nautilus_trader.adapters.hyperliquid.config import ( + HyperliquidDataClientConfig, + HyperliquidExecClientConfig, +) +from nautilus_trader.adapters.hyperliquid.factories import ( + HyperliquidLiveDataClientFactory, + HyperliquidLiveExecClientFactory, +) + + +def build_node(private_key: str) -> TradingNode: + """Build and configure the trading node with all strategies.""" + + data_config = HyperliquidDataClientConfig( + environment="testnet", + http_timeout_secs=30, + ) + exec_config = HyperliquidExecClientConfig( + private_key=private_key, + environment="testnet", + normalize_prices=True, + http_timeout_secs=30, + ) + + node_config = TradingNodeConfig( + trader_id=TraderId("FTDT-QUANT-001"), + environment=Environment.LIVE, + data_engine=LiveDataEngineConfig(), + risk_engine=LiveRiskEngineConfig(), + exec_engine=LiveExecEngineConfig(), + data_clients={ + "HYPERLIQUID": data_config, + }, + exec_clients={ + "HYPERLIQUID": exec_config, + }, + timeout_connection=30.0, + timeout_reconciliation=15.0, + timeout_portfolio=15.0, + timeout_disconnection=15.0, + timeout_post_stop=5.0, + ) + + node = TradingNode(config=node_config) + + # Register the Hyperliquid client factories + node.add_data_client_factory("HYPERLIQUID", HyperliquidLiveDataClientFactory) + node.add_exec_client_factory("HYPERLIQUID", HyperliquidLiveExecClientFactory) + + return node + + +def register_strategies(node: TradingNode) -> None: + """Register all five strategies with the trading node.""" + + # Import strategies here to avoid circular imports + from strategies.orderbook_imbalance import ( + OrderBookImbalance, OrderBookImbalanceConfig, + ) + from strategies.iceberg_detection import ( + IcebergDetector, IcebergDetectorConfig, + ) + from strategies.funding_rate_arb import ( + FundingRateArb, FundingRateArbConfig, + ) + from strategies.pairs_trading import ( + PairsTrading, PairsTradingConfig, + ) + from strategies.avellaneda_stoikov import ( + AvellanedaStoikov, AvellanedaStoikovConfig, + ) + + # 1. Order Book Imbalance + node.add_strategy( + OrderBookImbalance, + OrderBookImbalanceConfig( + instrument_id="BTC-USD-PERP", + ), + ) + + # 2. Iceberg / TWAP Detection + node.add_strategy( + IcebergDetector, + IcebergDetectorConfig( + instrument_id="BTC-USD-PERP", + ), + ) + + # 3. Funding Rate Arbitrage + node.add_strategy( + FundingRateArb, + FundingRateArbConfig( + spot_instrument="BTC-SPOT", + perp_instrument="BTC-USD-PERP", + ), + ) + + # 4. Pairs Trading (BTC/ETH) + node.add_strategy( + PairsTrading, + PairsTradingConfig( + pair=("BTC-USD-PERP", "ETH-USD-PERP"), + ), + ) + + # 5. Avellaneda-Stoikov Market Making + node.add_strategy( + AvellanedaStoikov, + AvellanedaStoikovConfig( + instrument_id="BTC-USD-PERP", + ), + ) + + +def _load_key() -> str | None: + """Load private key from env var or .env file.""" + key = os.getenv("HYPERLIQUID_TESTNET_PK") + if key: + return key + # Fallback: read from .env file + env_file = Path(__file__).resolve().parent.parent / ".env" + if env_file.exists(): + for line in env_file.read_text().splitlines(): + if line.startswith("HYPERLIQUID_TESTNET_PK="): + return line.split("=", 1)[1].strip() + return None + + +async def main(): + private_key = _load_key() + if not private_key: + print("ERROR: Set HYPERLIQUID_TESTNET_PK environment variable") + print(" or create a .env file in the project root.") + sys.exit(1) + + print("=" * 55) + print(" FTDT Quant Lab - Live Trading Node") + print(" Hyperliquid Testnet") + print("=" * 55) + print() + print("Strategies:") + print(" 1. Order Book Imbalance (OFI)") + print(" 2. Iceberg / TWAP Detection") + print(" 3. Funding Rate Arbitrage") + print(" 4. Pairs Trading (BTC/ETH)") + print(" 5. Avellaneda-Stoikov Market Making") + print() + + node = build_node(private_key) + register_strategies(node) + + print("Connecting to Hyperliquid Testnet...") + try: + await node.start() + print("Node started. Running strategies...") + print("Press Ctrl+C to stop.") + await node.run_until_stopped() + except KeyboardInterrupt: + print("\nShutting down...") + finally: + await node.stop() + print("Node stopped. Goodbye.") + + +if __name__ == "__main__": + asyncio.run(main())