이번에 들어간 내용
한투 호가 = 2번째 앱키 전용 키 없거나 start 실패 시 메인에 H0STASP0 안 붙임. 운영설정 WS_ORDERBOOK_SAVE_KIS 빨간 danger. LS RAM 합집합 후보∪보유∪영구∪grace. sync_targets와 split reconcile 둘 다. 틱 DB 영구 게이트는 그대로. 분봉 쓰레기 → 다음 소스 봉 통째 그 분 틱 0건이거나 전부 봉끝 대비 LIVE_FEED_FALLBACK_MAX_AGE_SEC 초과면 구멍. 메인 WS → 2차 → LS → REST → rollup. CANDLE_GARBAGE_FALLBACK 기본 true. 파일: feed_fallback.py(신규), ws_manager.py, kis_ws.py, candle_series.py, bt_candle_source.py, live_config_schema.py, database.py, 스모크, MD 2개. 같은 ws_manager/database/kis_ws/live_config에는 직전 커밋 이후 쌓여 있던 시세 폴백·ENV 키 정리도 같이 들어갔습니다. 파일 단위로 나눌 수 없어서입니다.
This commit is contained in:
@@ -371,6 +371,112 @@ def build_optuna_result_tiers(
|
||||
}
|
||||
|
||||
|
||||
def _optuna_overfit_sample_days(data: Dict[str, Any]) -> int:
|
||||
try:
|
||||
days = int(data.get("backtest_days") or 0)
|
||||
except (TypeError, ValueError):
|
||||
days = 0
|
||||
if days > 0:
|
||||
return days
|
||||
start = str(data.get("start") or "")
|
||||
end = str(data.get("end") or "")
|
||||
try:
|
||||
from datetime import datetime as _dt
|
||||
|
||||
return max(
|
||||
1,
|
||||
(_dt.strptime(end, "%Y-%m-%d") - _dt.strptime(start, "%Y-%m-%d")).days + 1,
|
||||
)
|
||||
except Exception:
|
||||
return 1
|
||||
|
||||
|
||||
def overfit_risk_pct_for_row(
|
||||
data: Dict[str, Any],
|
||||
row: Optional[Dict[str, Any]],
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
후보 한 줄의 과적합 가능도% (0~100, 높을수록 위험 · 만점=100).
|
||||
|
||||
스터디 공통(표본 장일) + 이 trial의 거래수·승률·PF 이상치.
|
||||
교차검증이 아님. DB apply 게이트와 별개.
|
||||
"""
|
||||
def _f(x: Any, default: float = 0.0) -> float:
|
||||
try:
|
||||
return float(x)
|
||||
except (TypeError, ValueError):
|
||||
return default
|
||||
|
||||
def _i(x: Any, default: int = 0) -> int:
|
||||
try:
|
||||
return int(x)
|
||||
except (TypeError, ValueError):
|
||||
return default
|
||||
|
||||
days = _optuna_overfit_sample_days(data or {})
|
||||
risk = 0.0
|
||||
if days <= 1:
|
||||
risk += 40.0
|
||||
elif days == 2:
|
||||
risk += 28.0
|
||||
elif days <= 4:
|
||||
risk += 16.0
|
||||
|
||||
if not row:
|
||||
risk = max(0.0, min(100.0, round(risk + 25.0, 1)))
|
||||
return {
|
||||
"overfit_risk_pct": risk,
|
||||
"verdict": "비권장",
|
||||
"verdict_ui": "위험 · 비권장",
|
||||
}
|
||||
|
||||
nt = _i(row.get("total_trades"))
|
||||
wr = _f(row.get("win_rate"))
|
||||
pf = _f(row.get("pf"))
|
||||
pnl = _f(row.get("total_pnl"))
|
||||
|
||||
if nt <= 1:
|
||||
risk += 25.0
|
||||
elif nt <= 3:
|
||||
risk += 18.0
|
||||
elif nt <= 9:
|
||||
risk += 10.0
|
||||
|
||||
if wr >= 90.0 and nt < 10:
|
||||
risk += 15.0
|
||||
elif wr >= 80.0 and nt < 5:
|
||||
risk += 10.0
|
||||
if pf >= 50.0 and nt < 10:
|
||||
risk += 10.0
|
||||
elif pf >= 10.0 and nt < 5:
|
||||
risk += 6.0
|
||||
|
||||
gated = list((data or {}).get("results_gated") or [])
|
||||
learn = list((data or {}).get("results") or (data or {}).get("results_all") or [])
|
||||
pool = gated if gated else learn
|
||||
if pool and nt > 0:
|
||||
best_pnl = round(pnl, 0)
|
||||
same = [r for r in pool if abs(_f(r.get("total_pnl")) - best_pnl) < 1.0]
|
||||
share = len(same) / max(1, len(pool))
|
||||
if share >= 0.4 and len(same) >= 5:
|
||||
risk += 12.0
|
||||
elif share >= 0.25 and len(same) >= 3:
|
||||
risk += 6.0
|
||||
|
||||
risk = max(0.0, min(100.0, round(risk, 1)))
|
||||
if risk >= 70.0:
|
||||
verdict, verd_ui = "비권장", "위험 · 비권장"
|
||||
elif risk >= 40.0:
|
||||
verdict, verd_ui = "주의", "주의"
|
||||
else:
|
||||
verdict, verd_ui = "상대적으로낮음", "상대적으로 낮음"
|
||||
return {
|
||||
"overfit_risk_pct": risk,
|
||||
"verdict": verdict,
|
||||
"verdict_ui": verd_ui,
|
||||
}
|
||||
|
||||
|
||||
def build_optuna_overfit_diagnostics(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Optuna 결과 → 과적합 위험% · 적용 가능도% · 임계값(파라미터) 분포 표용 dict.
|
||||
@@ -740,9 +846,13 @@ def ensure_optuna_gate_env_defaults(db: Any = None) -> None:
|
||||
"OPTUNA_POST_TOP_N": "5",
|
||||
"OPTUNA_POST_INCLUDE_MODE": "true",
|
||||
"OPTUNA_POST_INCLUDE_LIVE": "true",
|
||||
"OPTUNA_POST_INCLUDE_STABLE": "true",
|
||||
"OPTUNA_POST_RUN_OB_WHIPSAW": "true",
|
||||
"OPTUNA_OB_RECOMMEND_TRIALS": "1000",
|
||||
"OPTUNA_OB_AXIS_TRIALS": "0",
|
||||
"OPTUNA_OB_RECOMMEND_TRIALS": "500",
|
||||
"OPTUNA_OB_AXIS_TRIALS": "500",
|
||||
"OPTUNA_OB_COMBO_TRIALS_SINGLE": "150",
|
||||
"OPTUNA_OB_COMBO_TRIALS_DOUBLE": "200",
|
||||
"OPTUNA_OB_COMBO_TRIALS_TRIPLE": "250",
|
||||
"OPTUNA_OB_ENTRY_SPREAD_MIN": "0.1",
|
||||
"OPTUNA_OB_ENTRY_SPREAD_MAX": "8.0",
|
||||
"OPTUNA_OB_ENTRY_RATIO_MIN": "0.05",
|
||||
|
||||
Reference in New Issue
Block a user