用 7 年长样本复核 step54:时段坐实无效,周日效应符号翻转、撤回
用户追问"你用的是长时间周期分析的?"。原答案是 1m / 18.5 个月 / 3941 笔, 而上一轮的结论是"没效果"——没效果最怕样本不够,这个追问戳到了点子上。 改用 step41 那份 5m/15m/30m 复核:2019-09 → 2026-08,2525 天,8168 笔。 口径能对上——keep = (h1_agree==1) & push 就是深色过滤,出场配置 s2_so8_k2_m48 正是实盘那套 2/3/8/2/48(cfg_name 的分批命名,scale_at 默认 3)。 唯一差异是没加 ATR≥8bp 门控,而 §3.5 实测它在这些周期上几乎不触发 (30m 0%、15m 0.16%、5m 2.6%)。 ① 时段坐实无效。段间毛R极差的置换 p:5m 0.6185、15m 0.6687、30m 0.3105、 合并 0.6445,全部远离显著。1m 那个 p=0.0895 现在看清楚了,就是零分布里运气 略好的一条尾巴。 ② 周末效应没复现,而且符号翻转。1m 上周末−工作日是 -0.132(p=0.0246), 长样本上 5m +0.014、15m +0.142、30m -0.006、合并 +0.041;周日从 -0.199 (p=0.0079)变成 +0.033。这不是严格的样本外复现——1m 与 5m 是不同的信号 总体——但若"周末流动性薄所以吃亏"是真的市场结构效应,它没有理由只在 1m 上 出现、在 5m 上还反号。 所以上一提交里"周日效应统计上真实"那句要撤回。本步一共跑了约 35 个分组比较 (24 小时 + 两套时段定义 + 7 个星期 + 周末/周日),冒出一个 p=0.008 恰是多重 比较的期望产物。HANDOFF 里已把该结论标为撤回并记下两条教训:报告"无效"之前 先确认样本量撑得起这个"无";在几十个分组里挑出的最显著那个,默认它是噪声, 除非能在另一个总体上复现。 实践结论不变且更硬:不加任何时间维度的过滤,mom60≥7 仍是唯一值得上的开关。 复核走 --long,复用 step41 已有 feather,未重跑采集。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+47
-7
@@ -904,6 +904,8 @@ mom10 同形状(Q2 最好、Q4 最差),样本内外一致。**势要有—
|
||||
方向在两个时期一致,10 个币里 7 个周末更差(BTC 最甚 −0.336)。
|
||||
⚠️ 但**幅度在发现期塌了大半**(工作日−周末:样本外 −0.168 → 发现期 −0.039)。
|
||||
|
||||
> ⛔ **这条在长样本上没复现,而且符号翻转——见 ⑤,按噪声处理。**
|
||||
|
||||
**③ 关键:周末的劣势有一半住在 `mom60≥7` 那批单子里,step53 已经砍掉了**
|
||||
|
||||
| | 周末 vs 工作日 | 周日 vs 其余 |
|
||||
@@ -929,10 +931,48 @@ mom10 同形状(Q2 最好、Q4 最差),样本内外一致。**势要有—
|
||||
**`砍 mom60≥7 + 周日` 在 0~20bp 每一档都输给 `砍 mom60≥7` 单用**——叠加只是
|
||||
白丢 10% 的笔数。单用「砍周日」也要到 12bp 以上才赢过等权。
|
||||
|
||||
> **这一步的价值是排除,不是发现。** 用户问时段,直觉上「美盘流动性好该更赚」
|
||||
> 很难自证伪,跑完才知道它连随机切分都跑不赢。而顺手捞到的周日效应统计上真实
|
||||
> (p=0.008),却因为和已有过滤重叠而不可加——**"显著"和"值得做"是两件事,
|
||||
> 中间隔着一张决策表。**
|
||||
**⑤ 长样本复核(用户追问"你用的是长时间周期分析的?"):时段坐实无效,
|
||||
周末效应没复现且符号翻转**
|
||||
|
||||
1m 只能追到 18.5 个月 / 3941 笔,而上面的结论是"没效果"——**没效果最怕样本
|
||||
不够**。改用 step41 那份 5m/15m/30m:**2019-09 → 2026-08,2525 天,8168 笔**,
|
||||
过滤口径相同(`h1_agree==1 & push` 就是深色),出场配置 `s2_so8_k2_m48`
|
||||
正是实盘那套 2/3/8/2/48。
|
||||
|
||||
时段:**三个周期全部远离显著**——
|
||||
|
||||
| | 笔数 | 段间毛R极差 | 置换 p |
|
||||
|---|---|---|---|
|
||||
| 5m | 5434 | 0.046 | **0.6185** |
|
||||
| 15m | 1821 | 0.072 | **0.6687** |
|
||||
| 30m | 913 | 0.176 | **0.3105** |
|
||||
| 合并 | 8168 | 0.036 | **0.6445** |
|
||||
|
||||
1m 那个 p=0.0895 现在看清楚了:**它就是零分布里运气略好的一条尾巴。**
|
||||
|
||||
周末:**沿相反方向翻转**——
|
||||
|
||||
| | 周末−工作日 毛R | 置换 p |
|
||||
|---|---|---|
|
||||
| 1m(18.5 个月) | **−0.132** | 0.0246 |
|
||||
| 5m(7 年) | **+0.014** | 0.7616 |
|
||||
| 15m(7 年) | **+0.142** | 0.0710 |
|
||||
| 30m(7 年) | −0.006 | 0.9546 |
|
||||
| 合并(7 年) | **+0.041** | 0.2784 |
|
||||
|
||||
周日同样翻转:1m 上 −0.199(p=0.0079),合并长样本 **+0.033**(p=0.4774)。
|
||||
|
||||
⚠️ 这不是严格的样本外复现——1m 与 5m 的信号是不同的总体,不是同一批交易换个
|
||||
时间窗。但**若"周末流动性薄所以吃亏"是真的市场结构效应,它没有理由只在 1m 上
|
||||
出现、在 5m 上还反号**。结合本步一共跑了 ~35 个分组比较(24 小时 + 两套时段
|
||||
定义 + 7 个星期 + 周末/周日),冒出一个 p=0.008 恰是多重比较的期望产物。
|
||||
|
||||
> **这一步的价值是排除,而且排除得比第一轮更彻底。** 用户问时段,直觉上
|
||||
> 「美盘流动性好该更赚」很难自证伪,跑完才知道它连随机切分都跑不赢。
|
||||
> 更要紧的是**第一轮我把周日效应写成了"统计上真实"**——长样本一上就翻了符号。
|
||||
> 教训有两条:**① 报告"无效"之前先确认样本量撑得起这个"无"**;
|
||||
> **② 在几十个分组里挑出的最显著那个,默认它是噪声,除非它能在另一个总体上
|
||||
> 复现。** p 值不做多重比较校正就等于没做检验。
|
||||
|
||||
### 3.4 alpha 的来源(step32 消融)
|
||||
|
||||
@@ -1075,8 +1115,8 @@ step41 首轮跑的是错误的 3/1bp(见 §1.3),已用实际费率重算
|
||||
| **`available_ts` 改取 `bis[2]`(中枢成立即可用)以消除右边缘重画** | 重画确实从 6.5% 降到 1.2%、滞后 2.16→2.01,**但 alpha 被打成零**:实盘口径毛 R 0.933 → **−0.000**(扣费前就没了 edge),PF 3.22→0.80,余量 15.07→−2.20bp,8/8 币全变差。中枢没发育完就下注,支撑/压力还没立住。**「等中枢最后一笔」就是 alpha 本身,重画是必付代价。**推论:任何以「让信号更早确定」为目标的改动,先测毛 R,不要只看重画率和滞后 | step47 §5.42 |
|
||||
| **挑「信号根成交量大」的信号(有资金推的趋势)** | **方向完全相反**:vr60 四分位上毛R 单调 1.421→0.794、余量 27.18→13.47bp,样本内外 / 两套量比基准 / ATR 4 分位 4/4 / 逐时段 7/7 全部同向。止损率 22.5%→45.3% 翻倍,且**止盈率同时下降**(说明是方向变差,不是止损太窄)。根因:B4/S4 在突破根上进场,大量根 = 这一冲已经由别人的资金走完,你在收盘价接盘。**低量那一档才是好的**,可反向用作仓位权重 | step50 §3.31 |
|
||||
| **持仓中放量就平仓(把成交量当出场信号)** | **方向也是反的,且比入场那条更干净**:毛R 1.068 → 0.617(vr60≥3)/ 0.858(≥5)/ 1.009(≥8),**阈值越高越接近基线,最优点是「永不触发」**。触发的那批若不平,止盈率 45.7%、止损率 16.6%(全体基线 30.1% / 33.1%),**放量根标记的是最好的单子不是最差的**,平掉每笔让出 +0.484R。幸存者偏差已控(按持仓 ≥K 根分层 5/5 同向)。同一事件入场为负、持仓为正——入场时你是买方,持仓时资金是来接你货的 | step52 §3.31 |
|
||||
| **按时段交易(亚/欧/美)** | **差异在噪声量级**:段间毛R极差 0.122,置换检验 **p=0.0895**(随便切三份有 9% 概率切出这么大)。**美盘样本外 1.158 最好、发现期 0.885 最差**,两个时期反号。不是 ATR 混淆——控 ATR 后极差 0.101/0.108,和无条件的 0.122 一样,它本来就小 | step54 §3.392 |
|
||||
| **砍周日/周末** | 统计上真实(周日 p=0.0079、周末 p=0.0246,7/10 币同向),**但不可加**:伤害的一半住在 `mom60≥7` 那批里,§3.391 已砍。施加 `mom60<7` 后周末差 −0.132 → −0.058。决策表上 `mom60≥7 + 周日` 在 0~20bp **每一档**都输给 `mom60≥7` 单用 | step54 §3.392 |
|
||||
| **按时段交易(亚/欧/美)** | **噪声,已在 7 年长样本上坐实**:1m 段间毛R极差 0.122、p=0.0895 且美盘两期反号;5m/15m/30m(2019-09→2026-08,8168 笔)p = **0.62 / 0.67 / 0.31**,合并 **0.64**。不是 ATR 混淆——控 ATR 后极差 0.101/0.108,与无条件的 0.122 一样,它本来就小 | step54 §3.392 |
|
||||
| **砍周日/周末** | **1m 上显著但没复现,符号还翻了**:1m 周末 −0.132(p=0.0246)、周日 −0.199(p=0.0079);7 年长样本 5m **+0.014**、15m **+0.142**、30m −0.006、合并 **+0.041**(周日 +0.033)。本步共跑 ~35 个分组比较,冒出一个 p=0.008 恰是多重比较的期望产物。**即便按 1m 那版当真也不可加**:伤害的一半住在 `mom60≥7` 里,`mom60≥7 + 周日` 在 0~20bp 每一档都输给 `mom60≥7` 单用 | step54 §3.392 |
|
||||
| 线段(`Chan_XD`)做大级别 | 滞后太大,且中枢极少 | 早期,用户也这么说 |
|
||||
|
||||
---
|
||||
@@ -2119,7 +2159,7 @@ API 限流风险隔离三个好处。
|
||||
| 51 | **因子化仓位**(把 49/50 做成权重)→ 量因子该做成**开关**不是权重(硬砍 vs 加权:R夏普 0.496/0.442、并发 6.00/7.98);**前序因子不该进仓位**,边际收益买不起集中度。优势形态是削尾不是抬均值 |
|
||||
| 52 | **持仓中放量出场**(用户提议)→ 反的,最优点是永不触发;放量根标记的是止盈率翻倍的好单。自带模拟器与 `walk_exits` 逐笔对拍,10/10 币通过 |
|
||||
| 53 | **开仓前的量与趋势方向**(用户提议)⭐ → 前段量单调(越小越好,独立于信号根量);前段动量**驼峰形**(Q2 最好、Q4 最差)。`砍 mom60≥7` 全面优于 §3.39 的 `砍 vr60≥4`,且总R 比不砍还高。附滑点决策表 |
|
||||
| 54 | **开仓时段(亚/欧/美)**(用户提议)→ **无效**,置换检验 p=0.09 且美盘两期反号。星期几有效(周日 p=0.008)但与 `mom60` 过滤伤害重叠,叠加在每一档滑点上都更差。**排除型结论** |
|
||||
| 54 | **开仓时段(亚/欧/美)**(用户提议)→ **无效**。1m 上 p=0.09、美盘两期反号;**7 年 × 5m/15m/30m 复核 p=0.62/0.67/0.31**,坐实。周日效应在 1m 上 p=0.008 但长样本**符号翻转**(+0.033),按多重比较的噪声处理。**排除型结论,含一次自我更正** |
|
||||
|
||||
输出都在 `research/out/`。**2026-08-27 清理过一轮**:step1~20 的输出(早期方法论
|
||||
已被推翻,含未来函数偏差)与旧口径备份一并删除,只留支撑当前结论的证据。
|
||||
|
||||
@@ -299,11 +299,90 @@ def decision(d: pd.DataFrame, cuts: dict) -> None:
|
||||
print(pd.DataFrame(rows).to_string(index=False))
|
||||
|
||||
|
||||
SRC41 = HERE / "out" / "step41_exit_tp.feather"
|
||||
# step41 的分批出场配置名,与实盘完全一致:SL 2 / 减半 3(scale_at 默认)/
|
||||
# runner 8 / runner 止损 2 / 48 根。见 lib.exit_model.cfg_name
|
||||
CFG41 = "s2_so8_k2_m48"
|
||||
|
||||
|
||||
def long_history() -> None:
|
||||
"""用 5m/15m/30m 的 7 年数据复核时段与星期几。
|
||||
|
||||
为什么要这一步:1m 只能追到 18.5 个月(3941 笔),而时段结论是"没效果",
|
||||
**没效果最怕的就是样本不够**。step41 那份跨 2019-09 → 2026-08,5m 单周期
|
||||
就有 5434 笔,且过滤口径相同(`h1_agree==1 & push` 就是深色),出场配置
|
||||
也能对上实盘那套。若长样本上仍然测不出时段效应,"无效"才站得住。
|
||||
|
||||
⚠️ 口径差一处:这里没加 ATR≥8bp 门控。§3.5 实测该门控在这些周期上几乎
|
||||
不触发(30m 0%、15m 0.16%、5m 2.6%),所以影响可忽略,但要记着。
|
||||
"""
|
||||
from lib.exit_model import fee_of, taker_notional
|
||||
|
||||
d = pd.read_feather(SRC41)
|
||||
d["date"] = pd.to_datetime(d["date"])
|
||||
g, r, c = (d[f"{CFG41}_{k}"].to_numpy() for k in ("g", "r", "c"))
|
||||
d["net"] = g - fee_of(r, c)
|
||||
d["gR"] = g / (SL * d.atr_pct.values)
|
||||
d["R"] = d.net / (SL * d.atr_pct.values)
|
||||
d["tn"] = taker_notional(r, c)
|
||||
d["atr_bp"] = d.atr_pct * 1e4
|
||||
utc = d.date.dt.tz_convert("UTC")
|
||||
d["utc_h"], d["utc_dow"] = utc.dt.hour, utc.dt.dayofweek
|
||||
|
||||
print("\n" + "#" * 100)
|
||||
print("########## 长样本复核:5m/15m/30m × 7 年 ##########")
|
||||
print(f"{len(d)} 笔 · {d.symbol.nunique()} 币 · "
|
||||
f"{d.date.min():%Y-%m} → {d.date.max():%Y-%m}"
|
||||
f"({(d.date.max()-d.date.min()).days} 天)")
|
||||
print(f"出场配置 {CFG41}(= 实盘的 2/3/8/2/48)· 深色已过滤 · 无 ATR 门控")
|
||||
|
||||
for tf in ("5m", "15m", "30m"):
|
||||
x = d[d.ltf == tf].copy()
|
||||
if len(x) < 300:
|
||||
continue
|
||||
x["seg"] = label_session(x.utc_h, SESSIONS)
|
||||
print(f"\n--- {tf}({len(x)} 笔)时段 ---")
|
||||
rows = []
|
||||
for n, _, _ in SESSIONS:
|
||||
s = x[x.seg == n]
|
||||
ins, oos = s[s.group == "样本内"], s[s.group == "样本外"]
|
||||
row = stat(s, n, len(x))
|
||||
row["样本内毛R"] = round(ins.gR.mean(), 3) if len(ins) >= 30 else None
|
||||
row["样本外毛R"] = round(oos.gR.mean(), 3) if len(oos) >= 30 else None
|
||||
rows.append(row)
|
||||
print(pd.DataFrame(rows).to_string(index=False))
|
||||
permutation(x, SESSIONS, n_iter=10_000)
|
||||
|
||||
we = (x.utc_dow >= 5).to_numpy()
|
||||
print(f"\n--- {tf} 工作日 vs 周末 ---")
|
||||
print(pd.DataFrame([stat(x[~we], "工作日", len(x)),
|
||||
stat(x[we], "周末", len(x))]).to_string(index=False))
|
||||
perm_binary(x, we, f"{tf} 周末 vs 工作日", n_iter=10_000)
|
||||
|
||||
print("\n--- 三周期合并(每笔等权)---")
|
||||
d["seg"] = label_session(d.utc_h, SESSIONS)
|
||||
print(pd.DataFrame([stat(d[d.seg == n], n, len(d))
|
||||
for n, _, _ in SESSIONS]).to_string(index=False))
|
||||
permutation(d, SESSIONS, n_iter=10_000)
|
||||
we = (d.utc_dow >= 5).to_numpy()
|
||||
print(pd.DataFrame([stat(d[~we], "工作日", len(d)),
|
||||
stat(d[we], "周末", len(d))]).to_string(index=False))
|
||||
perm_binary(d, we, "合并 周末 vs 工作日", n_iter=10_000)
|
||||
perm_binary(d, (d.utc_dow == 6).to_numpy(), "合并 周日 vs 其余",
|
||||
n_iter=10_000)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--src", default=str(SRC))
|
||||
ap.add_argument("--long", action="store_true",
|
||||
help="只跑 5m/15m/30m 的 7 年长样本复核")
|
||||
args = ap.parse_args()
|
||||
|
||||
if args.long:
|
||||
long_history()
|
||||
return
|
||||
|
||||
from step50_volume import prep
|
||||
|
||||
d = pd.read_feather(args.src)
|
||||
|
||||
Reference in New Issue
Block a user