Files
kis_bot/scripts/adhoc_cancelable_reconcile_smoke.py
Your Name 9ba9ab73b6 feat(backtest): 대대적인 Optuna 백테스트 웹 UI 및 백엔드 파이프라인 개편
- Web UI:
  - Optuna 탭 추가 및 mode_combo (최빈값 조합), 사후합격 Top 10 시각화 기능
  - 파라미터 분포(p25~p75, median, mode) 히스토그램 및 과적합(Overfit) 위험도 진단 UI 신설
  - 체크박스 렌더링 깨짐 현상을 네이티브(appearance: auto)로 강제 복구 (CSS)
  - 다단 트레일링 스탑, 꼬리 진입/돌파 손절 등 고급 조건 설정 폼 UI 고도화

- Backend (Optuna Jobs):
  - CLI 환경에서 구동된 Optuna json 결과물을 웹 대시보드로 읽어오는 import 기능 강화
  - JSON 메타데이터에 sort_by, mode, 호가 적용 여부 등 핵심 파라미터 파싱 누락 수정
  - optuna_mode_combo.py 등 최빈값 조합 및 후보군 2차 검증을 위한 신규 모듈 추가

- DB & Execution:
  - WebSocket 호가/틱 피드 수집 통계(api_feed_collect_stats) 메모리 캐시 최적화
  - KIS client 접속 키(approval_key) 등 인프라스트럭처 안정성 및 공유 관리 구조 개선
  - 테스트 및 디버깅용 briefing 마크다운 자동 생성 기능 추가
2026-09-01 02:47:51 +09:00

131 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""
scripts/adhoc_cancelable_reconcile_smoke.py
===========================================
Worker SELL C+D — 주말 구조 스모크 (REST 주문·cancel 호출 없음).
검증:
· orders broker debug 컬럼 migrate
· update_order_broker_snapshot / get_latest_sell_order_for_code 헬퍼
· OrderManager._reconcile_cancelable_open disabled 분기 (noop)
· poll 만료 cancel 실패 시 CANCELLED 금지 소스 앵커
실행:
python3 -u scripts/adhoc_cancelable_reconcile_smoke.py
"""
from __future__ import annotations
import inspect
import sys
from pathlib import Path
from unittest.mock import MagicMock, patch
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
REQUIRED_ORDER_COLS = (
"broker_open_qty",
"broker_open_odno",
"broker_reconcile_at",
"broker_reconcile_note",
)
def main() -> int:
ok = True
print("=== adhoc_cancelable_reconcile_smoke ===")
from kis_trader.database.db_manager import get_db
from kis_trader.execution.order_manager import OrderManager, OrderRequest
db = get_db()
db._ensure_orders_table()
cols = [r["Field"] for r in db.conn.execute(
"SHOW COLUMNS FROM orders",
).fetchall()]
missing = [c for c in REQUIRED_ORDER_COLS if c not in cols]
if missing:
print(f"FAIL orders 컬럼 누락: {missing}")
ok = False
else:
print(f"OK orders broker debug 컬럼 {len(REQUIRED_ORDER_COLS)}개 확인")
snap_ok = db.update_order_broker_snapshot(
ord_no="__smoke__",
strategy_id="SMOKE",
code="000000",
open_qty=0,
open_odno=None,
note="adhoc_smoke",
)
if snap_ok:
print("OK update_order_broker_snapshot (no-row UPDATE 허용)")
else:
print("WARN update_order_broker_snapshot False (no matching row — migrate OK)")
mock_client = MagicMock()
mock_db = MagicMock()
mock_db.get_latest_sell_order_for_code.return_value = None
om = OrderManager(client=mock_client, db=mock_db)
req = OrderRequest(
strategy_id="SMOKE",
code="232680",
name="232680",
side="SELL",
qty=1,
price_ref=0.0,
reason="smoke",
)
def _env_bool(key, default=True):
if key == "CANCELABLE_RECONCILE_ENABLED":
return False
if key == "CANCELABLE_RECONCILE_CANCEL_RETRY":
return False
return default
with patch(
"kis_trader.execution.order_manager.get_env_bool",
side_effect=_env_bool,
):
action = om._reconcile_cancelable_open(
req, {"232680": {"psbl_qty": 10, "odno": "X"}},
)
if action != "disabled":
print(f"FAIL reconcile disabled 기대=disabled 실제={action}")
ok = False
else:
print("OK _reconcile_cancelable_open disabled → noop 경로")
from kis_trader.execution import order_manager as om_mod
src = inspect.getsource(om_mod.OrderManager.poll_pending_fills)
if "cancel_failed_at_poll" in src and "CANCELLED 금지" in src:
print("OK poll_pending_fills cancel 실패 → CANCELLED 금지 앵커")
else:
print("FAIL poll_pending_fills cancel-fail 가드 소스 누락")
ok = False
from kis_trader.strategies import base as base_mod
base_src = inspect.getsource(base_mod.BaseStrategy._enqueue_sell)
if "SELL_LOCKED_ENQUEUE_COOLDOWN_SEC" in base_src:
print("OK base._enqueue_sell sell_locked cooldown 앵커")
else:
print("FAIL base enqueue cooldown 소스 누락")
ok = False
ow_src = Path(ROOT / "kis_trader/execution/order_worker.py").read_text(encoding="utf-8")
if "prefetch_broker_holdings(force=False)" in ow_src:
print("OK order_worker prefetch force=False")
else:
print("FAIL order_worker prefetch force=False 누락")
ok = False
print("=== 최종:", "통과" if ok else "실패", "===")
return 0 if ok else 1
if __name__ == "__main__":
raise SystemExit(main())