- 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 마크다운 자동 생성 기능 추가
131 lines
4.0 KiB
Python
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())
|