feat: add per-symbol strategy params with sweep-optimized values

Support per-symbol strategy parameters (ATR_SL_MULT_XRPUSDT, etc.)
via env vars, falling back to global defaults. Sweep results:
- XRPUSDT: SL=1.5 TP=4.0 ADX=30 (PF 2.39, Sharpe 61.0)
- TRXUSDT: SL=1.0 TP=4.0 ADX=30 (PF 3.87, Sharpe 62.8)
- DOGEUSDT: SL=2.0 TP=2.0 ADX=30 (PF 1.80, Sharpe 44.1)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
21in7
2026-03-17 17:28:14 +09:00
parent 106eaf182b
commit 55c20012a3
9 changed files with 22658 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ class TradingBot:
def __init__(self, config: Config, symbol: str = None, risk: RiskManager = None):
self.config = config
self.symbol = symbol or config.symbol
self.strategy = config.get_symbol_params(self.symbol)
self.exchange = BinanceFuturesClient(config, symbol=self.symbol)
self.notifier = DiscordNotifier(config.discord_webhook_url)
self.risk = risk or RiskManager(config)
@@ -141,9 +142,9 @@ class TradingBot:
df_with_indicators = ind.calculate_all()
raw_signal, signal_detail = ind.get_signal(
df_with_indicators,
signal_threshold=self.config.signal_threshold,
adx_threshold=self.config.adx_threshold,
volume_multiplier=self.config.volume_multiplier,
signal_threshold=self.strategy.signal_threshold,
adx_threshold=self.strategy.adx_threshold,
volume_multiplier=self.strategy.volume_multiplier,
)
current_price = df_with_indicators["close"].iloc[-1]
@@ -198,8 +199,8 @@ class TradingBot:
logger.info(f"[{self.symbol}] 포지션 크기: 잔고={per_symbol_balance:.2f}/{balance:.2f} USDT, 증거금비율={margin_ratio:.1%}, 수량={quantity}")
stop_loss, take_profit = Indicators(df).get_atr_stop(
df, signal, price,
atr_sl_mult=self.config.atr_sl_mult,
atr_tp_mult=self.config.atr_tp_mult,
atr_sl_mult=self.strategy.atr_sl_mult,
atr_tp_mult=self.strategy.atr_tp_mult,
)
notional = quantity * price
@@ -429,7 +430,12 @@ class TradingBot:
self._is_reentering = False
async def run(self):
logger.info(f"[{self.symbol}] 봇 시작, 레버리지 {self.config.leverage}x")
s = self.strategy
logger.info(
f"[{self.symbol}] 봇 시작, 레버리지 {self.config.leverage}x | "
f"SL={s.atr_sl_mult}x TP={s.atr_tp_mult}x Signal≥{s.signal_threshold} "
f"ADX≥{s.adx_threshold} Vol≥{s.volume_multiplier}x"
)
await self._recover_position()
await self._init_oi_history()

View File

@@ -5,6 +5,16 @@ from dotenv import load_dotenv
load_dotenv()
@dataclass
class SymbolStrategyParams:
"""Per-symbol strategy parameters (from sweep optimization)."""
atr_sl_mult: float = 2.0
atr_tp_mult: float = 2.0
signal_threshold: int = 3
adx_threshold: float = 25.0
volume_multiplier: float = 2.5
@dataclass
class Config:
api_key: str = ""
@@ -57,3 +67,24 @@ class Config:
corr_env = os.getenv("CORRELATION_SYMBOLS", "BTCUSDT,ETHUSDT")
self.correlation_symbols = [s.strip() for s in corr_env.split(",") if s.strip()]
# Per-symbol strategy params: {symbol: SymbolStrategyParams}
self._symbol_params: dict[str, SymbolStrategyParams] = {}
for sym in self.symbols:
self._symbol_params[sym] = SymbolStrategyParams(
atr_sl_mult=float(os.getenv(f"ATR_SL_MULT_{sym}", str(self.atr_sl_mult))),
atr_tp_mult=float(os.getenv(f"ATR_TP_MULT_{sym}", str(self.atr_tp_mult))),
signal_threshold=int(os.getenv(f"SIGNAL_THRESHOLD_{sym}", str(self.signal_threshold))),
adx_threshold=float(os.getenv(f"ADX_THRESHOLD_{sym}", str(self.adx_threshold))),
volume_multiplier=float(os.getenv(f"VOL_MULTIPLIER_{sym}", str(self.volume_multiplier))),
)
def get_symbol_params(self, symbol: str) -> SymbolStrategyParams:
"""Get strategy params for a symbol. Falls back to global defaults."""
return self._symbol_params.get(symbol, SymbolStrategyParams(
atr_sl_mult=self.atr_sl_mult,
atr_tp_mult=self.atr_tp_mult,
signal_threshold=self.signal_threshold,
adx_threshold=self.adx_threshold,
volume_multiplier=self.volume_multiplier,
))