WLD DeepCoin 단계별 구조 재편 및 설정·문서 통합
로고스/루트 레거시를 제거하고 deepcoin 패키지·scripts 01~05 CLI·docs/reference로 데이터·GT·분석·매칭·운영 단계를 정리했다. config와 .env 기반 설정, trade_anaysis.html 동기화 포함. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
148
deepcoin/analysis/general_analysis_enrich_runner.py
Normal file
148
deepcoin/analysis/general_analysis_enrich_runner.py
Normal file
@@ -0,0 +1,148 @@
|
||||
"""
|
||||
general_analysis 봉 데이터 전구간 enrich + 최신봉·기법 점검 리포트.
|
||||
|
||||
python scripts/03_analyze_enrich.py
|
||||
python scripts/03_analyze_enrich.py --interval 1440
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from config import CHART_LOOKBACK_DAYS, GA_DEFAULT_TAIL_EXPORT, SYMBOL
|
||||
from deepcoin.analysis.general_analysis_align import (
|
||||
general_analysis_mtf_scores,
|
||||
general_analysis_mtf_vote_latest,
|
||||
)
|
||||
from deepcoin.analysis.general_analysis_config import (
|
||||
DEFAULT_CAPABILITY_HTML,
|
||||
DEFAULT_LATEST_DIR,
|
||||
GENERAL_ANALYSIS_INTERVALS,
|
||||
)
|
||||
from deepcoin.analysis.general_analysis_core import ga_col, interval_tf_prefix
|
||||
from deepcoin.analysis.general_analysis_pipeline import general_analysis_enrich_bars
|
||||
from deepcoin.ops.monitor import Monitor
|
||||
from deepcoin.data.mtf_bb import load_frames_from_db
|
||||
|
||||
|
||||
def _latest_row_summary(df: pd.DataFrame, prefix: str) -> dict[str, object]:
|
||||
"""최신 봉의 ga_·핵심 레거시 컬럼 요약."""
|
||||
if df.empty:
|
||||
return {}
|
||||
row = df.iloc[-1]
|
||||
out: dict[str, object] = {"dt": str(df.index[-1]), "tf": prefix}
|
||||
for c in df.columns:
|
||||
if c.startswith("ga_") or c in ("RSI", "bb_pos", "macd_hist", "stoch_k"):
|
||||
v = row[c]
|
||||
if pd.isna(v):
|
||||
continue
|
||||
out[c] = v
|
||||
return out
|
||||
|
||||
|
||||
def write_capability_html(
|
||||
summaries: dict[str, dict[str, object]],
|
||||
vote: dict[str, object],
|
||||
path: Path,
|
||||
) -> None:
|
||||
"""기법 컬럼 존재 여부·최신값 요약 HTML."""
|
||||
rows = ""
|
||||
for tf, snap in summaries.items():
|
||||
ga_cols = [k for k in snap if str(k).startswith("ga_")]
|
||||
rows += f"<tr><td>{tf}</td><td>{snap.get('dt','')}</td><td>{len(ga_cols)}</td></tr>"
|
||||
|
||||
vote_rows = "".join(f"<li><code>{k}</code>: {v}</li>" for k, v in vote.items())
|
||||
|
||||
html = f"""<!DOCTYPE html>
|
||||
<html lang="ko"><head><meta charset="utf-8"/>
|
||||
<title>general_analysis 기법 점검</title>
|
||||
<style>
|
||||
body {{ font-family: "Malgun Gothic", Arial, sans-serif; margin: 24px; background: #f5f5f5; }}
|
||||
table {{ border-collapse: collapse; width: 100%; background: #fff; }}
|
||||
th, td {{ border: 1px solid #e2e8f0; padding: 8px; font-size: 0.88rem; }}
|
||||
th {{ background: #e2e8f0; }}
|
||||
</style></head><body>
|
||||
<h1>general_analysis 기법 점검 ({SYMBOL})</h1>
|
||||
<p>3분~일봉 enrich 완료. 최신 봉 기준 컬럼 수·MTF 투표.</p>
|
||||
<h2>간격별 ga_ 컬럼 수</h2>
|
||||
<table><thead><tr><th>TF</th><th>최신 시각</th><th>ga_ 컬럼 수</th></tr></thead>
|
||||
<tbody>{rows}</tbody></table>
|
||||
<h2>MTF 투표 (최신 봉)</h2>
|
||||
<ul>{vote_rows}</ul>
|
||||
<p>상세 CSV: <code>{DEFAULT_LATEST_DIR}/</code></p>
|
||||
</body></html>"""
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(html, encoding="utf-8")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="general_analysis 8TF enrich")
|
||||
parser.add_argument("--interval", type=int, default=0, help="단일 간격만 (0=전체)")
|
||||
parser.add_argument(
|
||||
"--tail-export",
|
||||
type=int,
|
||||
default=GA_DEFAULT_TAIL_EXPORT,
|
||||
help="CSV 저장 최근 N봉",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
from deepcoin.paths import ANALYSIS_CAPABILITY_HTML, ANALYSIS_LATEST_DIR
|
||||
|
||||
intervals = (
|
||||
(args.interval,)
|
||||
if args.interval > 0
|
||||
else GENERAL_ANALYSIS_INTERVALS
|
||||
)
|
||||
|
||||
print(f"=== general_analysis enrich {SYMBOL} ===")
|
||||
mon = Monitor(cooldown_file=None)
|
||||
frames = load_frames_from_db(mon, SYMBOL, lookback_days=CHART_LOOKBACK_DAYS)
|
||||
if not frames:
|
||||
raise RuntimeError("coins.db 데이터 없음")
|
||||
|
||||
enriched: dict[int, pd.DataFrame] = {}
|
||||
summaries: dict[str, dict[str, object]] = {}
|
||||
out_dir = ANALYSIS_LATEST_DIR
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for iv in intervals:
|
||||
raw = frames.get(iv)
|
||||
if raw is None or raw.empty:
|
||||
print(f" skip {iv}: no data")
|
||||
continue
|
||||
p = interval_tf_prefix(iv)
|
||||
print(f" [{p}] enrich {len(raw)} bars...")
|
||||
ef = general_analysis_enrich_bars(raw, iv, full_context=True)
|
||||
enriched[iv] = ef
|
||||
tail = ef.tail(args.tail_export)
|
||||
csv_path = out_dir / f"{p}_latest.csv"
|
||||
tail.to_csv(csv_path, encoding="utf-8-sig")
|
||||
print(f" -> {csv_path} ({len(tail)} rows x {len(tail.columns)} cols)")
|
||||
summaries[p] = _latest_row_summary(ef, p)
|
||||
|
||||
flat_vote: dict[str, object] = {}
|
||||
if len(enriched) >= 2:
|
||||
for k, v in general_analysis_mtf_vote_latest(enriched).items():
|
||||
flat_vote[ga_col(k)] = v
|
||||
prefixed = {}
|
||||
for iv, ef in enriched.items():
|
||||
p = interval_tf_prefix(iv)
|
||||
row = ef.iloc[-1]
|
||||
for c in ("RSI", "bb_pos"):
|
||||
if c in row.index:
|
||||
prefixed[f"{p}_{c}"] = row[c]
|
||||
st = row.get(ga_col("struct_trend"))
|
||||
if st is not None:
|
||||
prefixed[f"{p}_{ga_col('struct_trend')}"] = st
|
||||
flat_vote.update(general_analysis_mtf_scores(prefixed))
|
||||
|
||||
write_capability_html(summaries, flat_vote, ANALYSIS_CAPABILITY_HTML)
|
||||
print(f"점검 리포트: {cap_path}")
|
||||
print("완료.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user