""" Configuration for Live Trading. Loads OKX API credentials from environment variables. Uses demo/sandbox mode by default for paper trading. """ import os from pathlib import Path from dataclasses import dataclass, field from dotenv import load_dotenv # Load .env from sibling project (BTC_spot_MVRV) ENV_PATH = Path(__file__).parent.parent.parent / "BTC_spot_MVRV" / ".env" if ENV_PATH.exists(): load_dotenv(ENV_PATH) else: # Fallback to local .env 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.""" # Check demo mode first self.demo_mode = os.getenv("OKX_DEMO_MODE", "true").lower() in ("true", "1", "yes") if self.demo_mode: # Load demo-specific credentials if available 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: # Load live credentials 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 TradingConfig: """Trading parameters configuration.""" # Trading pairs eth_symbol: str = "ETH/USDT:USDT" # ETH perpetual (primary trading asset) btc_symbol: str = "BTC/USDT:USDT" # BTC perpetual (context asset) # Timeframe timeframe: str = "1h" candles_to_fetch: int = 500 # Enough for feature calculation # Position sizing max_position_usdt: float = -1.0 # Max position size in USDT. If <= 0, use all available funds min_position_usdt: float = 10.0 # Min position size in USDT leverage: int = 1 # Leverage (1x = no leverage) margin_mode: str = "cross" # "cross" or "isolated" # Risk management stop_loss_pct: float = 0.06 # 6% stop loss take_profit_pct: float = 0.05 # 5% take profit max_concurrent_positions: int = 1 # Max open positions # Strategy parameters (from regime_strategy.py) z_entry_threshold: float = 1.0 # Enter when |Z| > 1.0 z_window: int = 24 # 24h rolling Z-score window model_prob_threshold: float = 0.5 # ML model probability threshold funding_threshold: float = 0.005 # Funding rate filter threshold # Execution sleep_seconds: int = 3600 # Run every hour (1h candles) slippage_pct: float = 0.001 # 0.1% slippage buffer @dataclass class PathConfig: """File paths configuration.""" base_dir: Path = field( default_factory=lambda: Path(__file__).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) cq_data_path: Path = field(default=None) def __post_init__(self): self.data_dir = self.base_dir / "data" self.logs_dir = self.base_dir / "logs" self.model_path = self.base_dir / "live_trading" / "regime_model.pkl" self.positions_file = self.base_dir / "live_trading" / "positions.json" self.trade_log_file = self.base_dir / "live_trading" / "trade_log.csv" self.cq_data_path = self.data_dir / "cq_training_data.csv" # Ensure directories exist self.data_dir.mkdir(parents=True, exist_ok=True) self.logs_dir.mkdir(parents=True, exist_ok=True) def get_config(): """Get all configuration objects.""" okx = OKXConfig() trading = TradingConfig() paths = PathConfig() return okx, trading, paths