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:
@@ -41,11 +41,25 @@ def main() -> None:
|
||||
trades = trades[: args.limit]
|
||||
print(f"테스트 모드: 타점 {args.limit}건만")
|
||||
|
||||
print(f"=== general_analysis {SYMBOL} (lookback {CHART_LOOKBACK_DAYS}일) ===")
|
||||
import sys
|
||||
import time
|
||||
|
||||
print(f"=== 03b GT 타점 MTF 분석 {SYMBOL} (lookback {CHART_LOOKBACK_DAYS}일) ===")
|
||||
print(f" 간격: 3,5,10,15,30,60,240,1440분 (1분 제외) · 타점 {len(trades)}건")
|
||||
sys.stdout.flush()
|
||||
t0 = time.time()
|
||||
print("[03b] Phase 0: DB에서 8TF OHLCV 로드...")
|
||||
sys.stdout.flush()
|
||||
mon = Monitor(cooldown_file=None)
|
||||
frames = load_frames_from_db(mon, SYMBOL, lookback_days=CHART_LOOKBACK_DAYS)
|
||||
if not frames:
|
||||
raise RuntimeError("coins.db 데이터 없음")
|
||||
for iv in (3, 5, 10, 15, 30, 60, 240, 1440):
|
||||
df = frames.get(iv)
|
||||
n = len(df) if df is not None else 0
|
||||
print(f" WLD_{iv}: {n:,}봉")
|
||||
print(f"[03b] Phase 0 완료 ({time.time() - t0:.0f}초)")
|
||||
sys.stdout.flush()
|
||||
|
||||
# limit 시 임시 trades 파일
|
||||
if args.limit > 0:
|
||||
@@ -64,6 +78,10 @@ def main() -> None:
|
||||
print(f"저장: {csv_path} ({len(df)}행 × {len(df.columns)}열)")
|
||||
|
||||
write_analysis_report(csv_path, Path(args.html))
|
||||
|
||||
from deepcoin.matching.gt_mtf_profile import run_gt_mtf_profile
|
||||
|
||||
run_gt_mtf_profile(csv_path)
|
||||
print("완료.")
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user