Wire up Hyperliquid testnet wallet and secure key management
Connected live node to Hyperliquid Testnet with wallet 0xc939...2507. Verified: 210 perps + 1309 spot instruments. Key management: - .env file (gitignored) for local development - .env.example as template - systemd Environment= for production - node.py loads from env var or .env fallback Wallet currently has 0 balance — needs mainnet deposit then testnet faucet claim before live trading.
This commit is contained in:
-175
@@ -1,175 +0,0 @@
|
|||||||
"""
|
|
||||||
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 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",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
private_key = os.getenv("HYPERLIQUID_TESTNET_PK")
|
|
||||||
if not private_key:
|
|
||||||
print("ERROR: Set HYPERLIQUID_TESTNET_PK environment variable")
|
|
||||||
print(" export HYPERLIQUID_TESTNET_PK=0x...")
|
|
||||||
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())
|
|
||||||
|
|||||||
Reference in New Issue
Block a user