Files
kis_bot/scripts/tail_symbol_gate_verify_20260709.py
Your Name fc27e726f9 feat: 새로운 안전 규칙 및 최적화 적용을 통한 트레이딩 시스템 개선
변경 사항 (Changes):

구문 오류(Syntax error) 및 토큰 낭비를 방지하기 위해 에이전트 쉘(Agent shell)과 파이썬 코드 스니펫에 다수의 신규 안전 규칙(Safety rules)을 추가함.

스키마 검증 및 적절한 SQL 포맷팅을 보장하기 위해 임시(Ad-hoc) 데이터베이스 쿼리 작성 가이드라인을 도입함.

코드 수정 후 UI 기능이 정상 작동하는지 확인하기 위해, 백테스트 웹 서비스 재시작 및 브라우저 검증에 대한 새로운 규칙을 구현함.

시스템 전반의 무결성(Integrity)을 유지하기 위해 실전 매매(Live trading), 웹 백테스팅, 파라미터 탐색(Parameter searches) 간의 일관성 검사(Consistency checks) 체계를 확립함.

기대 효과 (Impact):

이러한 개선 사항들은 트레이딩 시스템의 견고성(Robustness)과 신뢰성을 향상시키며, 에러 발생을 최소화하고 다양한 시스템 컴포넌트 간의 원활한 상호작용을 보장함.
2026-07-17 01:09:09 +09:00

127 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""7/9 SHORT 종목일일손익게이트 백테 검증 — Case A(edge=2000) vs B(edge=0)."""
from __future__ import annotations
import sys
import traceback
from collections import defaultdict
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from database import TradeDB
from kis_trader.engine import tail_engine as te
from kis_trader.backtest import tail_backtest_common as tbc
from kis_trader.engine.tail_tick_replay import tail_backtest_wants_tick_replay
def _summarize(trades, label: str) -> dict:
total = len(trades)
wins = [t for t in trades if float(t.get("pnl") or 0) > 0]
pnl = sum(float(t.get("pnl") or 0) for t in trades)
by_code: dict = defaultdict(list)
for t in trades:
by_code[t.get("code")].append(t)
multi = sum(1 for v in by_code.values() if len(v) > 1)
wr = (len(wins) / total * 100) if total else 0.0
print(
f" trades={total} wins={len(wins)} WR={wr:.1f}% "
f"pnl={pnl:+,.0f} multi_codes={multi}",
flush=True,
)
for code, ts in sorted(by_code.items()):
cum = 0.0
parts = []
for t in ts:
cum += float(t.get("pnl") or 0)
hm = str(t.get("entry_time") or t.get("candle_time") or "")[8:12]
parts.append(
f"{hm}:{t.get('pnl', 0):+.0f}({t.get('exit_reason', '')})→cum{cum:+.0f}"
)
if len(ts) > 1:
print(f" [{code}] " + " | ".join(parts), flush=True)
return {"label": label, "trades": total, "pnl": pnl, "multi": multi}
def main() -> int:
print("=== 7/9 SHORT 게이트 백테 검증 (skip_hts=DB) ===", flush=True)
db = TradeDB()
start, end = "2026-07-09", "2026-07-09"
start_key = start.replace("-", "") + "0000"
end_key = end.replace("-", "") + "2359"
start_ymd, end_ymd = start_key[:8], end_key[:8]
try:
base = te.get_tail_defaults_from_db(db)
skip_hts = bool(base.get("skip_hts_scan_dupes"))
print(f"skip_hts_scan_dupes(DB)={skip_hts}", flush=True)
universe, src, n_slots, _ = tbc.resolve_tail_universe(
start_ymd, end_ymd, use_saved_history=True, strategy_id="SHORT",
)
tf = int(base.get("timeframe") or 3)
rsi = int(base.get("rsi_period") or 14)
candles_by_code, _, _ = tbc.load_tail_candles_by_code(
db, start_key, end_key, tf, rsi_period=rsi,
)
codes = len(candles_by_code)
bars = sum(len(v) for v in candles_by_code.values())
slot = float(base.get("slot_money") or 300000)
budget = float(base.get("total_budget_krw") or slot * int(base.get("max_stocks") or 4))
print(
f"[로드] universe={src} slots={n_slots} codes={codes} bars={bars} "
f"slot={slot} budget={budget}",
flush=True,
)
fee = float(base.get("fee_rate") or 0.00015)
tax = float(base.get("sell_tax") or 0.0023)
meta = {"db": db, "start_key": start_key, "end_key": end_key}
use_tick = tail_backtest_wants_tick_replay(base)
print(f"[로드] tick_replay={use_tick}", flush=True)
cases = [
("A GATE_ON edge=2000", 30000.0, 1.5, 2000.0),
("B GATE_ON edge=0", 30000.0, 1.5, 0.0),
]
results = []
for label, krw, pct, edge in cases:
params = dict(base)
params["symbol_daily_loss_limit_krw"] = krw
params["symbol_daily_loss_limit_pct"] = pct
params["reentry_min_edge_krw"] = edge
params["skip_hts_scan_dupes"] = skip_hts
print(
f"\n--- {label}: krw={krw} pct={pct} edge={edge} ---",
flush=True,
)
trades = tbc.run_tail_backtest_web_aligned(
candles_by_code,
params,
universe,
slot_money=slot,
fee_rate=fee,
sell_tax=tax,
total_budget_krw=budget,
meta_out=meta,
)
results.append(_summarize(trades, label))
print("\n======== SUMMARY ========", flush=True)
for r in results:
print(f" {r['label']}: trades={r['trades']} pnl={r['pnl']:+,.0f} multi={r['multi']}", flush=True)
print("\n[LIVE 7/9] trades=3(신규2) pnl=-7,053 (376980 전일포지션 포함)", flush=True)
print("✅ VERIFY DONE", flush=True)
return 0
except Exception:
traceback.print_exc()
return 1
finally:
db.close()
if __name__ == "__main__":
raise SystemExit(main())