GT MTF 프로필·캘리브레이션과 04 매칭/시뮬/실거래 파이프라인을 추가한다.

3분~일봉 GT 타점 분석(03c), leg 체결 순서 수정, 총자산 90% 검증 루프,
walk-forward Go/No-Go 시뮬, monitor·live_trader 및 reference 문서를 포함한다.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-31 11:27:50 +09:00
parent b52d61b777
commit 2cb67c42b3
47 changed files with 5956 additions and 209 deletions

View File

@@ -5,6 +5,8 @@ general_analysis ground truth 타점 MTF 스냅샷 생성.
from __future__ import annotations
import json
import sys
import time
from pathlib import Path
from typing import Any
@@ -40,15 +42,31 @@ def build_trade_mtf_snapshots(
Returns:
wide DataFrame (1 row per trade).
"""
n_trades = len(trades)
enriched: dict[int, pd.DataFrame] = {}
for iv in GENERAL_ANALYSIS_INTERVALS:
t0 = time.time()
print(f"[03b] Phase A: 8TF enrich (1분봉 제외, 전 기법) — {len(GENERAL_ANALYSIS_INTERVALS)}개 간격")
sys.stdout.flush()
for step, iv in enumerate(GENERAL_ANALYSIS_INTERVALS, start=1):
raw = frames.get(iv)
if raw is None or raw.empty:
print(f" [{step}/8] {interval_tf_prefix(iv)} SKIP (데이터 없음)")
sys.stdout.flush()
continue
print(f" [GA] {interval_tf_prefix(iv)} 봉 지표 계산 ({len(raw)}봉)...")
label = interval_tf_prefix(iv)
print(f" [{step}/8] {label} enrich 시작 ({len(raw):,}봉)...")
sys.stdout.flush()
t_iv = time.time()
enriched[iv] = general_analysis_enrich_bars(raw, iv, full_context=True)
print(f" [{step}/8] {label} 완료 — {len(enriched[iv].columns)}열, {time.time() - t_iv:.0f}")
sys.stdout.flush()
print(f"[03b] Phase A 완료 (누적 {time.time() - t0:.0f}초)")
sys.stdout.flush()
print(f"[03b] Phase B: GT 타점 스냅샷 {n_trades}")
sys.stdout.flush()
rows: list[dict[str, Any]] = []
t_b = time.time()
for i, t in enumerate(sorted(trades, key=lambda x: x["dt"])):
ts = pd.Timestamp(t["dt"])
row: dict[str, Any] = {
@@ -70,12 +88,62 @@ def build_trade_mtf_snapshots(
row.update(flat)
row.update(general_analysis_mtf_scores(flat))
rows.append(row)
if (i + 1) % 50 == 0:
print(f" 타점 스냅샷 {i + 1}/{len(trades)}")
done = i + 1
if done == 1 or done % 25 == 0 or done == n_trades:
elapsed = time.time() - t_b
rate = done / elapsed if elapsed > 0 else 0
eta = (n_trades - done) / rate if rate > 0 else 0
print(
f" 타점 {done}/{n_trades} "
f"({elapsed:.0f}초 경과, ETA 약 {eta:.0f}초)"
)
sys.stdout.flush()
print(f"[03b] Phase B 완료 ({time.time() - t_b:.0f}초)")
sys.stdout.flush()
return pd.DataFrame(rows)
def append_missing_gt_snapshots(
frames: dict[int, pd.DataFrame],
trades_path: Path | str = DEFAULT_TRADES_FILE,
output_csv: Path | str = DEFAULT_OUTPUT_CSV,
) -> int:
"""
CSV에 없는 GT 타점만 MTF 스냅샷 추가.
Args:
frames: interval → OHLCV.
trades_path: ground_truth JSON.
output_csv: 03b CSV.
Returns:
추가된 행 수.
"""
out = Path(output_csv)
if not out.is_file():
return 0
data = load_ground_truth(Path(trades_path))
if not data:
return 0
trades = data.get("trades") or []
existing = pd.read_csv(out)
have = set(zip(existing["dt"].astype(str), existing["action"].astype(str)))
missing = [
t
for t in trades
if (str(t["dt"]), str(t["action"])) not in have
]
if not missing:
return 0
print(f"[03b] 누락 GT 타점 {len(missing)}건 스냅샷 추가")
add_df = build_trade_mtf_snapshots(frames, missing)
merged = pd.concat([existing, add_df], ignore_index=True)
merged.to_csv(out, index=False, encoding="utf-8-sig")
print(f"[03b] CSV 갱신: {out} ({len(merged)}행)")
return len(missing)
def export_trade_snapshots(
frames: dict[int, pd.DataFrame],
trades_path: Path | str = DEFAULT_TRADES_FILE,