Files
lowkey_backtest/live_trading/config.py
Simon Moisy c4ecb29d4c Update trading configuration to allow full fund utilization and adjust base size calculation in strategy
- Changed `max_position_usdt` to -1.0 to indicate that all available funds should be used if the value is less than or equal to zero.
- Modified the base size calculation in `LiveRegimeStrategy` to accommodate the new logic for `max_position_usdt`, ensuring it uses all available funds when applicable.
2026-01-15 10:40:43 +08:00

121 lines
4.4 KiB
Python

"""
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