refactor: Git에서 데이터 제거, 설정·코드만 유지

파이프라인 산출물(data/, docs/)을 Git 추적에서 제외하고
히스토리를 단일 커밋으로 재구성해 저장소 용량을 경량화한다.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-12 10:01:43 +09:00
commit 741c949470
92 changed files with 12230 additions and 0 deletions

158
scripts/2_run_techniques.py Normal file
View File

@@ -0,0 +1,158 @@
#!/usr/bin/env python3
"""2단계: 인과 기법 GT 정합 분석 (과거 데이터만 · 0단계 타점 대비)."""
from __future__ import annotations
import argparse
import logging
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "src"
if str(SRC) not in sys.path:
sys.path.insert(0, str(SRC))
from deepcoin.config import load_settings
from deepcoin.data.intervals import interval_label
from deepcoin.evaluation.report import (
build_comparison_report,
render_comparison_html,
save_comparison_report,
)
from deepcoin.techniques.base import TechniqueParams
from deepcoin.techniques.registry import list_technique_ids
from deepcoin.techniques.runner import (
load_ground_truth,
run_all_techniques,
save_technique_result,
)
def _configure_logging(verbose: bool) -> None:
"""로깅 레벨을 설정한다."""
level = logging.DEBUG if verbose else logging.INFO
logging.basicConfig(
level=level,
format="%(asctime)s [%(levelname)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
def main() -> int:
"""CLI 진입점."""
parser = argparse.ArgumentParser(description="2단계: 인과 기법 GT 정합 분석")
parser.add_argument(
"--techniques",
type=str,
default=None,
help="실행할 기법 ID (쉼표 구분). 기본: 전체",
)
parser.add_argument("--tolerance", type=int, default=None, help="GT 정합 허용 봉 수")
parser.add_argument("--no-report", action="store_true", help="비교 리포트 생략")
parser.add_argument("-v", "--verbose", action="store_true")
args = parser.parse_args()
_configure_logging(args.verbose)
settings = load_settings()
if not settings.ground_truth_file.exists():
logging.error("Ground Truth 파일 없음: %s — 먼저 0_ground_truth.py 실행", settings.ground_truth_file)
return 1
gt_result = load_ground_truth(settings.ground_truth_file)
technique_ids = None
if args.techniques:
technique_ids = [t.strip() for t in args.techniques.split(",") if t.strip()]
params = TechniqueParams(
interval_min=settings.gt_interval_min,
lookback_days=settings.gt_lookback_days,
min_leg_pct=settings.gt_min_leg_pct,
initial_cash_krw=settings.gt_initial_cash_krw,
fee_rate=settings.gt_trading_fee_rate,
extra={"reversal_pct": settings.gt_zigzag_reversal_pct},
)
tolerance = args.tolerance or settings.gt_align_tolerance_bars
logging.info(
"기법 실행: %s %s, %s일, tolerance=%s",
settings.symbol,
interval_label(params.interval_min),
params.lookback_days,
tolerance,
)
technique_count = len(technique_ids) if technique_ids else len(list_technique_ids())
print(
f"\n=== 2단계 기법 실행 시작 ({technique_count}종) ===",
flush=True,
)
completed = 0
def _on_result(result) -> None:
nonlocal completed
save_technique_result(result, settings.techniques_dir)
completed += 1
pct = completed / technique_count * 100.0 if technique_count else 100.0
align = result.alignment or {}
print(
f"[기법] {completed}/{technique_count} ({pct:.1f}%) — "
f"{result.technique_id} score={align.get('score', 0)*100:.1f}",
flush=True,
)
results = run_all_techniques(
db_path=settings.db_path,
symbol=settings.symbol,
params=params,
gt_result=gt_result,
tolerance_bars=tolerance,
technique_ids=technique_ids,
on_result=_on_result,
)
saved_paths: list[Path] = []
for result in results:
path = settings.techniques_dir / f"{result.technique_id}.json"
saved_paths.append(path)
align = result.alignment or {}
legs = align.get("legs", {})
print(
f" [{result.technique_id}] {result.technique_name}: "
f"레그 {result.summary.get('leg_count', 0)}개, "
f"수익 {result.pnl.get('total_return_pct', 0):+.1f}%, "
f"GT정합 score={align.get('score', 0)*100:.1f} "
f"(leg recall {legs.get('leg_recall', 0)*100:.0f}%)"
)
print(f"\n=== 2단계 인과 정합 분석 완료 ({len(results)}개) ===")
print(f"저장: {settings.techniques_dir}/")
for path in saved_paths:
print(f" - {path.name}")
if not args.no_report:
report = build_comparison_report(results, gt_result, settings.symbol)
json_path = save_comparison_report(report, settings.analysis_report_json)
html_path = render_comparison_html(report, settings.analysis_report_html)
print(f"\n=== GT 정합 순위 (상위 3) ===")
gt_return = report["gt"]["return_pct"]
print(f"GT 벤치마크: {gt_return:+.1f}%")
for idx, row in enumerate(report["ranking"][:3], start=1):
print(
f" {idx}. {row['technique_name']}: "
f"score {row['score']*100:.1f}, "
f"수익 {row['tech_return_pct']:+.1f}%, "
f"leg recall {row['leg_recall']*100:.0f}%"
)
print(f"리포트 JSON: {json_path}")
print(f"리포트 HTML: {html_path}")
print(f"\n등록 기법: {', '.join(list_technique_ids())}")
return 0
if __name__ == "__main__":
raise SystemExit(main())