#!/usr/bin/env python3 """step45_negative_v2.py — 负面过滤 v2(时间稳健版) 问题:绝对阈值(mkt_news5>=1500)受新闻量逐年增长影响,早年信号被误杀 改进:新闻量用"当年分位"(年内相对热度),不受绝对量影响 同时用交易数据验证:年份内相对特征是否仍是负面因子 """ import numpy as np import pandas as pd print("=== 加载 ===", flush=True) tr = pd.read_csv("/tmp/step43_trades.csv") tr["year"] = tr["date"].str[:4] print("交易:", len(tr), flush=True) # 年内新闻分位(每笔交易按其所在年份的新闻量排名) tr["news_yq"] = tr.groupby("year")["mkt_news5"].rank(pct=True) # 年内 adx 分位 tr["adx_yq"] = tr.groupby("year")["sig_mkt_adx"].rank(pct=True) def evaluate(cond, label): sub = tr[cond] if len(sub) < 50: print("{}: n={} 不足".format(label, len(sub)), flush=True) return avg = sub["ret"].mean() wr = (sub["ret"]>0).mean()*100 big_loss = (sub["ret"]<-10).mean()*100 print("{}: n={} avg={:.2f}% wr={:.1f}% 大亏率={:.1f}%".format( label, len(sub), avg, wr, big_loss), flush=True) return len(sub) print("\n=== 年内分位版负面因子 ===", flush=True) print("\n-- 新闻年内分位 --", flush=True) for t in [0.3, 0.5, 0.6, 0.7]: evaluate(tr["news_yq"] >= t, "news年内分位>={}".format(t)) print("\n-- adx年内分位 --", flush=True) for t in [0.5, 0.6, 0.7]: evaluate(tr["adx_yq"] >= t, "adx年内分位>={}".format(t)) print("\n-- 组合(年内分位) --", flush=True) evaluate((tr["news_yq"] >= 0.5) & (tr["mkt_down_days"] <= 2), "news50%+down<=2") evaluate((tr["news_yq"] >= 0.5) & (tr["mkt_down_days"] <= 2) & (tr["sig_flow1"] >= -1e7), "news50%+down<=2+flow>-1e7") evaluate((tr["news_yq"] >= 0.5) & (tr["adx_yq"] >= 0.5) & (tr["mkt_down_days"] <= 2), "news50%+adx50%+down<=2") # 分年覆盖 comb = (tr["news_yq"] >= 0.5) & (tr["mkt_down_days"] <= 2) & (tr["sig_flow1"] >= -1e7) print("\n组合分年:", tr[comb]["year"].value_counts().sort_index().to_dict(), flush=True) print("保留:", comb.sum(), "/", len(tr), "({:.1f}%)".format(comb.mean()*100), flush=True) print("\n=== 完成 ===", flush=True)