로고스/루트 레거시를 제거하고 deepcoin 패키지·scripts 01~05 CLI·docs/reference로 데이터·GT·분석·매칭·운영 단계를 정리했다. config와 .env 기반 설정, trade_anaysis.html 동기화 포함. Co-authored-by: Cursor <cursoragent@cursor.com>
149 lines
5.1 KiB
Python
149 lines
5.1 KiB
Python
"""
|
|
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()
|