| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- from __future__ import annotations
- import hashlib
- import json
- from dataclasses import asdict
- from datetime import datetime
- from pathlib import Path
- import pandas as pd
- from dragon_branch_configs import alpha_first_glued_refined_hot_cap_config
- from dragon_indicators import DragonIndicatorConfig, DragonIndicatorEngine
- from dragon_shared import END_DATE, START_DATE
- from dragon_strategy import DragonRuleEngine
- RC_VERSION = "RC1"
- RC_BRANCH = "alpha_first_glued_refined_hot_cap"
- TRADES_OUTPUT = "dragon_rc1_golden_trades.csv"
- EVENTS_OUTPUT = "dragon_rc1_golden_events.csv"
- MANIFEST_OUTPUT = "dragon_rc1_golden_manifest.json"
- EVENTS_CORE_COLUMNS = [
- "date",
- "side",
- "layer",
- "reason",
- "close",
- "a1",
- "b1",
- "c1",
- "kdj_buy",
- "kdj_sell",
- "ql_buy",
- "ql_sell",
- ]
- TRADES_CORE_COLUMNS = [
- "buy_date",
- "buy_price",
- "buy_reason",
- "sell_date",
- "sell_price",
- "sell_reason",
- "holding_days",
- "return_pct",
- ]
- def _sha256(path: Path) -> str:
- digest = hashlib.sha256()
- with path.open("rb") as fp:
- for chunk in iter(lambda: fp.read(1024 * 1024), b""):
- digest.update(chunk)
- return digest.hexdigest()
- def _df_sha256(df: pd.DataFrame) -> str:
- digest = hashlib.sha256()
- payload = df.to_csv(index=False, encoding="utf-8", float_format="%.15g")
- digest.update(payload.encode("utf-8"))
- return digest.hexdigest()
- def _load_indicator_snapshot(base_dir: Path) -> tuple[pd.DataFrame, str]:
- full_snapshot = base_dir / "dragon_indicator_snapshot_full.csv"
- if full_snapshot.exists():
- df = pd.read_csv(full_snapshot, encoding="utf-8-sig")
- source = full_snapshot.name
- else:
- fallback_snapshot = base_dir / "dragon_indicator_snapshot.csv"
- if fallback_snapshot.exists():
- df = pd.read_csv(fallback_snapshot, encoding="utf-8-sig")
- source = fallback_snapshot.name
- else:
- engine = DragonIndicatorEngine(DragonIndicatorConfig(start_date="2015-01-01", end_date=None))
- df = (
- engine.compute(engine.fetch_daily_data())
- .reset_index(drop=False)
- .rename(columns={"index": "date"})
- )
- source = "fetched_live_history"
- df["date"] = pd.to_datetime(df["date"])
- indexed = df.sort_values("date").set_index("date")
- return indexed, source
- def main() -> None:
- base_dir = Path(__file__).resolve().parent
- indexed, source = _load_indicator_snapshot(base_dir)
- config = alpha_first_glued_refined_hot_cap_config()
- engine = DragonRuleEngine(config=config)
- events, trades = engine.run(indexed)
- events = events[
- (events["date"] >= START_DATE)
- & (events["date"] <= END_DATE)
- ].copy()
- trades = trades[
- (trades["buy_date"] >= START_DATE)
- & (trades["buy_date"] <= END_DATE)
- & (trades["sell_date"] >= START_DATE)
- & (trades["sell_date"] <= END_DATE)
- ].copy()
- events.insert(0, "branch", RC_BRANCH)
- trades.insert(0, "branch", RC_BRANCH)
- events.sort_values(["date", "side", "layer", "reason"], inplace=True)
- trades.sort_values(["buy_date", "sell_date", "buy_reason", "sell_reason"], inplace=True)
- events_path = base_dir / EVENTS_OUTPUT
- trades_path = base_dir / TRADES_OUTPUT
- manifest_path = base_dir / MANIFEST_OUTPUT
- events.to_csv(events_path, index=False, encoding="utf-8-sig")
- trades.to_csv(trades_path, index=False, encoding="utf-8-sig")
- returns = trades["return_pct"].astype(float) if not trades.empty else pd.Series(dtype=float)
- summary = {
- "trade_count": int(len(trades)),
- "event_count": int(len(events)),
- "win_rate": float((returns > 0).mean()) if not returns.empty else float("nan"),
- "avg_return": float(returns.mean()) if not returns.empty else float("nan"),
- "median_return": float(returns.median()) if not returns.empty else float("nan"),
- }
- manifest = {
- "generated_at": datetime.now().isoformat(timespec="seconds"),
- "release_version": RC_VERSION,
- "branch": RC_BRANCH,
- "evaluation_window": {"start": START_DATE, "end": END_DATE},
- "indicator_source": source,
- "artifacts": {
- "trades": {
- "path": TRADES_OUTPUT,
- "sha256": _sha256(trades_path),
- "columns": list(trades.columns),
- "core_columns": TRADES_CORE_COLUMNS,
- "core_sha256": _df_sha256(trades[TRADES_CORE_COLUMNS]),
- },
- "events": {
- "path": EVENTS_OUTPUT,
- "sha256": _sha256(events_path),
- "columns": list(events.columns),
- "core_columns": EVENTS_CORE_COLUMNS,
- "core_sha256": _df_sha256(events[EVENTS_CORE_COLUMNS]),
- },
- },
- "summary": summary,
- "config_snapshot": {
- **asdict(config),
- "disabled_rules": sorted(config.disabled_rules),
- },
- }
- manifest_path.write_text(
- json.dumps(manifest, indent=2, ensure_ascii=False) + "\n",
- encoding="utf-8",
- )
- if __name__ == "__main__":
- main()
|