""" Configuration for Multi-Pair Live Trading. Extends the base live trading config with multi-pair specific settings. """ import os from pathlib import Path from dataclasses import dataclass, field from dotenv import load_dotenv load_dotenv() @dataclass class OKXConfig: """OKX API configuration.""" api_key: str = field(default_factory=lambda: "") secret: str = field(default_factory=lambda: "") password: str = field(default_factory=lambda: "") demo_mode: bool = field(default_factory=lambda: True) def __post_init__(self): """Load credentials based on demo mode setting.""" self.demo_mode = os.getenv("OKX_DEMO_MODE", "true").lower() in ("true", "1", "yes") if self.demo_mode: self.api_key = os.getenv("OKX_DEMO_API_KEY", os.getenv("OKX_API_KEY", "")) self.secret = os.getenv("OKX_DEMO_SECRET", os.getenv("OKX_SECRET", "")) self.password = os.getenv("OKX_DEMO_PASSWORD", os.getenv("OKX_PASSWORD", "")) else: self.api_key = os.getenv("OKX_API_KEY", "") self.secret = os.getenv("OKX_SECRET", "") self.password = os.getenv("OKX_PASSWORD", "") def validate(self) -> None: """Validate that required credentials are present.""" mode = "demo" if self.demo_mode else "live" if not self.api_key: raise ValueError(f"OKX API key not set for {mode} mode") if not self.secret: raise ValueError(f"OKX secret not set for {mode} mode") if not self.password: raise ValueError(f"OKX password not set for {mode} mode") @dataclass class MultiPairLiveConfig: """ Configuration for multi-pair live trading. Combines trading parameters, strategy settings, and risk management. """ # Asset Universe (top 10 by market cap perpetuals) assets: list[str] = field(default_factory=lambda: [ "BTC/USDT:USDT", "ETH/USDT:USDT", "SOL/USDT:USDT", "XRP/USDT:USDT", "BNB/USDT:USDT", "DOGE/USDT:USDT", "ADA/USDT:USDT", "AVAX/USDT:USDT", "LINK/USDT:USDT", "DOT/USDT:USDT" ]) # Timeframe timeframe: str = "1h" candles_to_fetch: int = 500 # Enough for feature calculation # Z-Score Thresholds z_window: int = 24 z_entry_threshold: float = 1.0 z_exit_threshold: float = 0.0 # Exit at mean reversion # ML Thresholds prob_threshold: float = 0.5 # Position sizing max_position_usdt: float = -1.0 # If <= 0, use all available funds min_position_usdt: float = 10.0 leverage: int = 1 margin_mode: str = "cross" max_concurrent_positions: int = 1 # Trade one pair at a time # Risk Management - ATR-Based Stops atr_period: int = 14 sl_atr_multiplier: float = 10.0 tp_atr_multiplier: float = 8.0 # Fallback fixed percentages base_sl_pct: float = 0.06 base_tp_pct: float = 0.05 # ATR bounds min_sl_pct: float = 0.02 max_sl_pct: float = 0.10 min_tp_pct: float = 0.02 max_tp_pct: float = 0.15 # Funding Rate Filter funding_threshold: float = 0.0005 # 0.05% # Trade Management min_hold_bars: int = 0 cooldown_bars: int = 0 # Execution sleep_seconds: int = 3600 # Run every hour slippage_pct: float = 0.001 def get_asset_short_name(self, symbol: str) -> str: """Convert symbol to short name (e.g., BTC/USDT:USDT -> btc).""" return symbol.split("/")[0].lower() def get_pair_count(self) -> int: """Calculate number of unique pairs from asset list.""" n = len(self.assets) return n * (n - 1) // 2 @dataclass class PathConfig: """File paths configuration.""" base_dir: Path = field( default_factory=lambda: Path(__file__).parent.parent.parent ) data_dir: Path = field(default=None) logs_dir: Path = field(default=None) model_path: Path = field(default=None) positions_file: Path = field(default=None) trade_log_file: Path = field(default=None) def __post_init__(self): self.data_dir = self.base_dir / "data" self.logs_dir = self.base_dir / "logs" # Use the same model as backtesting self.model_path = self.base_dir / "data" / "multi_pair_model.pkl" self.positions_file = self.base_dir / "live_trading" / "multi_pair_positions.json" self.trade_log_file = self.base_dir / "live_trading" / "multi_pair_trade_log.csv" # Ensure directories exist self.data_dir.mkdir(parents=True, exist_ok=True) self.logs_dir.mkdir(parents=True, exist_ok=True) def get_multi_pair_config() -> tuple[OKXConfig, MultiPairLiveConfig, PathConfig]: """Get all configuration objects for multi-pair trading.""" okx = OKXConfig() trading = MultiPairLiveConfig() paths = PathConfig() return okx, trading, paths