| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- from __future__ import annotations
- from pathlib import Path
- import pandas as pd
- def _load_csv(base_dir: Path, name: str) -> pd.DataFrame:
- return pd.read_csv(base_dir / name, encoding="utf-8-sig")
- def main() -> None:
- base_dir = Path(__file__).resolve().parent
- group_summary = _load_csv(base_dir, "dragon_trade_group_summary.csv")
- ablation = _load_csv(base_dir, "dragon_rule_ablation.csv")
- sensitivity = _load_csv(base_dir, "dragon_threshold_sensitivity_summary.csv")
- deep_oversold = _load_csv(base_dir, "dragon_deep_oversold_subtype_summary.csv")
- deep_oversold_exp = _load_csv(base_dir, "dragon_deep_oversold_experiments.csv")
- predictive_exp = _load_csv(base_dir, "dragon_predictive_break_experiments.csv")
- baseline = ablation[ablation["experiment"] == "baseline"].iloc[0]
- holding = group_summary[group_summary["group_type"] == "holding_bucket"].copy()
- sample_split = group_summary[group_summary["group_type"] == "sample_split"].copy()
- regime = group_summary[group_summary["group_type"] == "market_state_layer"].copy()
- protected = ablation[
- (ablation["experiment"] != "baseline")
- & (ablation["real_buy_overlap"] == baseline["real_buy_overlap"])
- & (ablation["real_sell_overlap"] == baseline["real_sell_overlap"])
- ].copy()
- fragile = sensitivity[sensitivity["stable_real_alignment"] == False].copy()
- robust = sensitivity[sensitivity["stable_real_alignment"] == True].copy()
- lines = [
- "# Dragon Stage 3 Stability Report",
- "",
- "## Baseline",
- f"- trades: `{int(baseline['trades'])}`",
- f"- win_rate: `{baseline['win_rate']:.2%}`",
- f"- avg_return: `{baseline['avg_return']:.2%}`",
- f"- profit_factor: `{baseline['profit_factor']:.2f}`",
- f"- real BUY overlap: `{int(baseline['real_buy_overlap'])}`",
- f"- real SELL overlap: `{int(baseline['real_sell_overlap'])}`",
- "",
- "## Holding Structure",
- ]
- for _, row in holding.sort_values("holding_bucket").iterrows():
- lines.append(
- f"- `{row['holding_bucket']}`: trades `{int(row['trades'])}`, win_rate `{row['win_rate']:.2%}`, "
- f"avg_return `{row['avg_return']:.2%}`, avg_mfe `{row['avg_mfe_pct']:.2%}`, avg_mae `{row['avg_mae_pct']:.2%}`"
- )
- lines.extend(["", "## Sample Split"])
- for _, row in sample_split.sort_values("sample_split").iterrows():
- lines.append(
- f"- `{row['sample_split']}`: trades `{int(row['trades'])}`, avg_return `{row['avg_return']:.2%}`, "
- f"profit_factor `{row['profit_factor']:.2f}`"
- )
- lines.extend(["", "## Regime Structure"])
- for _, row in regime.sort_values("trades", ascending=False).iterrows():
- key = row["market_state_layer"]
- lines.append(
- f"- `{key}`: trades `{int(row['trades'])}`, avg_return `{row['avg_return']:.2%}`, profit_factor `{row['profit_factor']:.2f}`"
- )
- lines.extend(["", "## Rule Ablation"])
- if protected.empty:
- lines.append("- No protected experiment preserved full real-trade alignment.")
- else:
- protected_sorted = protected.sort_values("delta_avg_return", ascending=False)
- for _, row in protected_sorted.head(8).iterrows():
- lines.append(
- f"- `{row['experiment']}`: delta_avg_return `{row['delta_avg_return']:.2%}`, "
- f"delta_profit_factor `{row['delta_profit_factor']:.2f}`, delta_aux_sell_overlap `{int(row['delta_aux_sell_overlap'])}`"
- )
- best_degrade = ablation[(ablation["experiment"] != "baseline")].sort_values("delta_avg_return", ascending=False).head(6)
- lines.extend(["", "## Candidate Pressure Points"])
- for _, row in best_degrade.iterrows():
- lines.append(
- f"- `{row['experiment']}`: delta_avg_return `{row['delta_avg_return']:.2%}`, "
- f"real BUY `{int(row['real_buy_overlap'])}`, real SELL `{int(row['real_sell_overlap'])}`"
- )
- lines.extend(["", "## Deep Oversold Subtypes"])
- for _, row in deep_oversold.iterrows():
- lines.append(
- f"- `{row['entry_subtype']}`: trades `{int(row['trades'])}`, win_rate `{row['win_rate']:.2%}`, "
- f"avg_return `{row['avg_return']:.2%}`, fast_failures `{int(row['fast_failures'])}`"
- )
- lines.extend(["", "## Focused Deep Oversold Experiments"])
- for _, row in deep_oversold_exp.iterrows():
- lines.append(
- f"- `{row['experiment']}`: deep trades `{int(row['deep_oversold_trade_count'])}`, "
- f"delta_avg_return `{row['delta_avg_return']:.2%}`, real BUY `{int(row['real_buy_overlap'])}`, real SELL `{int(row['real_sell_overlap'])}`"
- )
- lines.extend(["", "## Predictive Break Experiments"])
- for _, row in predictive_exp.iterrows():
- lines.append(
- f"- `{row['experiment']}`: predictive trades `{int(row['predictive_trade_count'])}`, "
- f"delta_avg_return `{row['delta_avg_return']:.2%}`, real BUY `{int(row['real_buy_overlap'])}`, real SELL `{int(row['real_sell_overlap'])}`"
- )
- lines.extend(["", "## Threshold Sensitivity"])
- for _, row in sensitivity.iterrows():
- lines.append(
- f"- `{row['parameter']}`: stable_real_alignment `{bool(row['stable_real_alignment'])}`, "
- f"avg_return_range `{row['avg_return_range']:.2%}`, profit_factor_range `{row['profit_factor_range']:.2f}`"
- )
- lines.extend(["", "## Fragile Parameters"])
- if fragile.empty:
- lines.append("- None in this pack.")
- else:
- for _, row in fragile.iterrows():
- lines.append(
- f"- `{row['parameter']}`: minimum real BUY overlap `{int(row['real_buy_overlap_min'])}`, minimum real SELL overlap `{int(row['real_sell_overlap_min'])}`"
- )
- lines.extend(["", "## Robust Parameters"])
- for _, row in robust.sort_values("avg_return_range").head(6).iterrows():
- lines.append(
- f"- `{row['parameter']}`: avg_return_range `{row['avg_return_range']:.2%}`, aux_sell_overlap_range `{int(row['aux_sell_overlap_range'])}`"
- )
- lines.extend(
- [
- "",
- "## Quant Judgment",
- "- `glued_buy` remains the structural backbone. Disabling it destroys alignment and does not produce a credible upgrade path.",
- "- `non_glued_positive_expansion_buy` is redundant in the current sample window: its aligned dates are now absorbed by `dual_gold_resonance_buy`, so it should not be treated as an independent alpha family.",
- "- `deep_oversold_rebound_buy` is the clearest weak entry family: removing it improves average return materially, but at a significant alignment cost.",
- "- Within the deep-oversold family, the weakest subtypes are `positive_b1_rebound` and `shallow_false_start`; this is now a subtype redesign problem, not a whole-rule deletion problem.",
- "- Safe default improvement was limited to rerouting 4 weak subtype dates to same-day fallback rules; blocking the remaining weak subtypes raises return modestly but degrades real-trade overlap too much for the current objective.",
- "- `knife_take_profit_2_glued` did not improve results when disabled in rerun form, which implies the current drag is partly replaced by alternative same-cycle exits rather than removed cleanly.",
- "- `predictive_b1_break` is now effectively a frozen bridge rule: loosening it worsens results, tightening it marginally helps but breaks workbook alignment.",
- "- Auxiliary sell compression parameters are relatively robust; major remaining optimization leverage is not in the aux layer.",
- ]
- )
- (base_dir / "dragon_stage3_stability_report.md").write_text("\n".join(lines) + "\n", encoding="utf-8")
- if __name__ == "__main__":
- main()
|