fix(정합성·뱃지): 틱 로더 recv_ts 전달 · _lag_sec 폴백 · use_rust 결과JSON 기록

Q1) 쓰레기 스킵 22.8% 여전한 이유 → 로더가 recv_ts 를 tick dict 에 안 넣음
- breakout_tick_loader._ingest_tick_rows: recv_ts 문자열 필드 추가
  (bar_is_garbage 가 wall-clock 정합 판정에 사용)
- feed_fallback.bar_is_garbage: _lag_sec 사전계산 필드 최우선 사용
  Rust Parquet 로더는 recv_ts 없이 _lag_sec 만 실어옴 → 이 폴백으로 커버
- 우선순위: _lag_sec > recv_ts > 봉끝(레거시)

Q2) 자동 등록 잡 (mode_refine phase1/phase2) 뱃지  뜨는 이유
- register_result_json_as_job 이 원본 JSON 의 use_rust 를 읽는데 없어서 None
- optuna_web_jobs: inherit_use_rust 인자 신설 → 부모 실행 잡 값 상속
- _spawn_job_reaper: register 호출 시 부모 use_rust 전달
- optuna_common.annotate_optuna_period_daily_avg: 결과 JSON 저장 훅에
  use_rust=bool(BACKTEST_USE_RUST=='1') 자동 삽입
  → 4전략(tail/momentum/breakout/scalp) 모두 커버 (근본)

우선순위: 원본 JSON use_rust > 부모 잡 상속 > None()

실매 스모크: logs/test_live_execution_validation_20260906_194154.log → 최종: 통과
웹 재시작 200. 다음 옵투나 실행부터 반영.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Your Name
2026-09-06 19:42:17 +09:00
parent b5d7c5d848
commit 94daf529f0
4 changed files with 49 additions and 13 deletions

View File

@@ -535,24 +535,32 @@ def bar_is_garbage(
return str(missing_policy or "hole").strip().lower() == "hole"
bar_end = bar_end_datetime(candle_time, tf_min)
for t in bucket:
# 1) 사전 계산된 _lag_sec 가 있으면 최우선 (로더가 recv_ts - tick_time 을 이미 계산)
# None 이면 판정 불가 → 이 틱은 안전(False), 다음 폴백으로.
pre_lag = t.get("_lag_sec")
if pre_lag is not None:
try:
_pl = float(pre_lag)
if not is_feed_read_stale(_pl):
return False
# _pl 이 stale 이면 다음 틱으로 계속. 이 틱은 컷 대상.
continue
except (TypeError, ValueError):
pass # 아래 폴백으로
raw = str(t.get("tick_time_raw") or t.get("tick_time") or "")
# 각 틱의 wall-clock 기준(recv_ts) 대비 lag = 실매 RAM 판정과 동일 논리
# 2) 각 틱의 wall-clock 기준(recv_ts) 대비 lag = 실매 RAM 판정과 동일 논리
recv_dt: Optional[datetime] = None
rts = t.get("recv_ts")
if rts is not None:
if rts is not None and str(rts).strip():
try:
if isinstance(rts, datetime):
recv_dt = rts
else:
s = str(rts).strip().replace("T", " ")
# 형식 예: '2026-09-04 09:00:05.123' 또는 '2026-09-04 09:00:05'
if "." in s:
recv_dt = datetime.strptime(s[:19], "%Y-%m-%d %H:%M:%S")
else:
recv_dt = datetime.strptime(s[:19], "%Y-%m-%d %H:%M:%S")
recv_dt = datetime.strptime(s[:19], "%Y-%m-%d %H:%M:%S")
except Exception:
recv_dt = None
# recv_ts 없거나 파싱 실패 → 봉끝 기준(레거시 폴백, 실매보다 보수적)
# 3) recv_ts 없거나 파싱 실패 → 봉끝 기준(레거시 폴백, 실매보다 보수적)
base_dt = recv_dt if recv_dt is not None else bar_end
if base_dt is None:
# 봉끝도 파싱 실패면 판정 포기 → False(버리지 않음)