ㅇ Changes: - Introduced the DART strategy to the trading system, including its configuration and integration into the existing framework. - Updated the database schema to include DART-specific tables for disclosures and watchlists. - Enhanced the backtesting and parameter search functionalities to support the DART strategy. - Implemented new rules for browser verification and API interactions to ensure compliance with the updated DART strategy. Impact: - These additions expand the trading capabilities of the system, allowing for more comprehensive analysis and execution of DART-related strategies, while maintaining system integrity and performance.
96 lines
3.3 KiB
Python
96 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
kis_trader/backtest/param_search_dart.py — DART Optuna/Grid 축
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Dict, List
|
|
|
|
from database import TradeDB
|
|
from kis_trader.backtest.dart_backtest_common import run_dart_backtest_web_aligned
|
|
from kis_trader.engine import dart_engine as de
|
|
from kis_trader.utils.env import get_env_bool
|
|
|
|
|
|
def _dart_grids() -> Dict[str, Dict[str, List[Any]]]:
|
|
"""mode → 축. 실매 기본값이 각 축에 포함."""
|
|
d = de.get_dart_defaults_from_db()
|
|
rsi_os = float(d.get("rsi_oversold", 30))
|
|
rsi_rc = float(d.get("rsi_reclaim", 35))
|
|
sl = float(d.get("sl_pct", 0.02))
|
|
tp = float(d.get("tp_pct", 0.04))
|
|
vol = float(d.get("vol_mult", 1.5))
|
|
win = int(d.get("event_window_bars", 120))
|
|
return {
|
|
"fast": {
|
|
"rsi_oversold": sorted({rsi_os, 25.0, 30.0, 35.0}),
|
|
"rsi_reclaim": sorted({rsi_rc, 32.0, 35.0, 40.0}),
|
|
"sl_pct": sorted({sl, 0.015, 0.02, 0.025}),
|
|
"tp_pct": sorted({tp, 0.03, 0.04, 0.05}),
|
|
"vol_mult": sorted({vol, 1.2, 1.5, 2.0}),
|
|
"event_window_bars": sorted({win, 60, 120, 180}),
|
|
},
|
|
"coarse": {
|
|
"rsi_oversold": [20.0, 25.0, 30.0, 35.0],
|
|
"rsi_reclaim": [30.0, 35.0, 40.0, 45.0],
|
|
"sl_pct": [0.015, 0.02, 0.03],
|
|
"tp_pct": [0.03, 0.04, 0.06],
|
|
"vol_mult": [1.0, 1.5, 2.0, 2.5],
|
|
"event_window_bars": [60, 90, 120, 180],
|
|
"trail_pct": [0.01, 0.015, 0.02],
|
|
"trail_arm_pct": [0.015, 0.02, 0.03],
|
|
},
|
|
"fine": {
|
|
"rsi_oversold": sorted({rsi_os, rsi_os - 2, rsi_os + 2, 28.0, 30.0}),
|
|
"rsi_reclaim": sorted({rsi_rc, rsi_rc - 2, rsi_rc + 2, 35.0, 38.0}),
|
|
"sl_pct": sorted({sl, 0.018, 0.02, 0.022}),
|
|
"tp_pct": sorted({tp, 0.035, 0.04, 0.045}),
|
|
"vol_mult": sorted({vol, 1.3, 1.5, 1.8}),
|
|
"event_window_bars": sorted({win, 90, 120, 150}),
|
|
},
|
|
}
|
|
|
|
|
|
def apply_params_to_db(params: Dict[str, Any]) -> None:
|
|
"""Optuna --apply-best 전용. 포트폴리오 키 제외."""
|
|
if not get_env_bool("DART_TRADE_ENABLED", False):
|
|
# 적용은 허용하되 매매 스위치는 사용자 것 유지
|
|
pass
|
|
mapping = {
|
|
"rsi_oversold": "DART_RSI_OVERSOLD",
|
|
"rsi_reclaim": "DART_RSI_RECLAIM",
|
|
"sl_pct": "DART_STOP_LOSS_PCT",
|
|
"tp_pct": "DART_TAKE_PROFIT_PCT",
|
|
"vol_mult": "DART_VOL_MULT",
|
|
"event_window_bars": "DART_EVENT_WINDOW_BARS",
|
|
"trail_pct": "DART_TRAIL_PCT",
|
|
"trail_arm_pct": "DART_TRAIL_ARM_PCT",
|
|
"rsi_period": "DART_RSI_PERIOD",
|
|
"max_hold_bars": "DART_MAX_HOLD_BARS",
|
|
}
|
|
patch = {}
|
|
for k, env_k in mapping.items():
|
|
if k in params:
|
|
patch[env_k] = str(params[k])
|
|
if not patch:
|
|
return
|
|
db = TradeDB()
|
|
try:
|
|
db.insert_env_snapshot(patch)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def evaluate_dart_param_combo(
|
|
params: Dict[str, Any],
|
|
*,
|
|
start: str,
|
|
end: str,
|
|
env_row: Dict[str, Any],
|
|
) -> Dict[str, Any]:
|
|
base = de.get_dart_defaults_from_db(env_row=env_row)
|
|
base.update(params)
|
|
return run_dart_backtest_web_aligned(
|
|
start=start, end=end, params=base, env_row=env_row,
|
|
)
|