BotDeepSeek/config.py

146 lines
5.3 KiB
Python

import os
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional
_PROJECT_DIR = Path(__file__).resolve().parent
try:
from dotenv import load_dotenv
load_dotenv()
except ImportError:
pass
@dataclass
class IBConfig:
host: str = os.getenv("IB_HOST", "127.0.0.1")
port: int = int(os.getenv("IB_PORT", "4001"))
client_id: int = int(os.getenv("IB_CLIENT_ID", "1"))
account: Optional[str] = os.getenv("IB_ACCOUNT", "U4845070")
is_paper: bool = os.getenv("IB_PAPER", "false").lower() == "true"
@property
def port_label(self) -> str:
if self.port == 4002:
return "Gateway Paper (4002)"
elif self.port == 4001:
return "Gateway Live (4001)"
elif self.port == 7497:
return "TWS Paper (7497)"
elif self.port == 7496:
return "TWS Live (7496)"
return f"Unknown ({self.port})"
@dataclass
class StockStrategyConfig:
enabled: bool = True
symbols: list[str] = field(default_factory=lambda: ["AMZN", "AAPL", "NVDA", "NOK"])
currency: str = "USD"
exchange: str = "SMART"
bar_size: str = "1 min"
lookback_days: int = 5
fast_ma_period: int = 20
slow_ma_period: int = 50
trade_value_usd: float = 2000.0 # per-trade dollar amount; qty = floor(value / price)
min_profit_pct: float = 1.5
stop_loss_pct: float = 2.5
use_hard_stop: bool = True # place real GTC STP orders at the exchange
entry_confirm_bars: int = 2 # entry signal must hold for N consecutive bars
stop_cooldown_minutes: int = 30 # no re-entry on same symbol for N min after a stop-out
use_trailing_stop: bool = True # once profit >= min_profit, trail the stop below the peak high
trailing_stop_pct: float = 2.0 # trailing stop distance below peak high
adx_min: float = 30.0 # ADX trend filter for entries (was 25; 08-06 raised to avoid weak-trend whipsaw)
require_slow_ma_slope: bool = True # only enter if the slow MA is itself rising (no knife-catching in a downtrend) high
@dataclass
class ShortTermConfig:
enabled: bool = True
symbols: list[str] = field(default_factory=lambda: ["AMZN", "AAPL", "NVDA", "NOK"])
currency: str = "USD"
exchange: str = "SMART"
bar_size: str = "1 min"
lookback_days: int = 5
fast_ma_period: int = 5
slow_ma_period: int = 10
trade_value_usd: float = 2000.0
max_hold_days: int = 0 # 0 = unlimited hold (08-05 撤销 5 天上限)
min_profit_pct: float = 1.5
stop_loss_pct: float = 2.5
use_hard_stop: bool = True
entry_confirm_bars: int = 2
stop_cooldown_minutes: int = 30
use_trailing_stop: bool = True
trailing_stop_pct: float = 2.0
@dataclass
class ForexStrategyConfig:
enabled: bool = False
pairs: list[str] = field(default_factory=lambda: ["EUR.USD", "GBP.USD"])
exchange: str = "IDEALPRO"
bar_size: str = "1 min"
lookback_days: int = 5
fast_ma_period: int = 12
slow_ma_period: int = 26
trade_units: int = 3000
stop_loss_pct: float = 1.0
@dataclass
class MeanReversionConfig:
enabled: bool = True
symbols: list[str] = field(default_factory=lambda: ["AMZN", "AAPL", "NVDA", "NOK"])
currency: str = "USD"
exchange: str = "SMART"
bar_size: str = "1 min"
lookback_days: int = 5
trade_value_usd: float = 2000.0
rsi_period: int = 14
rsi_oversold: float = 30.0
rsi_overbought: float = 70.0
bb_period: int = 20
bb_std: float = 2.0
rapid_drop_pct: float = 1.0
rapid_drop_bars: int = 5
recovery_pct: float = 1.5
min_profit_pct: float = 1.5
stop_loss_pct: float = 2.5
use_hard_stop: bool = True
entry_confirm_bars: int = 2
stop_cooldown_minutes: int = 30
use_trailing_stop: bool = True
trailing_stop_pct: float = 2.0
trend_ma_period: int = 50 # mean-reversion buys only above this SMA
@dataclass
class AppConfig:
ib: IBConfig = field(default_factory=IBConfig)
stock: StockStrategyConfig = field(default_factory=StockStrategyConfig)
short_term: ShortTermConfig = field(default_factory=ShortTermConfig)
forex: ForexStrategyConfig = field(default_factory=ForexStrategyConfig)
mean_reversion: MeanReversionConfig = field(default_factory=MeanReversionConfig)
max_retries: int = 5
retry_delay: int = 5
loop_interval: float = 60.0
order_timeout: float = 30.0
max_positions: int = 12 # global cap on concurrent open lots across all strategies
max_daily_loss: float = 150.0 # stop opening new positions for the day beyond this realized loss
sell_only: bool = False # liquidation mode: no new buys, strategies only manage exits
max_symbol_value_usd: float = 2300.0 # per-symbol total position value cap (all strategies combined)
sell_cooldown_minutes: int = 30 # global: no strategy may (re)buy a symbol within N min of ANY sell
sell_improvement_pct: float = 0.5 # beyond the cooldown, re-buy only if price is >=0.5% below last sell
sell_improvement_window_minutes: int = 120 # how long the price-improvement rule applies after a sell
symbol_trade_value_usd: dict[str, float] = field(
# per-symbol per-trade dollar value override (halved for gap-prone NOK, 08-06)
default_factory=lambda: {"NOK": 1000.0}
)
# absolute path: independent of the working directory the bot is started from
state_file: str = str(_PROJECT_DIR / "bot_state.json")
config = AppConfig()