Files
MoFin/scripts/research/step29_compress_predictive.py
T
hmo b9c68a83a7 docs: 预测超跌反弹策略研究成果归档(方法论/策略文档/研究记录/脚本)
- 新增 strategy_research_methodology.md(由果及因/12维/铁律/支撑压力规范)
- 新增 predictive_oversold_strategy.md(v5定稿,年化18.57%)
- 新增 deployment-plan-predictive-oversold.md(整合部署计划)
- 归档 docs/research/(63份研究过程文档)+ scripts/research/(19个研究脚本)
- 更新 docs/README.md 文档中心(策略研究章节)
2026-08-10 14:37:21 +08:00

65 lines
2.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""step29_compress_predictive.py — 压缩预测信号到稀缺(数据定阈值,验证预测力保持)
在四因子基础上加更多预测因子压缩信号量:
- 行业状态(sec_above/sec_ret20
- 个股技术(bias60深度/量能/距低点)
- 资金流
逐层验证:信号量下降 且 大涨率/avg60 保持或提升
"""
import numpy as np
import pandas as pd
print("=== 加载 ===", flush=True)
panel = pd.read_pickle("/tmp/panel_12d.pkl")
panel = panel.sort_values(["code", "date"]).reset_index(drop=True)
panel["fwd_ret60"] = panel.groupby("code")["close"].transform(lambda x: x.shift(-60)/x - 1) * 100
panel["is_big"] = (panel["fwd_ret60"] >= 50).astype(int)
print("面板:", len(panel), flush=True)
base = panel.dropna(subset=["fwd_ret60"])
print("基线: 大涨率={:.2f}% avg60={:.2f}%".format(
base["is_big"].mean()*100, base["fwd_ret60"].mean()), flush=True)
def validate(cond, label, min_n=50):
s = base[cond]
if len(s) < min_n:
print("{}: n={} 样本不足".format(label, len(s)), flush=True)
return None
rate = s["is_big"].mean()*100
avg = s["fwd_ret60"].mean()
wr = (s["fwd_ret60"]>0).mean()*100
cand = s[["code", "date"]].sort_values(["code", "date"])
cand["prev"] = cand.groupby("code")["date"].shift(1)
cand["gap"] = (pd.to_datetime(cand["date"]) - pd.to_datetime(cand["prev"])).dt.days
cand = cand[(cand["prev"].isna()) | (cand["gap"] > 30)]
cand["year"] = cand["date"].str[:4]
n_dedup = len(cand)
monthly = n_dedup / max(len(cand["year"].unique()),1) / 12
print("{}: n={} 大涨率={:.2f}% avg60={:.2f}% wr={:.1f}% | 去重{} 月均{:.1f}".format(
label, len(s), rate, avg, wr, n_dedup, monthly), flush=True)
return {"n": n_dedup, "monthly": monthly, "rate": rate, "avg": avg, "wr": wr}
# 基础四因子
c4 = (panel["mkt_rsi"] < 41) & (panel["mcap_q"] < 0.2) & (panel["pe_q"] < 0.2) & (panel["news3"] >= 1)
print("\n=== 四因子基准 ===", flush=True)
validate(c4, "四因子(弱市+小市值+低PE+新闻)")
print("\n=== 加行业状态 ===", flush=True)
validate(c4 & (panel["sec_above"] == 0), "+行业MA20下")
validate(c4 & (panel["sec_ret20"] < 0), "+行业20日跌")
validate(c4 & (panel["sec_ret20"] < -5), "+行业20日深跌")
print("\n=== 加个股技术 ===", flush=True)
validate(c4 & (panel["bias60"] < -10), "+bias60<-10(深跌)")
validate(c4 & (panel["bias60"] < -15), "+bias60<-15")
validate(c4 & (panel["bias60"] < -20), "+bias60<-20")
validate(c4 & (panel["vol_ratio"] < 1.0), "+缩量")
validate(c4 & (panel["dist_lo20"] < 5), "+距前低<5%")
print("\n=== 组合最优方向 ===", flush=True)
# 行业弱 + 深跌
validate(c4 & (panel["sec_ret20"] < -5) & (panel["bias60"] < -15), "四因子+行业深跌+bias60<-15")
validate(c4 & (panel["sec_ret20"] < -5) & (panel["bias60"] < -10) & (panel["dist_lo20"] < 8), "四因子+行业深跌+bias60<-10+距低点<8")
print("\n=== 完成 ===", flush=True)