fix(옵투나·백테웹): 휩쏘 키 통일 + 엔진 뱃지 + 잡 삭제 + race·후처리 시그니처

휩쏘 키 통일 (bt-form-postfilter-key-parity.mdc 신설)
- 저장키 vs 조회키 불일치 해소: whipsaw_enabled(옛) → whipsaw_filter_enabled(표준)
- backtest_web.py: params[..] 세팅, static/js/backtest.js: 폼 파라미터
- optuna_web_jobs·param_search_apply_snapshot·param_search_scalping: 옛 alias 제거
- bt_post_filters: 로컬 변수도 whipsaw_filter_enabled 로 통일
- scripts/scratch: 관련 스크립트 동기 반영

엔진 뱃지 (optuna-job-engine-label.mdc 신설)
- optuna_web_jobs: use_rust 명시값만 신뢰, 미상은  (전략명 하드코딩 폴백 금지)
- 스캘핑/모멘텀/돌파 Rust 포팅 확장에도 안전한 라벨링

Optuna 웹 잡 UX
- save_job: tmp 파일 PID 접미 (멀티 프로세스 race 해소)
- _spawn_job_reaper: mode_refine 완료 시 phase1/phase2 JSON 자동 등록
  → 예전 UX 복원 (실행 잡ID 위에 결과 잡ID 노출)
- delete_job / delete_jobs_bulk 신설 + API + UI 삭제 버튼
  실행 중 잡 거부, 로그·원본 결과 JSON 보존

후처리 시그니처 수정
- bt_post_filters.orderbook_reject_for_entry 호출:
  price= → current_price=, 단일 대입 → 튜플 unpack
  (매 trial 마다 TypeError 삼켜지고 후처리 무효화되던 버그)

버그 조사·룰 강화
- verify-before-conclude-cross-strategy.mdc: 함수 추적 딥다이브 → 근본 대안 3개
- .cursorrules: 룰 27~29 추가 (해외 UI 정합·휩쏘 키·엔진 뱃지)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Your Name
2026-09-06 19:23:22 +09:00
parent 1d69c217e2
commit b5d7c5d848
13 changed files with 349 additions and 51 deletions

View File

@@ -269,8 +269,11 @@ def _patch_from_momentum_merged(m: Dict[str, Any]) -> Dict[str, str]:
def _whipsaw_combo_to_env_patch(strategy: str, m: Dict[str, Any]) -> Dict[str, str]:
"""TPE/Grid merged 의 whipsaw_* → {STRAT}_WHIPSAW_* (돌파·꼬리 스킵은 호출측)."""
if "whipsaw_filter_enabled" not in m and "whipsaw_enabled" not in m and "whipsaw_subbar_sec" not in m:
"""TPE/Grid merged 의 whipsaw_* → {STRAT}_WHIPSAW_* (돌파·꼬리 스킵은 호출측).
표준 키 whipsaw_filter_enabled 만 사용 (룰 28 · 2026-09-06 통일).
"""
if "whipsaw_filter_enabled" not in m and "whipsaw_subbar_sec" not in m:
return {}
from kis_trader.backtest.optuna_whipsaw_recommend import _whipsaw_env_prefix
@@ -278,8 +281,8 @@ def _whipsaw_combo_to_env_patch(strategy: str, m: Dict[str, Any]) -> Dict[str, s
if not pfx:
return {}
out: Dict[str, str] = {}
whip_val = m.get("whipsaw_filter_enabled") if "whipsaw_filter_enabled" in m else m.get("whipsaw_enabled")
whip_val = m.get("whipsaw_filter_enabled")
if whip_val is not None:
on = str(whip_val).strip().lower() in ("1", "true", "yes", "on")
out[f"{pfx}_WHIPSAW_FILTER_ENABLED"] = "true" if on else "false"