Files
Chan/research/HANDOFF.md
T
jackyu66gitandCursor 84ee59ecfb research: B4 时点干净,但实盘做的不是回测那批单(实盘口径 PF 0.73 vs 回测 4.21)
step63 因果回放:B4 的时点完全干净——100% 召回、100% 准时、零滞后,
一类那个把 PF 从 2.35 打到 0.92 的坑(§3.396)B4 没有。

但回放多产出 592 个全量口径里不存在的信号,PF 0.46 / t −5.03。
step68 按实盘口径复测(2001 根滚动窗口、每 500 根 init_stream、只做当根收盘,
逐行对齐 shadow_signal.py),并把三道滤网全测一遍:

  无过滤    789 笔,额外占比 75%,PF 0.64
  三道全开  195 笔,额外占比 74%,PF 0.73

滤网把成交量砍掉 75% 却几乎不改变额外信号占比——按同比例刷掉好的和坏的。
拆开看:回测里也有的 51 笔 PF 4.21/t+5.90,回测里没有的 144 笔 PF 0.26/t−6.21。

即回测报的 4.21 拿不到:那 51 笔要事后全量重算才能识别,实盘当下分不出来。
机制是重画——实时算出的中枢,数据变多后被修正掉。与 §3.396 同类:
一类错在时点,B4 错在存在性。

顺带闭掉一条待办:2001 根窗口与 2万→4万根增长窗口跑出完全相同的 789/197/592,
窗口左边界效应判为否。

限定:本轮是 5m/30m 而实盘跑 1m,需单独复验;同向过滤器被开了未来函数后门
(HTF 时间线用全量算),真实盘只会更差。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 23:46:19 +08:00

168 KiB
Raw Blame History

缠论信号研究 → 实盘落地:交接文档

最后更新:2026-08-27。写给接手这项工作的下一个 agent。 读完这份文档应该不需要再翻聊天记录。若确有需要,历史转录在 /Users/jack/.cursor/projects/Users-jack-Project-chan/agent-transcripts/


0. 一句话现状

策略在回测和多重偏差审计下都站得住(跨 11 个币、7 年、多空对称、无未来函数), 研究阶段基本结束;当前唯一的拦路问题是「实盘执行成本能否压进预算」, 下一步是写影子交易器实测滑点,而不是继续调参。

用户明确要求:不要再跑新的参数优化。 他的原话是「很多时候回测数据特别好, 一到 dry run 和实盘就歇菜了」。他要的是执行层的验证。


1. 策略的确切定义

这是全文最重要的一节。所有回测数字都基于以下这套口径,改任何一条数字就不可比。

1.1 信号生成(三层)

第一层  小级别(LTF) 自身的中枢         build_htf_zones(cdf, ltf, chan=chan_l)
第二层  中枢突破后回抽不回,收盘转强 → 入场   find_fast_bsp3(cdf, zones)
第三层  大级别(HTF) 分型方向必须同向        attach_htf_context(...) 后取 h1_agree == 1
可选    中枢阶梯方向过滤(顺向推进)        z_above / z_below,见 1.4

用户对「区间套」的定义(务必按这个理解,早期我理解错过): 大级别(1h/4h)分型定位转折点 + 小级别(15m/5m/1m)中枢突破形成第三类买卖点。 不是大级别中枢突破。

1.2 find_fast_bsp3 的当前默认参数

research/lib/fast_bsp3.py

参数 默认值 含义与注意
scan 200 中枢成立后向后扫多少根找突破
pullback_win 30 回抽窗口
tol -1.0 负值=禁用「回抽未触及边界就跳过」。这是最关键的参数,见 3.2
max_per_zone 1 同一中枢只做首次入场,见 4.2
require_touch False 不要求回抽触及中枢边界,见 3.2

tol=-1 + require_touch=False 是当前口径,滞后 2.2 根。 早期默认(tol=0.003, require_touch=True)滞后 5.8 根,年化从 906% 掉到 370%。 新旧差异已完整量化在 step34(tol 扫描)与 step33require_touch)里, 旧口径的原始输出已清理——不需要它,也不要回到旧口径

1.3 交易执行口径

SL, TP, MAX_BARS = 1.5, 3.0, 48      # ATR 倍数止损/止盈 + 超时根数
run_trades(cdf, entries, SL, TP, MAX_BARS, fee=..., entry_delay=1)
  • 入场:信号次根开盘价entry_delay=1),不是信号根收盘价
  • 研究口径成本:4bp 手续费 + 1bp 滑点 = 5bp(所有带「已扣 5bp」的数字都是这个)
  • ATR 取信号根的值(atr[sig_idx]),不是入场根

⚠️ TP=3.0 已被证明偏小(step41/42,见 3.5 与 5.3,且出场参数要按级别分开定。 本文档所有历史数字仍是 TP=3.0 口径,改口径前不要混用

成本模型:不是一刀切的 5bp(用户 2026-08-27 指出)

用户指出「只有开仓才是 taker」。对了一半——止盈挂限价确实是 maker 但止损是 stop-market,成交时仍是 taker(做成 stop-limit 会有急跌不成交的 风险,那种损失远大于省下的费)。所以按出场原因分别计费。

实际费率档位(用户 2026-08-27 给的,单边):返佣前 taker 0.040% / maker 0.016%API 返 50% → taker 2.0bp / maker 0.8bp。

环节 性质 单边费率
入场(次根开盘市价) taker + 滑点 2.0bp
止盈(限价被动成交) maker,无滑点 0.8bp
止损(stop-market taker + 滑点 2.0bp
超时(到点市价平) taker + 滑点 2.0bp

⚠️ step41/42 首轮跑的时候这里写的是 taker 3.0 / maker 1.0bp 隐含「原始 taker 6bp、返 50% 得 3bp」的错误前提。真实原始是 4bp。 方向是保守的——taker 高估了 50%,所以那两步跑出来的净收益、 滑点余量、均R 全部偏低,不是偏高。exit_model.py 已改成实际值, 但本文档里凡是标注「旧费率 3/1bp」的数字尚未逐条重算

SL1.5/TP3/48根 1m 样本外实测(止盈成交占 60%):

口径 平均成本 说明
全 taker 双边 8.00bp 最早的口径,双重高估
混合费率 @ 3/1bp 6.20bp step41/42 首轮
混合费率 @ 实际 2/0.8bp 2.00bp 当前
研究口径 固定 5bp 5.00bp §2 那批老数字

注意方向变了:研究口径的 5bp 现在是偏保守的。 实际混合费率只有 2bp。 实现在 research/lib/exit_model.pystep41/42 共用。 分批离场不额外增加费用(手续费按名义额收,出场 0.5+0.5 总额不变), 而且第一批必然是止盈成交,所以分批在成本上还占便宜。

1.4 阶梯过滤(顺向推进)

对应缠论「趋势 vs 盘整」:当前中枢相对前一个中枢是否同向推进。

pg, pdn = z["zg"].shift(), z["zd"].shift()
z["z_above"], z["z_below"] = z["zd"] > pg, z["zg"] < pdn
push = z_above if direction == 1 else z_below

加上它 PF 从 2.72 → 3.4130m/2h)。用户特别在意这一点,因为它印证了 缠论对趋势的定义(一个分型后第一个中枢就反转的概率低于出现第二个中枢后反转)。

1.5 各级别的确切配对

小级别 大级别(h1,做同向过滤) 备注
1m 5m step23 的配置是 1m:5m:15m15m 只记录不过滤
5m 30m 统计量最强
15m 1h
30m 2h 单笔质量最高

2. 最优配置与核心数字

2.1 级别矩阵(step28,同向+阶梯,3 币)

组合 笔数 胜率 中位 PF t值
5m/30m 1321 53.1% +0.31% 1.98 10.16
30m/2h 258 65.1% +1.65% 3.41 8.51
5m/15m 1292 51.7% +0.24% 1.82 8.84
15m/1h 467 56.5% +0.74% 2.46 7.96

选择逻辑:30m/2h 单笔质量最好,5m/30m 统计显著性最强。1h 及以上小级别笔数不足。

2.2 跨品种样本外(step37)— 最有说服力的一项

参数一个没动,拿 8 个完全没参与调参的币验证:

分组 笔数 年笔数 胜率 中位 PF t值 剔10%PF
样本内(BTC/ETH/SOL) 2309 334 61.4% +0.531% 2.86 +19.11 1.77
样本外(8 个新币) 5859 884 62.9% +0.592% 2.73 +28.50 1.66

逐币最弱的 XRP 仍是 PF 2.21 / t 7.64。没有一个币是负的。

2.3 收益量级——务必用正确口径(step35 第 5 节)

这一条最容易被误读,历史上我自己也一度报错过口径:

口径 年化 回撤 Sharpe
A 1%风险+20倍上限+复利 +1323.8% 8.1% 10.38
B 1%风险+20倍上限+不复利 +270.0% 8.4% 10.38
C 固定名义1倍+不复利 +194.7% 8.4% 7.95
D 固定名义3倍+不复利 +584.1% 25.2% 7.95

只有 C/D 是可以直接对照的量级。 那些 906%/1323% 的数字来自复利+杠杆假设。 平均单笔杠杆 2.1x(中位 1.8x)。 未含资金费率,未含同时持仓的保证金约束。


3. 已验证成立的结论

3.1 没有未来函数(step38,最要紧的一项)

担心的是 incremental.py 里那句注释:「最后一笔 is_sure 允许收回」—— 中枢生效时刻 available_ts 取自笔的 sure_time,而那是全量重算得出的。

做法:对每个信号只喂到该根为止的数据(窗口 4000 根),重跑 TF_DF → 中枢 → fast_bsp3,看信号是否真的在那一刻存在。

结果:同根命中 100.0%(抽检 1217 个信号),完全消失 0.0%,假阳性 0.7%。 偏移中位 +0.0 根。回测口径可信。

3.2 滞后是收益的第一驱动(step34)

口径 笔数 滞后(根) 胜率 PF 年化 Sharpe
禁用跳过(现用) 2309 2.2 61.4% 2.86 +906.1% 9.02
tol 0 2214 2.7 60.4% 2.74 +731.3% 8.43
tol 0.1% 2134 3.6 58.7% 2.64 +569.8% 7.65
tol 0.3%(旧默认) 2045 5.8 55.4% 2.37 +370.4% 6.30
tol 1% 1561 9.9 48.3% 1.88 +112.0% 3.53

滞后与收益严格单调。这也意味着实盘延迟会直接侵蚀收益,是下一阶段的核心风险。

3.3 其余已排除的偏差

  • 中枢生效时刻step36 §1):0% 走 end_time 回退分支,全部用 sure_time
  • 多空对称step36 §3):做多 PF 3.12 / t 14.77,做空 PF 2.62 / t 12.27 → 不是单纯吃加密货币的上涨 beta
  • 时间样本外step36 §4):20192022 挑参数,20232026 验证 → PF 从 3.31 降到 2.44t 仍 12.29。有衰减但成立
  • 滑点脆弱性step35 §1):加到 +30bp 仍 PF 1.73 / t 10.15
  • 入场后移step35 §2):后移 1→4 根平滑衰减(PF 3.18→2.53), 未来函数会呈断崖,这里没有
  • 持仓重叠(step35 §3-4):单腿平均并发 0.01,组合 9 腿平均并发 0.1, 有仓位时间仅 8.6%

⚠️ 「各笔基本独立」这句原来说得太满,已修正。 低并发确实成立, 但那只说明「时间上不重叠」,不等于「统计上独立」——见下方 3.31。

3.31 新出场口径下的并发,以及信号之间的相关性(1m,8 币样本外,门控后)

分批出场把平均持仓从 9.9 根拉到 29 根,并发必须重算:

出场 范围 平均并发 有仓位时间 峰值并发
旧 SL1.5/整仓TP3/48 8 币组合 0.043 4.0% 6
新 SL2/分批→8/留损2/48 8 币组合 0.120 10.2% 6

并发翻近三倍,绝对值仍低。要紧的是峰值 6——8 个币里 6 个同时在仓。

信号在时间上扎堆,且方向高度一致:

  • ±5 分钟内有其他币信号的占 21.6%,±30 分钟 39.6%,±60 分钟 49.6%
  • 同一小时内有 ≥2 个币发信号的时段占 20.9%(2262 个小时), 其中 92.7% 方向完全一致,完全对冲的只有 5.8%

这不是缺陷,是信号在正常工作。 市场同涨同跌时,同一个中枢突破形态在 各币上同时出现;若 6 个币同时发信号却方向随机,那才说明信号是噪声。

但它有两个后果:

  1. t 值有一定虚高:有效样本量小于名义的 13929 笔。不足以推翻结论 (t 值 43 以上),但「各笔基本独立」不再是准确说法
  2. 加币不产生分散,只增加机会数量。组合波动不会随币数下降。 仓位不能按「1% 风险 × N 个币」线性放——峰值 6 仓 × 92.7% 同向, 8 个币就是 6% 风险压在一个移动上;平均杠杆 3.6x 时峰值 21.6 倍名义额。 要设并发上限,或按当前并发数缩放单仓风险。 §10 里「保证金约束未建模」那条在扩币前必须先做

好消息:§5.3 报的 12.6% 最大回撤是在真实时间序列上按实际发生顺序算的, 亏损扎堆已经体现在里面,不是用独立假设推出来的。相关性没被漏掉, 只是不能再指望「加币能降回撤」。

11 币全样本复核(step482026-08-281161 笔 / 208 天 / 实盘口径。

相邻两笔的间隔:中位 122 分钟,62.8% 超过 1 小时,组合平均每天仅 5.58 笔。 同时持仓数:90.9% 的时间空仓,7.5% 只有 1 仓,≥2 仓合计 1.7%,峰值 8。

所以「11 个币会不会同时开」的答案是:绝大多数时候不会,但左尾是硬的—— 7.4% 的信号与前一笔同分钟、20.7% 在 5 分钟内。而这批的方向:

同一分钟出现多笔的时刻共 72 个,方向完全一致的占 100.0%(不是 92.7%)。

这些同时开的仓不是分散,是同一笔押注被拆到几个币上做。 名义 3 个仓位,实质是 3 倍单向敞口。两条推论:

  1. 保证金不是约束,闲置才是。 91% 时间空仓,峰值并发只占 0.1% 的时间。 「币多了保证金不够」基本不成立,真问题是资金绝大部分时间在睡觉
  2. 并发上限要按「同向净敞口」设,不能按「仓位个数」设。 同时开的必然同向,限「最多 3 仓」等于允许 3 倍单向敞口

扎堆的交易赚不赚钱(step48:必须把「同一分钟」和「错开几分钟」分开, 两者结论相反,混在一起会得出错误判断。

分组 笔数 胜率 毛R PF 余量bp
真孤立(±5 分钟内无同伴) 763 (66%) 65.5% 0.832 2.83 11.92
错开:5 分钟内但不同分钟 240 (21%) 82.1% 1.443 7.31 29.59
同一分钟撞在一起 158 (14%) 63.3% 0.777 2.20 12.35

错开的那批是全样本最好的一档(毛R 是孤立组的 1.7 倍),而严格同分钟的 反而略差于孤立组。机制上说得通:错开 = 一波行情从某个币扩散开,后发信号是 对先发的确认;同分钟 = 全市场同时被一个冲击打中,那就是追高。

簇级复核(±5 分钟合一簇,每簇算一个观测,排除重复计数): 多笔簇簇均毛R 1.180 vs 单笔簇 0.832,簇级 R 夏普 0.848 vs 0.459。 结论在簇级依然成立。多笔簇内全赢 59.5%、全输 10.1%、有赢有输 30.4% —— 簇内风险不可分散,但偏度有利(赢的簇是输的簇的 6 倍)。

集中度上两类没差别:整簇方向一致 99.4%(同分钟 100%、错开 99.2%)。 簇内中位 2 个币、最大 8,跨度中位 2 分钟。所以「限制最多 N 个并发仓位」 把两类一视同仁是错的,它们期望收益差 1.9 倍。

簇内顺序:看着是圣杯,其实大半是未来信息(step48) ⚠️

用户提出研究簇内的币种先后顺序。事后按位次切,落差很大:

分组 笔数 胜率 毛R PF 余量bp
(对照)孤立单笔 763 65.5% 0.832 2.83 11.92
簇内第 1 笔 158 81.6% 1.441 5.58 25.63
簇内第 2 笔 158 72.8% 1.085 3.93 20.09
簇内第 3 笔 53 62.3% 0.733 2.19 11.41

但「我是首发」= 「接下来 5 分钟没有别的币再发」,这是未来信息。 首发赢面大恰恰因为后面真跟出来了别的币(那波行情是真的), 而"会不会跟出来"在下单那一刻不可知。

换成开仓时真正可知的信息(过去 5 分钟有无别的币先发):

分组 笔数 占比 胜率 毛R PF 余量bp
无前序 979 84% 68.4% 0.938 3.19 14.13
有前序 ≥1 个币先发 182 16% 69.8% 1.021 3.71 21.88

43% 的落差塌成 8.8%,方向还反过来(跟随略优于首发)。 但残留不是零,且有一处比毛R 更要紧:滑点余量 14.13 → 21.88bp,高 55%。 对 1m 这是实打实的——1m 的生死线就在执行成本上。

「谁在领跑」无稳定结构:首发率 BTC 8.6% ~ DOGE 18.4%158 次首发摊到 10 个 币平均 15.8 次,这个离散度基本是抽样噪声。

这个方向的纪律(组合空间大,样本只有 158 个簇,不设约束必然批量产出 假发现):每一个切法都必须能写成「开仓那一刻我已经知道的信息」。 凡用到「这一簇共几个币」「我是第几个」「簇跨度多长」的,都含未来信息, 回测漂亮但实盘拿不到。

唯一可交易的那条已通过样本外验证(step49)10 币 × 80 万根, 2025-02 ~ 2026-08 共 3941 笔,其中发现期(step48 用过的最近 208 天)1161 笔、 样本外 2780 笔。

无前序 有前序
样本外 毛R 1.086 1.275 +0.189
样本外 余量 18.83bp 24.89bp +6.06bp
发现期 余量 14.14bp 21.96bp +7.82bp

逐时段 6/6 全部同向(余量差 12.52 / 9.10 / 3.82 / 3.89 / 6.95 / 9.25bp 中位 8.03)。发现期毛R 差只有 0.085,样本外反而放大到 0.189——不是过拟合 衰减,是发现期恰好偏保守。占比很稳,各时段 13~19%。

ATR 混淆已排除:有前序 的 ATR 确实略高(中位 15.04 vs 13.13bp),但按 ATR 四分位分层后 4/4 层同向,层内余量差 3.29 / 8.39 / 5.16 / 4.14bp,与不分层 的 +6.06 同量级。且毛R 本身是 ATR 归一化指标,其 +0.19 不可能是 ATR 假象。

可用方式:这 16% 的信号能多容忍约 6bp 执行成本。

「加仓位权重」这条已被 step51 否掉,见 §3.39。 +6bp 余量在 5bp 滑点假设下只值约 0.011R,而这批信号 100% 发生在别的币已有仓位时—— 加权后峰值并发 7.00 → 8.46、回撤 17.3 → 19.2,按峰值保证金归一是净负的。 边际收益买不起它带来的集中度。

仍未测的出路是放宽 ATR 门控(多做几笔,而非每笔做大):ATR 最低层里 有前序 余量仍有 14.92bp(对照 11.63),提示门控对它们可以更松。 尚未回测,先别改。

⚠️ 「同分钟 vs 错开」是看过数据之后才划的切法,不是事先定的。 208 天、158 个簇,post-hoc 切分容易切出噪声。拿它当仓位规则前必须换一段 时间验证。 目前可确定的只有「扎堆整体更好」(簇级也成立); 「好处全集中在错开那一档」尚待样本外确认。

信号根成交量:假设方向是反的,高量入场明显更差(step50)

用户假设「有资金的趋势才是好趋势」,预期开仓根成交量越大越好。 成交量在信号根收盘时可知,符合上面那条纪律,是合法的可交易切法。 同一批 3941 笔,按信号根相对成交量四分位:

vr60 分位(当根量 / 前 60 根均量) 样本外毛R 样本外余量 发现期毛R 发现期余量
量最低(中位 0.63 1.421 27.18bp 1.192 20.91bp
量中低 1.187 20.37bp 1.133 19.80bp
量中高 1.067 18.69bp 0.841 13.30bp
量最高(中位 5.34 0.794 13.47bp 0.634 7.94bp

单调递减,且样本内外、两套量比基准(前 10 根 / 前 60 根)全部同向。 稳健性达到了 step49 那条的标准:ATR 四分位 4/4 同向(层内毛R 差 0.327 / 0.238 / 0.347 / 0.592),逐时段 7/7 同向。不是 ATR 换脸。

机制在出场结构里,伤害集中在止损命中率

vr60 分位 止盈% 止损% 超时% 到 3ATR 减仓率 赢时均R 亏时均R
量最低 33.5 22.5 44.0 77.6% 1.830 1.098
量最高 26.1 45.3 28.6 60.9% 1.651 1.106

亏损幅度四档全是 −1.10(止损就是止损),赢时均R 只降 10%。止损率翻倍 是全部损失来源。这里有个判别点:若只是「2 ATR 止损相对突然放大的波动太窄」 的尺度错配,超时单应按原比例分流进止盈和止损两侧;实际是超时(−15.4pp) 和止盈(−7.4pp)一起流进止损(+22.8pp)。方向本身在变差,不只是止损太窄 所以对策是回避而非放宽止损。

为什么直觉会反:B4/S4 是在突破根上进场的。大量根意味着这一冲已经由别人 的资金完成了,你在它的收盘价接手——高量不是「资金在推你」,是「你在给推 完的人接盘」。用户的直觉在中长周期趋势跟随上成立,但这个入场点站在它的 对面。「有资金」要能获利,必须在资金到达之前进场,不是同时。

有前序 是两件独立的事,不是同一效应换个说法(相关性很弱:有前序组 vr10 中位 1.76 vs 无前序 1.46)。2×2 交叉,最好的一档是两者叠加:

笔数 占比 毛R 余量bp
低量 × 有前序 253 6% 1.398 31.00bp
低量 × 无前序 1717 44% 1.092 18.35bp
高量 × 有前序 382 10% 1.074 19.62bp
高量 × 无前序 1589 40% 0.988 16.39bp

尚未做的:把量比做成硬过滤(如砍掉最高四分位)要付 25% 的笔数, 而 1m 本来就稀疏(10 币约 2.5 笔/天)。先当仓位权重用,别当开关。 (已由 step51 §3.39 定论:该做成开关,不是权重。)

但持仓中放量不是该平仓的信号——恰恰相反(step52)

用户接着问:既然入场撞上放量是接盘,那持仓中出现放量根是不是也说明这一波 走完了、该直接平掉?测下来是反的,而且反得比入场那条还干净。

规则:持仓期间任一根 vr60 ≥ 阈值 就收盘市价平掉(taker)。同根内优先级 止损(盘中)> 目标(盘中)> 放量平仓(收盘)。10 币 3941 笔:

全样本 毛R 净均R R夏普 PF 余量bp 胜率 均持仓
基线(不看量) 1.068 0.940 0.627 3.80 18.45 71.7% 30.0
vr60≥3 就平 0.617 0.475 0.459 2.81 7.81 69.7% 11.1
vr60≥5 就平 0.858 0.723 0.568 3.37 12.85 71.7% 19.8
vr60≥8 就平 1.009 0.878 0.617 3.69 16.68 71.9% 26.3

阈值越高(触发越少)越接近基线,单调——这条曲线的最优点是「永不触发」。 样本内外一致。「浮盈才平」的变体把胜率抬到 74.4%(基线 71.7%)但毛R 掉到 0.655,是过早止盈的教科书特征:胜率上升、期望下降

根因在这里。vr60≥5 触发的 1769 笔(45%),若不平,最终:

占比 净均R 对照:全体基线
走到 8ATR 止盈 45.7% +2.640 30.1%
最终止损 16.6% 0.422 33.1%
48 根超时 37.8% +1.283 36.8%

持仓中的放量根标记的是最好的那批单子,不是最差的。 在那里平掉每笔让出 +0.484R。幸存者偏差已控(触发组平均已活 9.6 根):按基线持仓 ≥K 根分层后 5/5 档全部同向,放量组止盈率约为无量组两倍——

存活≥K根 放量组止盈率 无量组止盈率 放量组净均R 无量组净均R R差
5 41.2% 19.8% 1.443 0.658 +0.785
10 42.7% 21.4% 1.599 0.898 +0.700
20 34.4% 20.3% 1.558 1.106 +0.452
30 24.7% 15.5% 1.469 1.188 +0.281

同一个事件,入场时是负的、持仓时是正的,区别只在你站在它的哪一边。 入场那根放量你是买方,付的是资金已经推到的价;持仓中那根放量是资金来接你的 货,那是兑现不是离场。用户「有资金的趋势才是好趋势」的直觉成立, 但作用点在持仓期而非入场点

未测的建设性方向:既然持仓中放量预示止盈率翻倍,或许该延长 runner 目标 / 加仓而不是平仓。注意基线已经隐含吃到了这部分(它就是拿着不动), 所以要多拿必须主动改目标位,这是新参数,要重新回测。 R差 随 K 递减(0.785 → 0.281)说明越晚出现的放量根剩余空间越小, 若要做,触发窗口应偏前段。

TRX 应从币池剔除:实盘口径 208 天只有 5 笔,ATR 门控几乎全刷掉 (与 §5.3「2026 只剩 4.2%」一致)。实际可用是 10 个币,不是 11 个。 逐币每天笔数:DOGE/AVAX/SOL 约 0.66BTC/LTC 0.45BNB 0.31TRX 0.02。

3.32 多空对称:这不是伪装成策略的 beta

用户问「整个市场都是正相关的,是不是很少有独立行情」。市场相关是真的, 但这个策略不是市场敞口1m8 币样本外,门控后):

方向 笔数 占比 胜率 净bp PF 均R t值
做多 7057 50.7% 71.2% 35.4 4.05 0.968 43.0
做空 6872 49.3% 71.9% 40.5 4.40 1.006 43.4

做空还略好。所有时段净方向合计仅 +185 笔(总 13929),长期无方向偏置

分年更决定性——若是 beta,2021 年做空该被打爆:

多 均R / PF 空 均R / PF 空头占比
2021 大牛 1.019 / 4.45 1.116 / 5.34 46.5%
2022 熊 0.901 / 3.85 0.962 / 4.07 53.8%
2026 熊 0.863 / 3.33 0.793 / 3.42 55.9%

2021 年做空的 PF 5.34 是整张表最高的一格,七年里没有一年、 没有一个方向是亏的。空头占比随行情切换(牛市 46.5% → 熊市 55.9%), 说明结构识别在跟着市况调方向。与 §3.3 的 30m 结论(多 PF 3.12 / 空 2.62)一致。

3.33 扩币的筛选标准(两条方向相反的约束)

  1. ATR 分布对门控阈值(当前 8bp)——够不够扛住固定成本
  2. 流动性 / 盘口价差——滑点能否压进预算

两条都是及格线,不是「越高越好」的排序依据。

⚠️ 「那就做 ATR 最大的」是错的,两个方向都不支持:

币内(每个币按自己的 ATR 分位)——严格单调,高 ATR 时刻更差:

币内 ATR 分位 净均R R夏普
最低 20% 1.040 0.690
40-60% 0.982 0.655
最高 20% 0.878 0.599

ATR 飙升往往意味着行情已走过头,噪声大、容易反抽。 (但不必加上限门控:最高分位的 0.878 仍然是好交易,砍掉只是白丢机会。)

跨币——看似正相关(ATR vs 净均R r=+0.684),但剔除 BTC 后掉到 +0.469, 且其余 9 币的净均R 区间只有 0.935~1.024(极差 0.089)。BTC 自己 0.787, 明显低于所有其他币。BTC 差更可能因为它是最大最有效的市场、结构性机会少, 把它的低 ATR 与低 R 读成因果是过度拟合一个点。

ATR 唯一真正提供的是 bp 余量r=+0.85,剔 BTC 后仍 +0.85)。 但这是机械关系——余量按定义随 ATR 缩放。它有用(滑点大致固定在 bp, 余量高就能扛更多滑点),但不代表 ATR 高的币「更赚」。

⚠️ 追高 ATR 还会撞上这份数据看不见的流动性墙。 现有 11 币全是头部流动性; 高 ATR 通常意味着小市值、盘口更薄,多出来的余量很可能被滑点吃回去。 把在头部币上成立的关系外推到另一个流动性区间,是最容易翻车的那类外推。

现有 11 币的实际情况:BTC ATR 中位 2026 仅 6.5bp、门控刷掉 58.5%、 预算 8.58bp 垫底;TRX 2026 门控后只剩 4.2% 的信号,当前环境基本不能做。

筛选很便宜:拉候选币 1m 数据,只算 ATR 分位数与盘口价差,不必跑策略 就能排掉大半。

⚠️ 但样本外的说服力会被稀释:当前最硬的证据是「8 个币完全没参与调参、 全部为正」。若新币是在同一份历史上筛出来的,它们就不再是样本外。 要保持这个性质,得留一批筛完不看、直接进实盘验证。

3.34 组合最优解:选币的杠杆很小,币数的杠杆在前 6 个

穷举每个 N 的最优子集(1m,门控后,固定日历,只扣手续费不扣滑点):

币数 最优子集夏普 增量 年化R 若信号独立应有 捕获比例
1 9.94 323 9.94 100%
2 13.15 +3.21 611 14.06 94%
4 16.93 +1.61 1174 19.88 85%
6 18.87 +0.78 1672 24.35 77%
8 19.87 +0.38 2188 28.11 71%
11 20.22 +0.02 2690 32.97 61%

三条结论:

  1. 边际收益在 6~8 币后归零。 8→11 只换来 +0.35 夏普(+1.8%), 但年笔数多 500+,成本与运维复杂度是实打实的。
  2. 具体选哪几个几乎不重要。 165 个 8 币组合:最好 19.87ADA/AVAX/ DOGE/ETH/LINK/LTC/SOL/XRP)、最差 17.61、中位 18.66,极差 2.2612%)。 ⚠️ 这一条已被 §3.37 推翻——它忽略了盘口冲击。计入后币间差距是 5 倍, 且排序近乎翻转(AVAX 从必选变成必剔,BTC 反而可用)。选币很重要。
  3. 相关性吃掉近 40% 的分散化收益——捕获比例从 100% 单调降到 61%。 与 3.31 的「92.7% 同向」一致:加币是加机会,不是加分散。

⚠️ 并发保证金不是瓶颈,此前的担心是错的。(早前按事件平均算出 0.92, 高估了——事件在繁忙时段聚集。时间加权才是对的口径。)

时间加权均并发 有仓时间占比 有仓时均并发 p99 最大
全样本 11 币 0.15 12.3% 1.24 2 9
2026 11 币 0.11 9.1% 1.26 2 8

资金 88% 的时间闲置,扩币在保证金维度有大把余地。峰值 9 仍要按 3.31 的同向假设做限额,但那是尾部风控,不是容量约束。

⚠️ 上表夏普只扣手续费、未扣滑点,绝对值虚高(年化 20 不可信), 只能用于相对比较。 真正的约束是实测滑点 vs 预算——见 5.3 与 3.35。 按杠杆排序:滑点是生死(100%)> 币数 1→6(+90%)> 选哪几个(±12%,基本是噪声)

3.36 成本模型的已知缺口:滑点被当成了常数,但它是仓位的函数 ⚠️

全文所有预算数字都假设滑点是固定 bp,与下单规模无关。这是错的 (用户 2026-08-28 指出)。且这个错误不是随机的——它系统性偏袒低 ATR 端。

固定分数下单意味着 名义额 = 风险额 / (2·ATR),即仓位 ∝ 1/ATR 而预算(bp)∝ ATR。两者方向相反:

ATR 桶 bp 中位杠杆 中位名义额(10万本金、每笔冒1% 预算 bp
8-12 5.0x $502,029 13.7
12-16 3.6x $362,362 19.5
16-22 2.7x $269,999 23.1
22-30 2.0x $198,172 29.3
>30 1.3x $129,065 52.1

低 ATR = 单子最大 + 预算最小 + 滑点随单子变大 = 三重挨打。 所以按固定 bp 算出的逐币/分桶预算,系统性低估了低 ATR 端的劣势

ATR 门控因此比原论证更有价值:被刷掉的信号中位杠杆 8.9x、p90 17.6x (保留的是中位 3.2x、p90 5.3x)——门控砍掉的正是最大的单子。 这比「固定成本占比高」是更强的理由。

三条待办(都属于「数据回来前不做、回来后会后悔」):

  1. 影子交易要记录信号时刻的盘口快照(≥10 档),不只是成交价。 有深度就能离线算任意仓位的冲击成本——一次测量回答所有资金量级, 否则换个规模就得重测。若用极小量或 paper 测,得到的只是 价差/2 + 漂移 这个下界,必然乐观。
  2. 资金容量要算出来,不要等实盘暴露。 预算 20bp 蕴含一个资金上限。 中位名义额 $32 万、p90 $53 万,在 ADA/LINK/AVAX 的 1m 永续盘口上不是零头。
  3. maker 腿的仓位问题是成交率,不是冲击。 回测假设 3 ATR 与 8 ATR 的限价单全额成交。$30 万挂单可能只部分成交,而部分成交会改变分批出场 的收益结构(§3.5 的结论建立在全额成交上)。需在影子数据里验证。

3.37 计入盘口冲击后,币种排序几乎翻转 —— §3.34「选哪几个不重要」作废 ⚠️

Bitget USDT 永续实时盘口(2026-08-28 01:30 HKT5 次快照取中位)。 净预算 = 回测预算 − $300k 单边吃单冲击($300k ≈ 10万本金 × 中位杠杆 3.2x):

价差bp ask深度 $300k冲击 回测预算 净预算 冲击占预算
SOL 0.09 $3.3M 2.82 28.3 25.5 10%
DOGE 1.12 $13.5M 4.35 28.5 24.1 15%
ETH 0.04 $19.4M 0.27 20.8 20.5 1%
XRP 0.68 $14.9M 4.82 24.5 19.7 20%
BTC 0.01 $4.5M 0.26 14.6 14.3 2%
LINK 0.84 $2.8M 12.20 26.2 14.0 47%
ADA 4.62 $6.3M 9.70 23.5 13.8 41%
LTC 1.99 $3.2M 11.13 23.6 12.5 47%
AVAX 1.33 $3.0M 23.65 29.0 5.3 82%

§3.34 的「165 个 8 币组合极差仅 12%、选哪几个不重要」是错的——那个结论 完全建立在忽略流动性上。计入冲击后币间差距是 5 倍25.5 vs 5.3)。

排序近乎翻转,根因是 ATR 与流动性负相关,所以按预算(∝ATR)排出的序 恰好是按流动性排的逆序:

  • AVAX 原始预算最高(29.0)、净预算最低(5.3)。它在最优 8 币里入选频率 95%,实际最该剔除。5 次快照 22.3~24.7bp,不是抽样噪声
  • LINK / ADA / LTC(入选频率 95%/95%/70%)净预算全掉到 12~14
  • BTC 此前判为「中性」,实际净预算 14.3,反而优于 LINK/ADA/LTC—— 原始预算最低但冲击几乎为零

这就是 §3.33 定性警告过的「流动性墙」,现已量化,且比预想严重。

真正的结论:可用币种是资金量的函数,不存在固定的最优币表。 按 $100k 名义额(≈$32k 本金)重算,净预算回到 ADA 18.0 / LINK 17.2 / LTC 16.5 / AVAX 11.6——除 AVAX 外全部健康。扩币前先定本金。

当前运行点:本金 < $2k(用户 2026-08-28 确认,目的是先跑通流程)。 在这个规模上 §3.37 的重排序不适用——单笔仅 $6.4k,冲击占预算 18% (连 AVAX 也只有 8%),9 个币全部可用,§3.34 的「选哪几个不重要」重新成立。 分水岭在 **$20k$50k 本金**:以上才需要收缩到 SOL/DOGE/ETH/XRP/BTC (这 5 个在 $2k~$200k 全区间冲击 ≤21%,是与资金量无关的安全核心)。

冲击占预算比例(按本金,杠杆 3.2x):

$2k $10k $20k $50k $100k
BTC / ETH 0% 0% 0% 0% 0~2%
SOL 1% 3% 4% 5% 6%
XRP / DOGE 5~6% 9~10% 12% 15% 16~17%
LINK 4% 11% 16% 31% 46%
LTC 12% 22% 30% 41% 57%
ADA 20% 28% 29% 38% 51%
AVAX 8% 28% 43% 70% 91%

小资金无操作性障碍Bitget 最小下单量在 $300 本金都不卡, 半仓取整误差最差 2.4%(ETH @ $500),其余 <1%。

⚠️ 但 $2k 跑通 ≠ 验证了策略容量。 小资金下有两处系统性偏乐观、且不可外推: (a) 冲击≈0,测出的滑点只剩 价差/2 + 延迟漂移,几乎必然通过 15.19bp, 但不能推出 $50k 也通过;(b) maker 腿成交率也是假的好——$3.2k 挂单几乎 必然全成,$150k 不一定,而 §3.5 分批出场的收益结构全建立在全额成交上。 → 这正是「记录盘口快照」的价值:它是唯一能让小资金数据回答大资金问题的东西。 只记成交价的话,每上一个资金台阶都得重测一遍。

$2k 阶段真正该盯的只有两件:延迟与漂移(与规模无关,结论长期有效)、 中枢阶梯 + ATR 门控必须在线上生效(否则测的是另一批信号,与回测不可比)。

⚠️ 三条保留:(1) 单一时段快照,盘口有日内周期,需跨时段采样; (2) 信号恰在波动放大时触发,那时盘口更薄——上表是乐观下界 (3) 只算了入场 taker 腿,止损/超时同为 taker,maker 腿则是成交率问题。 第 (2) 条意味着这批静态数字不能替代影子数据,只是把「该测什么、该剔谁」 提前定下来了。

3.35 跨 venue:信号身份不迁移,但总体期望迁移(live 前置测量)

回测全部跑在 Binance 数据上,实盘要在 Bitget 成交。 服务器侧的 research/live/venue_parity.py 把这件事量了:

品种 Bitget信号 Binance信号 同根重合
BTC 47 38 42.6%
ETH 39 35 28.2%
SOL 48 29 14.6%

(5m 同向过滤后口径。SOL 差得最多是因为 tick 粗细不同:Bitget 0.001、 Binance 0.01,粗 10 倍会让 close > high[j-1] 大量平局不触发, Bitget 上信号多出 74%。这是系统性差异,不是随机扰动。

signal_sensitivity.py 进一步显示 0.25bp 的数据扰动就能换掉一半信号

aggregate_robustness.py 的结论是:总体期望不塌。 加 0.5 / 1 / 2bp 噪声重跑,毛均收益与 PF 都在原区间内摆动,没有单调恶化。

脆的是信号身份,不是 alpha。 这决定了两件事: 一、滑点不能逐笔对照 Binance 回测,只能对照同一 venue 上的总体毛均收益; 二、影子测量必须跑在生产路径上(Bitget 原生数据 + Hummingbot), 换个运行时测出来的数就不作数。

同窗口 Bitget vs Binance 毛均收益(210 天、TP=3.0 口径): BTC 5.87 vs 6.09、ETH 10.02 vs 12.06、SOL 8.92 vs 9.87bp。 Bitget 一致略低 0.2~2bp,但没有量级差异,总体口径可迁移。

⚠️ 上面那批数字用的是 毛均收益 6.0bp、只有同向过滤、TP=3.0 不能直接当预算用,正确的逐币预算见 lib/shadow_budget.py 与 5.3。

3.38 浅色信号(未过双过滤)在 1m 上不能做——差在毛质量,不在成本(step44)

用户观察「图上很多浅色 b4/s4 的入场价看着也很有优势」。step40 做过同类消融但 只覆盖 15m/30m 且用旧口径(5bp 平摊、1.5/3.0/48),1m 从未验证。

research/step44_filter_ablation_1m.py,8 币 × 30 万根,当前最优 1m 出场 SL2.0 / 3ATR 减半 / runner 8ATR / rstop 留原位 / 48 根),真实费率, ATR ≥ 8bp 门控后共 2302 笔:

口径 笔数 胜率 毛R 净均R 剔10%PF 滑点余量bp
深色(同向 ∧ 阶梯) 955 68.3% 0.933 0.798 2.35 15.07
浅色(任一不过) 1347 44.3% 0.155 0.009 0.74 0.10
— 只过阶梯 445 52.1% 0.419 0.279 1.03 4.18
— 只过同向 265 38.1% 0.029 0.176 0.59 2.15
— 两个都不过 637 41.4% 0.046 0.103 0.62 1.64

关键是「毛R」列——那是扣任何成本之前的数字。 浅色 0.155 vs 深色 0.933 差 6 倍。所以不存在「信号本来不错、被手续费吃掉」这回事:浅色的跟随性 本来就差。浅色扣完手续费只剩 0.10bp,任何滑点都会让它亏;逐币 8 个里 4 个已为负(ETH 1.98 / LTC 2.93 / DOGE 1.05 / XRP 0.14),最好的 ADA 也才 2.41bp。

为什么肉眼看着有优势:(1) 入场价确实是好的,信号标的是真实局部结构; (2) 但价格不跟随,毛R 0.155 覆盖不了 2 ATR 的止损——入场点好 ≠ 价格继续 朝你走;(3) 44.3% 的胜率意味着近一半确实走对,扫图时看到的就是这些, 走错的当时形态一样好看。

⚠️ 新发现:1m 上阶梯过滤远比同向过滤重要,与 30m 相反。 只过阶梯 +4.18bp,只过同向 2.15bp 且毛R 为负;而 30m 上同向单独就能把 PF 从 1.59 提到 1.85(§4 step30)。两个过滤器的相对价值随级别翻转, 不要跨级别套用滤网结论。

3.39 因子化仓位:量因子该做成开关不是权重,前序因子根本不该进仓位(step51)

用户提出把 §3.31 的两个分层结论(有前序 +6bp 余量、低量根 +14bp 余量) 做成仓位/杠杆因子。做了组合层面的评估,结论与分层表给人的印象不一致 两个因子的命运完全相反。

方法上刻意设的三道约束(分层结论转仓位规则最容易翻车的地方):

  1. 阈值取整数、权重取整数比,一个参数都不搜。 vr60 切在 1 / 2 / 4 权重 1.5 / 1.25 / 0.75 / 0.5。观测到的四分位边界在不同时段并不一致 (样本外 0.63/1.26/2.28/5.34,发现期 0.62/1.48/3.11/7.97), 用样本分位数等于在同一批数据上既发现又调参。
  2. 权重归一化到均值 1,各方案投出去的平均资金相同,均R 才可比。
  3. 判据是四项一起看:均R / R夏普 / 最大回撤 / 峰值加权并发。 只看均值必然误判——加权一定抬方差,且 有前序 按定义就发生在别的币 已有仓位时,给它加权就是在敞口最集中的时刻加杠杆。

全样本 3941 笔,假定滑点 5bp/taker 腿:

方案 盈亏平衡滑点 R夏普 最大回撤R 峰值并发 总R/峰值并发
等权(现状) 16.7bp 0.420 17.3 7.00 371.4
仅量因子(加权) 18.2bp 0.442 12.7 7.98 367.4
仅前序因子 17.0bp 0.421 19.2 8.46 312.6
两因子相乘 18.6bp 0.446 14.3 9.48 314.6
硬砍高量档(vr60 ≥ 4 不做) 18.6bp 0.496 11.2 6.00 389.3
硬砍 + 前序权重 19.0bp 0.500 11.0 7.19 332.1

有前序 不能做仓位因子——它的边际收益买不起它带来的集中度。 盈亏平衡滑点只 +0.3bp,但峰值并发 7.00 → 8.46、回撤 17.3 → 19.2 按峰值保证金归一后是净负的(371 → 313)。原因是量纲:+6bp 余量在 5bp 滑点假设下只值约 0.011R,而它 100% 发生在已有并发仓位的时刻。 §3.31 说的「可用于加仓位权重」到此作废——那条余量优势是真的, 但兑现方式不是仓位。(可能的出路是对这批放宽 ATR 门控,即多做几笔而非 每笔做大,那条仍未测。)

⚠️ 本节推荐的开关(vr60 ≥ 4 不做)已被 §3.391 取代。 mom60 ≥ 7 不做 在盈亏平衡滑点、R夏普、回撤、总R、保留笔数五项上全面更优。 本节关于**「开关优于权重」「前序不该进仓位」「优势形态是削尾」**三条方法论 结论仍然成立,只是最佳的那个开关换了个因子。

② 量因子「不做」优于「少做」。 加权版 R夏普 0.442、硬砍版 0.496 回撤 12.7 vs 11.2;峰值并发 7.98 vs 6.00。硬砍付出笔数 −22% 3941 → 3061)、总R 10%,换来回撤 −35% 和并发 −14%。 并发下降这一点单独就值:§3.31 已把峰值敞口列为扩币的前置约束, 砍掉高量档等于同时松开这个约束。

③ 优势的形态是「削尾」不是「抬均值」。 均R 差在各滑点档上几乎恒定 (0.085 → 0.082),但基数在塌,所以相对优势随成本上升而放大: 15bp 处总R/回撤 2.57 → 11.864.6 倍),因为回撤从 150.5 掉到 60.3。 这两个因子买的是尾部风险,不是收益。

⚠️ 可操作口径要用发现期的数,不是全样本。 盈亏平衡滑点样本外 18.2bp、 发现期只有 13.5bp(硬砍后 15.6bp)——差距就是 2026 的 ATR 压缩(§5.3)。 发现期才代表当前波动环境。13.5bp 与 shadow_budget.BUDGET_PORTFOLIO_2026 的 15.19bp 同量级,互为印证。影子测量要对标的是 13.5 / 15.6,不是 18.6。

3.391 开仓前那段:量要小、势要有但不能过头(step53)

用户提出看开仓之前的量与趋势方向。这是第三个位置——step50 管信号根、 step52 管持仓中,这里管入场前。

先纠正一个错的心智模型(我和用户都以为的)B4/S4 不是回抽后进场。 mom10 中位 +3.47 ATR,为负的只占 6%。也就是说信号触发时,价格在前 10 根里已经顺着你的方向走了三个多 ATR,你的 2 ATR 止损是架在一段已经走完 的行情后面。所谓"回抽后转强"里的回抽,幅度远小于它之前那一冲。

这一条也解释了 step50:信号根是突破根,放量 = 追在最后一棒上。

① 入场前的量:单调,越小越好,且独立于信号根的量

vpre10(前 10 根量均值,已 shift(1) 不含信号根) 样本外毛R 样本外余量 发现期毛R 发现期余量
Q1 最低(中位 0.61 1.474 27.25bp 1.074 17.85bp
Q2 1.266 23.45bp 1.184 19.76bp
Q3 1.156 21.37bp 1.033 18.61bp
Q4 最高(中位 2.21 0.573 8.51bp 0.510 6.04bp

vpre30 同形状。vr60 后仍成立:信号根低量层里毛R差 −0.284、 高量层 −0.541,与 vr60 相关只有 +0.301,不是同一件事换个说法。

② 入场前的动量:驼峰形,不是单调

mom60(前 60 根顺向动量,ATR 单位) 样本外毛R 样本外余量 发现期毛R 发现期余量
Q1 最低(中位 0.33 1.252 22.60bp 1.180 19.47bp
Q2(中位 3.14 1.473 28.68bp 1.355 26.26bp
Q3 1.141 20.49bp 0.981 16.23bp
Q4 最高(中位 8.33 0.603 8.65bp 0.284 1.44bp

mom10 同形状(Q2 最好、Q4 最差),样本内外一致。势要有——完全没动过的 Q1 也不如 Q2;但不能过头——Q4 在发现期余量只剩 1.44bp,等于不能做。

⚠️ 驼峰形意味着中位数二分法会把它测没:控制表里 mom10 在"信号根低量"层 的毛R差是 +0.044(看着无效),那是因为二分把 Q1+Q2 和 Q3+Q4 各自平均了。 对非单调因子不要用中位数分层做检验。

③ 逆向进场(真回抽)很差,但只占 6%

笔数 占比 毛R 余量bp
顺向 × 缩量 1851 47% 1.350 24.63
顺向 × 放量 1872 48% 0.855 14.35
逆向 × 缩量 119 3% 0.615 7.81
逆向 × 放量 99 3% 0.362 3.61

mom60≥7 不做 全面优于 §3.39 定的 vr60≥4 不做 —— 换开关

发现期(当前波动环境),阈值取整数不搜参:

方案 保留 盈亏平衡滑点 R夏普 回撤R 总R
等权(现状) 100% 13.5bp 0.325 16.8 596.6
砍 vr60≥4(§3.39 的建议) 69% 15.6bp 0.411 10.8 514.9
砍 mom60≥7 78% 17.5bp 0.476 7.7 657.7
砍 vr60≥4 + mom60≥7 58% 18.3bp 0.515 8.0 527.8
三个都砍(+vpre10≥1.5 42% 20.0bp 0.593 6.5 430.4

砍 mom60≥7 在每一项上都赢过 砍 vr60≥4,还多留 9 个点的笔数。 更要紧的是它总R 比不砍还高657.7 vs 596.6):被砍掉那 22% 的单子期望为负, 砍掉不是花钱买稳健,是纯赚。样本外同向(21.4bp / 0.588 / 1923.6 对照砍 vr60 的 19.8 / 0.529 / 1820.8)。

选哪个方案取决于真实滑点,这是决策表(发现期总R):

真实滑点 0bp 5bp 8bp 10bp 12bp 15bp 18bp 20bp
等权 946 597 387 247 107 102 312 452
砍 mom60≥7 921 658 500 394 289 131 28 133
三个都砍 574 430 344 287 229 143 57 0

5~12bp 区间 砍 mom60≥7 通吃,那正是最可能的落点。只有真实滑点 ≥15bp 才该上"三个都砍",而那时策略本身已经在生死线上。影子测量出数之前不用选, 但要知道选项长这样。

阈值 mom60 ≥ 7vpre10 ≥ 1.5 是贴着 Q4 边界取的整数,不是搜出来的, 但也不是完全无关于数据(我看过分位表才取的整)。真上线前应在更早的 时段上确认阈值附近没有断崖式敏感。

3.392 时段(亚/欧/美)没用,周日有效但已被 mom60 吃掉(step54

用户问哪个时段更容易盈利。答案分两半:时段这个切法本身无效,但换成星期几 就有东西——只是那东西不该做成新过滤。

① 亚/欧/美三段:差异在噪声量级,且美盘两个时期反号

UTC 0/8/16 三等分 笔数 毛R 余量bp 中位ATRbp 样本外毛R 发现期毛R
亚盘 1249 1.127 18.18 12.5 1.153 1.057
欧盘 1414 1.006 18.43 14.1 1.044 0.926
美盘 1278 1.079 18.73 13.6 1.158 0.885

美盘在样本外是最好的一段、在发现期是最差的一段,这是噪声的典型指纹。 段间毛R极差 0.122,置换检验 p = 0.0895——随便把 24 小时切成三份, 有 9% 的概率切出这么大的差。按真实开盘时刻切五段(含欧美重叠单列)结论一样。

⚠️ 这里不是输给了 ATR 混淆。控 ATR 后段间极差 0.101 / 0.108,和无条件的 0.122 几乎一样——时段效应不是 ATR 的代理,它只是本来就小。逐小时表里最差的 20 UTC(0.802)与最好的 22 UTC(1.262)差得很大,但每小时只有 108~275 笔, 是噪声,别照着挑时辰。

② 星期几才有信号,集中在周日

笔数 胜率 毛R PF 余量bp 样本外毛R 发现期毛R
周五 601 74.7% 1.228 4.78 23.44 1.359 0.862
周四 623 73.5% 1.150 4.56 20.64 1.104 1.252
周日 470 66.6% 0.893 2.76 13.08 0.955 0.772
工作日 3133 72.6% 1.095 4.01 19.38 1.151 0.959
周末 808 67.9% 0.963 3.08 14.86 0.983 0.920

置换检验:周末 vs 工作日 p = 0.0246,周日 vs 其余 p = 0.0079。 方向在两个时期一致,10 个币里 7 个周末更差(BTC 最甚 −0.336)。 ⚠️幅度在发现期塌了大半(工作日−周末:样本外 −0.168 → 发现期 −0.039)。

这条在长样本上没复现,而且符号翻转——见 ⑤,按噪声处理。

③ 关键:周末的劣势有一半住在 mom60≥7 那批单子里,step53 已经砍掉了

周末 vs 工作日 周日 vs 其余
过滤前 0.132 0.199
施加 mom60<7 0.058 0.104

注意重叠不在笔数上mom60≥7 在周末占 22.9%、工作日 21.3%,几乎一样。 是伤害重叠——周末真正亏钱的是那些追已走完行情的单子。周末流动性薄, 追高的代价被放大,这跟 §3.391「势不能过头」是同一件事在另一个维度上的投影。

④ 所以不要加这条过滤。决策表(发现期总R):

方案 保留 0bp 5bp 8bp 10bp 12bp 15bp
等权 100% 946 597 387 247 107 102
砍周日 86% 844 543 362 241 120 60
砍周末 78% 747 473 309 200 90 74
砍欧盘 60% 579 363 234 148 61 68
砍 mom60≥7(§3.391 78% 921 658 500 394 289 131
砍 mom60≥7 + 周日 68% 804 574 435 343 251 113

砍 mom60≥7 + 周日 在 0~20bp 每一档都输给 砍 mom60≥7 单用——叠加只是 白丢 10% 的笔数。单用「砍周日」也要到 12bp 以上才赢过等权。

⑤ 长样本复核(用户追问"你用的是长时间周期分析的?"):时段坐实无效, 周末效应没复现且符号翻转

1m 只能追到 18.5 个月 / 3941 笔,而上面的结论是"没效果"——没效果最怕样本 不够。改用 step41 那份 5m/15m/30m2019-09 → 2026-082525 天,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
1m18.5 个月) 0.132 0.0246
5m7 年) +0.014 0.7616
15m7 年) +0.142 0.0710
30m7 年) 0.006 0.9546
合并(7 年) +0.041 0.2784

周日同样翻转:1m 上 −0.199(p=0.0079),合并长样本 +0.033p=0.4774)。

⚠️ 这不是严格的样本外复现——1m 与 5m 的信号是不同的总体,不是同一批交易换个 时间窗。但若"周末流动性薄所以吃亏"是真的市场结构效应,它没有理由只在 1m 上 出现、在 5m 上还反号。结合本步一共跑了 ~35 个分组比较(24 小时 + 两套时段 定义 + 7 个星期 + 周末/周日),冒出一个 p=0.008 恰是多重比较的期望产物。

这一步的价值是排除,而且排除得比第一轮更彻底。 用户问时段,直觉上 「美盘流动性好该更赚」很难自证伪,跑完才知道它连随机切分都跑不赢。 更要紧的是第一轮我把周日效应写成了"统计上真实"——长样本一上就翻了符号。 教训有两条:① 报告"无效"之前先确认样本量撑得起这个"无" ② 在几十个分组里挑出的最显著那个,默认它是噪声,除非它能在另一个总体上 复现。 p 值不做多重比较校正就等于没做检验。

3.393 一类/二类买卖点:引擎实现下全是负的,一类尤其糟(step55)

用户提出把 B4 那套研究思路搬到一二类上,并指定用 5m/15m 测。

先量滞后,不先跑收益——Chan_BSP_TYPE 的枚举注释里写着 B4 存在的全部意义 就是「几何位置同 B3/S3,但不等笔确认」,说明这个项目早就付过等笔确认的学费。

① 滞后:三类完全一样(用户的判断,实测确认)

类型 5m 滞后中位 15m 滞后中位 5m 漂移中位 占 2ATR 止损
B1 8 根 9 根 1.68 ATR 84%
B2 8 根 8 根 2.03 ATR 101%
B3 8 根 9 根 1.95 ATR 98%

三类都卡在同一处:中枢 is_sure + 笔 is_sure + sure_time所以滞后不是区分一二三类的变量,它是 find_all_bsp 这个实现的共同属性。

⚠️ 「漂移为正的占比 100%」是定义决定的,不是发现:笔之所以在那里结束, 正是因为价格从极值反向走了,bi.end_klc 就是极值点。有信息量的是幅度不是符号。

② 收益:全负,一类是最差的一档(5m / 15m5 币,出场用实盘的 2/3/8/2/48

类型 5m 笔数 5m 胜率 5m 毛R 5m PF 5m t值 15m PF 15m t值
B1 623 18.6% 0.592 0.24 17.3 0.21 18.9
S1 644 14.8% 0.675 0.20 22.3 0.23 15.9
B2 293 35.8% 0.104 0.73 1.4 0.85 0.8
S2 288 36.8% 0.115 0.82 1.6 0.75 2.4
B3 2806 33.3% 0.187 0.64 8.0 0.76 5.3
S3 2685 35.4% 0.135 0.70 5.6 0.73 4.8

口径校验通过B3 跑出 PF 0.64/0.76,§4 记的引擎 B3 是 0.66 —— 接线是对的, 所以 B1/B2 的数可以信。

③ 一类为什么烂得这么彻底:它的结构自带反向杠杆

B1 买点的理想入场是那一笔的低点。等到 sure_time 可以动手时,价格已经朝上 跑了 1.68 ATR。于是新入场价往下 2 ATR 的止损,落在比原始低点还低 0.3 ATR 的位置——几乎贴着极值,任何一次回踩都打掉;而 3 ATR 的减半目标从低点算起变成 了 4.7 ATR。胜率 15~21% 完美对应这个几何:它低于随机入场SL2/TP3 下随机 约 40%)。

这和三类的滞后代价不是一回事。 三类是顺势突破,等 8 根是「追高一点」; 一类是逆势抄底,等 8 根是「在反弹了 1.7 ATR 之后才去接刀」——同样的滞后, 在反转型信号上是加倍惩罚

④ 结论与下一步

引擎现成的 B1/B2 不可用,且原因是结构性的不是参数性的,调参救不回来。 B3 当年的解法不是调参,是重新定义成实时判据(B4:收盘突破 zg → 收盘未跌回 → 重新上行,全部当根可判),选样口径随之改变(627 个中枢只认 212 个), 统计性质才翻正。

但这条路未必能照搬到一类:B4 能实时判,是因为「突破 + 回踩不破 + 重新上行」 每一步都能用收盘价当根判定。而一类的核心是背驰,它要求「知道这一笔已经 结束」——那本身就是事后信息。要做实时版,得先找到一个不依赖笔端点的力竭代理。

另有一个来自 §3.391 的先验值得先算:一类按定义就发生在一段已走完的行情 末端,也就是 mom60 最高的那个区间——而那正是我们实测最差的四分位 (Q4 发现期余量只剩 1.44bp)。真要做实时一类,先验就不利。

3.394 实时版一类(fast B1/S1):滞后不是病根,一类没有边(step56)

§3.393 判定引擎 B1/S1 不可用后,用户要求照 B3→B4 的路子做实时版。做了, 没救回来,但这次实验把病因锁死了。

research/lib/fast_bsp1.py 把引擎 B1 的三个条件全换成当根可判的代理:

引擎条件 滞后源 实时代理
中枢已成 zs.is_sure available_ts(与 B4 同口径)
一笔向下离开中枢 笔端点 收盘 < zd
背驰 check_bi_div 笔端点 进入段面积在中枢确认时已是历史;离开段面积从突破根逐根累加
触发 leave_bi.sure_time 主要滞后源 收盘反向越过前一根极值(沿用 B4 的转强判据)

注意一类和三类方向相反:中枢向下突破后 B4 做空,fast B1 是在同一段下跌里 找力竭然后做多。

结果(5 币,5m/15m,出场 2/3/8/2/48

信号 5m 笔数 5m 胜率 5m PF 5m t值 15m PF 15m t值
fastB1 一买 482 22.4% 0.38 9.4 0.37 10.6
fastB1 一卖 528 20.3% 0.36 12.5 0.41 9.6
fastB3 三买(同管线对照) 972 55.0% 1.83 +10.6 1.84 +8.5
fastB3 三卖(同管线对照) 927 54.6% 1.93 +10.5 2.06 +10.7

对照组是这次实验的全部价值所在:同一份数据、同一套出场、同一条管线, B4 跑出 PF 1.832.06 / t +8.5+10.7。所以 fast B1 的负数不是管线接错了。

病根锁定:滞后不是主因。 引擎版 PF 0.22 → 实时版 0.38,确实有改善, 但离 1.0 还差得远。更关键的是滞后分档:

lag(入场根 极值根) 5m 笔数 5m PF
≤1 根(≈买在极值上) 472 0.40
2-3 根 390 0.36
4-6 根 125 0.29

即使入场就在极值那一根,PF 仍只有 0.40。 §3.393 里「等 8 根导致几何劣势」 的解释因此只对了一半:滞后确实在扣分,但把滞后清零也救不活——一类在这个 市场/周期/出场结构下本身就是负边缘的。

背驰强度有单调性但不够:15m 上最强四分位 PF 0.99、余量 0.24bp、t −2.0, 毛收益刚够打平、净收益仍为负;且这是四选一的样本内挑选,不构成可交易的结论。

判定:一类到此为止,不再投入。 这与 §3.4 消融、§3.391 的 mom60 结论 互相印证——这一族信号的 alpha 在顺势延续上,不在反转上。fast_bsp 的文档 头早就写了「B4 不只是 B3 提前几根,两者统计性质符号相反」,一类的实验说明 反过来也成立:把反转信号提前,它还是反转信号。

3.395 一类反手:已被 step59 推翻,不要用本节的 PFstep55/57

本节结论作废。 下面的 PF 2.3~3.0 用 sure_time+1 当入场时点,而 §3.396 的逐根回放证明实盘要等中位 +15 根才知道信号存在(0% 能准时拿到), 按真实首现根入场后 PF 塌到 0.92 / 1.30、t 0.20 / 0.64。 保留本节是为了记录推理链和那个「胜率低于随机 = 信号指反了」的判据, 它本身是对的、也可复用;错的是把 sure_time 当成了可执行时刻。

用户问「是不是一类二类的识别错了」。查下来结论是:代码没写错,但信号该反着用。

先排除掉一个我自己的错误猜测。 check_bi_div 只比 MACD 面积、不检查创新极值, 这是缠论背驰定义(创新极值 力度减弱)丢了一半。看着像致命缺陷,但实测 93.2% 的 B1 / 93.4% 的 S1 离开笔本来就创了新极值,缺口只影响约 7%, 解释不了 PF 0.2。先量再断,别拿理论缺陷当结论。

真正的线索是胜率的方向B1 胜率 18.6%,而 SL2/TP3 下随机入场约 40%。 远低于随机说明样本带信息,只是指反了——真正没用的信号会落在 40% 附近。 于是拿相反方向重跑出场(路径依赖,不能把 g 取负号了事):

反手 5m 胜率 5m PF 5m t值 15m PF 15m t值
B1(反手做空) 64.4% 2.35 +10.4 3.03 +12.6
S1(反手做多) 67.1% 2.75 +12.8 2.63 +9.6
B3/S3(反手) 45~49% 1.14~1.24 +4 1.15~1.20 +4

稳健性(step57)——这是本项目做过的最稳的结果

切法 结论
逐币 5 个币全正。15m PF 2.254.125m 2.312.70
前后半段 15m 2.81 / 2.815m 2.55 / 2.51,几乎不变
逐年 20212026 连续六年全正15m PF 2.572.99
多空 两边都正,排除单边行情
余量 15m 3376bp、5m 1828bp。对比 B4 只有约 3bp

为什么不是 bug 而要反着用

代码是照缠论写的:向下离开中枢 + 背驰 → B1 买。教科书没错,错的是它发信号的 时刻。 信号在 leave_bi.sure_time 发出,中位滞后 8~9 根,此时价格已从低点 反弹了 1.68 ATR(§3.393 表)。引擎想说「抄底」,但它给出的时间戳对应的是 「反弹已走完」。在下跌趋势里于此处做空 —— 那是标准的顺势回调入场

所以这一族信号的几何识别是对的,方向标注按理论也是对的,是滞后把它变成了 相反的交易。它是一个穿着反转外衣的顺势回调信号。

它与 B4 不是一回事:B4 是突破延续(§3.391 实测 mom10 中位 +3.47 ATR, 根本不是回调入场),这个是回调延续。两种入场原型不同,可能互补

止损位置:真问题,但不是主因(step58)

用户提出:B1 做多的止损可能挂在了 B2 低点上方,于是在那次「回踩不破前低」的 正常回抽处被打掉,而不是等趋势真正走完。查下来观察成立且比预估更严重

5m 一类
入场价到结构极值(ATR,用入场根 ATR 归一) 中位 2.90
2ATR 止损在结构位外侧留的余地 中位 0.90(在结构以内
止损落在结构位以内的占比 88.6%

即近九成的一类做多,价格连回踩到前低都不需要就已出局。

修掉之后确实有改善,但救不活。⚠️ 做这个对照时目标必须随止损等比放大 (恒定 1.5R 减半 / 4R 收尾);放宽止损却不放大目标会把盈亏比压到 1 以下, 测出来的「放宽无效」是自证的:

方向 止损 中位宽度 胜率 PF t值
原方向做多 固定 2ATR 2.00 16.7% 0.22 31.0
原方向做多 结构+1.5 4.40 33.1% 0.36 16.6
反手做空 固定 2ATR 2.00 65.7% 2.53 +14.4
反手做空 结构+1.5 4.40 58.2% 2.15 +10.7

结论:趋势确实越过第二类买卖点继续走原方向。 最有说服力的读法是 「结构+1.5」那一档——止损宽达 4.4 ATR,仍有 67% 被打掉,即三分之二的一类 信号会在 48 根内跌破结构低点再多走 1.5 ATR。缠论里「B2 回踩不破前低」这条 在本市场多数时候不成立。

佐证:反手做空在最窄的 2ATR 止损上最好(2.53),放宽反而降到 2.15。 这与顺势回调入场自洽——价格若重新涨过反弹高点,论点当场失效,不该留余地。

仍未验证,落地前必须做完(否则不许上实盘)

  1. 因果性zs.is_sure / bi.sure_time 在全量数据上算出,§5.41 已知中枢 右边缘会重画。必须用增量/流式回放确认信号在当时真的发得出来。 反证据(不能替代验证):同一套机器算出的 B3 是 PF 0.64 的烂数, 若存在通用的未来函数,B3 不该这么难看。
  2. 消融:是不是「反弹就做空」都赚。照 §3.4 对 B4 做过的那样,把背驰条件 拿掉、把中枢换成伪阻力位,看 PF 掉不掉。掉不下来就说明 alpha 在几何和 时点上,与背驰无关,那这个信号就该重新命名和重新设计。
  3. 与 B4 的重叠度与相关性。若只是换名字的 B4,就没有增量价值。

3.396 因果回放:信号存在性是真的,时点是假的(step59)

§3.395 的 PF 太好,先查因果性——增量模块文件头自己写着「最后一笔 is_sure 允许收回」,§5.41 也记了中枢右边缘会重画。

做法init_stream 预热 2 万根,随后逐根 append_bar,每根之后重算 cal_bi_zs_list_pure + find_all_bsp,记录每个信号第一次出现在哪一根; 入场用首现根,而不是事后的 sure_time。信号身份用「类型 + 极值 KLC 时刻」, 不能用 sure_time 当键——它正是会被重画的字段。

必须逐根。分段重建(每 S 根算一次)等于在第 t 根多给了 S 根的信息, 测出来的因果性是假的。

检查 结果
召回(全量信号在回放中出现过的比例) 100%B1 50/50S1 65/65
幻影(回放发过、全量没有的) 0
首现根 全量 sure_time 中位 +15 根P25 +11P75 +22P90 +31
准时拿到的比例 0%
反手 · 5m 全量口径 回放首现口径
B1 PF 2.35 0.92t 0.20,余量 1.37bp
S1 PF 2.75 1.30t 0.64,余量 +4.21bp

结论:信号的存在性是因果的(不重画、不消失),但时点不是。 实盘要晚中位 15 根、5m 上 75 分钟才知道它存在,而那笔交易吃的正是 「反弹已走完」这个窗口,晚 75 分钟就没了。t 值 0.20/0.64 完全不显著。

⚠️ 可复用的教训sure_time 是引擎事后标注的确认时刻,不等于可执行时刻。 任何用它当 entry 的回测都要先过逐根回放。样本 115 笔偏薄,但机制清楚、 点估计从 2.35 塌到 0.92,方向不存在疑义。

3.397 线段顶点当标准答案:识别是对的,但精度和时点都不够(step60)

用户提出用线段终点当趋势反转的标准答案——是未来函数,但用作标签验证 检测器而非用于交易,能把「检测器对不对」和「能不能交易」分开。

对照组是关键:B1 按构造就长在笔的低点上,而笔低点本来就有概率撞上线段底。 所以问的是「在所有同向笔端点里,B1 这个标签把命中率提高了多少倍」。

5m 样本 命中线段顶点 相对笔端点的提升
笔端点(基准) 48229 15.0% 1.00
B1 623 30.3% 2.02×
S1 644 27.2% 1.81×
B3 / S3 2806 0.0% 0.00

15m 同向:B1 28.1%1.81×)、S1 27.3%1.76×)。

各容差档(±0~±5 根)数字完全相同,不是 bug:线段终点本身就是某根笔的终点, 两者天然按笔端点对齐,放宽容差不会多命中。B3/S3 恰好 0% 也是对的—— 三类长在回抽笔的端点上,按定义就在趋势中段,不该命中反转点。这两条互为 标签有效性的旁证。

所以检测器是有信息量的:它把「这个笔低点是真反转」的概率翻了一倍。 但还有两道坎:

5m · 按原方向抄底 笔数 胜率 PF t值
未命中线段顶点 903 8.7% 0.08 42.0
命中线段顶点 364 36.3% 0.70 3.2

15m:未命中 PF 0.08、命中 PF 0.83t 0.36)。

精度只有 30%,而那 70% 的噪声是灾难性的(PF 0.08)。更要命的是:即使用 未来函数把精度提到 100%,也只到 PF 0.70~0.83,仍不赚钱。

原因是 §3.398 的几何:入场价已在结构底上方 2.90 ATR(step58)。 即使你真站在线段底上,从底部上方 2.9 ATR 处用 2 ATR 止损做多,结构本身就是 负期望的。§3.396 的回放还要在此之上再晚 15 根。

一类的完整诊断(三层,逐层否定)

  1. 识别对不对 —— 2× 提升(step60
  2. 精度够不够 —— 不够,30%;且用未来函数选到 100% 也只到 PF 0.83
  3. 时点来不来得及 —— 来不及,全量口径已晚到入场价高出结构底 2.9 ATR, 实盘回放再晚 15 根

判定:一类线到此为止。 病不在识别,在于「等笔确认」这个机制天然把信号 推到了结构失效之后,而这是 find_all_bsp 的固有属性,不是可调的参数。

3.398 极值点的波动率:观察成立,但解释力有限(step61)

用户提出:一二类长在极值点上,那个区域波动天然大,这可能就是确认慢的原因。 拆成三条可证伪的子命题分别测,结论是一条成立、一条只沾边、一条不成立

① 一类确实长在高波动区 —— 成立,且很干净

atr_z = 该点 ATR / 其之前 200 根的中位 ATR(含当根会把要检验的插针算进去)。

5m 样本 atr_z 中位 高于基准占比
笔端点(基准) 48219 1.003 50%
B1 623 1.224 74%
S1 644 1.173 68%
B3 / S3 2806 1.03~1.06 55~56%
B2 / S2 293 0.94~0.97 39~44%

基准恰好落在 50%,说明构造是对的。一类比随机笔端点显著偏高。

⚠️ 但二类是反过来的B2/S2 的 atr_z 中位 < 1,只有约四成高于基准 —— 二类长在低波动区。这符合结构:二类是首轮反转冲动之后的回抽,那时波动已 平复。所以「一二类都在极值点」这个说法对一类成立、对二类不成立, 两者是镜像而非同类。

② 波动大 → 确认慢 —— 只沾边,不是主因

5m · atr_z 四分位 atr_z 中位 滞后中位 滞后均值
Q1 低 0.85 8.0 9.3
Q2 1.07 7.0 8.8
Q3 1.34 8.0 9.6
Q4 高 1.80 9.0 11.3

corr(atr_z, lag_bars) = +0.10(15m 亦为 +0.107)。方向对,但只解释约 1% 的 方差,滞后中位几乎不随波动变化。滞后是结构性的——笔要等分型形成再确认, 这个 8~9 根跟波动率基本无关(§3.393 已测得三类买卖点滞后完全一致)。

③ 入场后波动率回落 → 目标够不着 —— 回落属实,但不是亏损的机制

atr_fwd = 入场后 48 根平均 ATR / 入场时 ATR:一类 5m 中位 0.89669% 回落), 三类 0.945~0.957。即一类的 3/8 ATR 目标按一个虚高的 ATR 定,绝对价格上约高估 10%。回落是真的。

但它不是死因

5m 走到 3ATR 减仓 止损 超时 止盈
一类 9.4% 81.3% 17.9% 0.8%
三类 30.7%

九成的一类根本走不到第一个目标,八成直接止损出场。 若死因是「目标够不着」, 超时占比该很高;实际超时只有 17.9%。所以一类不是「走不动」,是入场后立刻 朝反方向走

按 atr_z 分档看表现也印证:PF 在 0.17~0.25 之间基本持平,高波动组并不更差 也不更好 —— 波动率不是区分变量。

小结:极值点高波动这个观察是对的,但它既没造成滞后(结构性的),也没造成 亏损(死于立即反向而非目标够不着)。它与 §3.397 的结论一致:一类的入场价已在 结构底上方 2.9 ATR,那个位置本身就是负期望的。

3.399 一类线收尾:过滤器符号随入场时点翻转,判定为拟合(step62/56)

用户指出:很多一二类实际在趋势中途被识别而非末期;若真在末期,即使有延迟 也该走出行情。step60 的数据支持这个判断——命中线段顶点的 30% 是 PF 0.70~0.83 没命中的 70% 是 PF 0.08,亏损几乎全部来自误识别在趋势中途的那批。

step62:找到了区分变量,识别精度接近翻倍

ext_run(极值越过中枢边界几个 ATR)单调有效,5m:

ext_run 档 命中线段顶点 PF
Q1 最短 12.0% 0.12
Q4 最延伸 43.8% 0.46

最佳组合 ext_run≥P75 且 div≥中位:命中率 47.9%、PF 0.54 (基准 28.7% / 0.22)。识别确实可以优化,且幅度不小。

三个附带结论:

  • 背驰越强反而越差div Q1(最强)命中 17.0% / PF 0.13Q4(最弱) 37.5% / 0.28。这是对 check_bi_div 这个 MACD 面积判据的直接证伪。
  • 趋势级数无区分力:连续同向中枢数 ≤1/2/3/≥4 的命中率 28.5/30.6/28.6/25.5%,基本持平。
  • 「趋势 vs 盘整」前提引擎已隐含强制(纠正我先前的猜测):B1 要求 enter_bi.dir == leave_bi.dir == DOWN,中枢向下进、向下出本身就定义了它嵌在 下跌趋势里,实测该条件在 2504 笔上恒为 True,过滤器无从添加。 zs_count 也不可用——它是全局中枢序号(310、585)而非趋势内序号。

step56 复测:把过滤器接到低滞后版上,符号翻转

step56 的实时版把滞后压到 ≤1 根但无质量过滤(PF 0.40),step62 有过滤但滞后 未解(PF 0.54)。两者各解决一半,合起来是唯一同时处理两个约束的路径。结果:

5m · 延伸度分档 滞后版(step62 低滞后版(step56
Q1 最短 0.12 0.58
Q4 最延伸 0.46 0.33

叠加后 PF 从 0.37 掉到 0.30~0.33比不过滤更差div 同样翻转:滞后版里 背驰最弱的最好,低滞后版里背驰最强的最好。

这个符号翻转是判定依据,不是需要再调的参数。 同一批信号、同一个特征, 换个入场时点最优方向就反过来,说明这些「过滤效果」是入场时点的交互产物, 不是信号的稳定属性。继续在上面挑阈值就是拟合噪声。

一类线全部尝试汇总(六次独立进攻,全部止步于 1.0 以下)

尝试 最好 PF 出处
引擎原生 0.20~0.24 step55
反手 2.35~3.03 → 0.92/1.30 因果回放后 step57 / step59
实时重写(fast_bsp1 0.36~0.41 step56
结构止损(目标等比放大) 0.36 step58
线段顶点选样(用未来函数 0.70~0.83 step60
质量过滤(ext_run + div 0.54 step62
低滞后 + 质量过滤 0.33 step56

注意第五行:即使用未来函数把选样做到完美,也只到 0.83。

判定:一类线关闭。 病根是 §3.397 的几何——入场价已在结构底上方 2.9 ATR, 实盘回放还要再晚 15 根(§3.396),而这来自「等笔确认」这个机制本身, 不是可调参数。识别可以优化,但识别从来不是瓶颈。

3.3991 二类:不是继承了一类的错,是信息为零(step64)

用户提的悖论:二类按定义是「一买后回调、再继续趋势」,一类既已证否,二类凭什么好?

代码上悖论成立——find_all_bsp 里 B2 被 B1 门控(if first_bsp_bi_div)。但当时 有个反驳值得测:B2 比 B1 多要求价格确实反弹了、且回踩守住了 B1 低点, 这两条是「那个底是真的」的事后确认,而 §3.397 的诊断恰恰是一类缺这个确认。 若成立,B2 就是 B1 里被验证过的子集,是好事而非坏事。

测下来是坏消息,且机制与用户说的不同。

⚠️ 先记一个我用错的口径:报表里 B2/S2「命中线段顶点 0.0%」(276~293 笔一个 没中)是定义决定的,不是发现。B2 按定义是反弹后的更高低点,线段顶点在 B1 那个极值上,两者不可能重合。这个指标对自称在极值的一类有效,对二类无效。 若日后要给二类找标准答案,该问的是「B2 之后 B1 低点是否再未被破」,不是顶点重合。

两组有效结论:

一、二类的几何是所有信号里最差的

入场到结构止损位 2ATR 止损落在结构内侧
B1 2.90 ATR 88.6%
B2 4.87 ATR 99~100%

二类的天然止损位是 B1 的低点(回踩守住的就是那点)。但反弹 + 回踩之后,入场价 离那个低点已有 4.87 ATR。二类没有可用的止损位:挂 2 ATR 是纯任意止损, 挂到结构位则单笔风险近 5 ATR。step58 在一类上试过放宽到结构位,PF 仅 0.22→0.36; 二类的缺口比一类大 68%,没有理由更好。

二、二类两个方向都没有边缘——这是它和一类的本质区别

5m/15m 原方向 PF / t 反手 PF / t
B1 0.21~0.24 / 17 ~ 19 2.35~3.03 / +10 ~ +13
S1 0.20~0.23 / 16 ~ 22 2.63~2.75 / +9.6 ~ +12.8
B2 0.73~0.85 / 0.79 ~ 1.42 1.09~1.10 / +1.67 ~ +1.70
S2 0.75~0.82 / 1.55 ~ 2.40 0.85~1.13 / +0.19 ~ +1.36

一类 t = −17~−22 是强烈指反:它有信息,只是滞后把「反转信号」变成了 「反弹追单」(反手曾看似 PF 3.0,但 §3.396 已证那是 sure_time 后视产物)。 二类两边 t 都贴着零,原方向 −0.8、反手 +1.75m 反手 S2 甚至 0.85。 没有可提取的东西,连反手都没有。

其余画像与 §3.393 一致:二类 atr_z 中位 0.94~0.97(低波动,与一类的 1.22 相反), 滞后 8 根(与一类持平,§3.393 已记「三类滞后无差别」)。

判定:二类关闭,一二类线整体收尾。 一类是信号指反(有信息、方向错、 错在滞后),二类是信号消失——在一类之上又等两笔,把仅剩的方向性磨掉, 同时把止损位推远到 4.87 ATR。用户的悖论方向对,但不是「继承错误」, 是「多等的那两笔把信息也等没了」。

3.3992 一类线重开:病根是选样×止损的交互,不是没机会(step65/58/66

用户问「那如果修改 B1/B2 的识别规则呢」。这个问题推翻了 §3.399 的关闭结论 下面三步是重开的依据。

step65:先量机会本身装不装得下确认成本(不经过检测器,直接取 seg_list

级别 线段中位幅度 扣 2.9 ATR 确认成本后 剩余 > 2ATR 止损 剩余/止损
5m 11.4 ATR 8.5 93% 4.26x
15m 10.9 8.0 93% 3.99
1h 11.5 8.6 95% 4.30
4h 12.4 9.5 96% 4.74

五币四级别一致(10.5~13.7)。滞后不是瓶颈——这与我原先的预期相反。 但它与 §3.397 直接矛盾(空间在,却拿不到),矛盾的解答就是下面这条。

step58 复测:先排除一个伪解释。 首轮结构止损用了 r_scale=True 3.9 ATR 的止损把 runner 目标推到 15.6 ATR,比 11.4 ATR 的整段行情还长。 改成绝对 3/8 ATR 目标重跑,PF 仍是 0.36(与 r_scale 版完全相同)。 我预判的这个修正不成立,首轮结论正确只是理由错了。

step66:把两个杠杆同时拧(三者首次组合),天花板一次性打开

5m 固定 2ATR 结构+1.0
落在真线段端点(28.7% PF 0.70 / 胜率 36% PF 2.29 / 胜率 63%
没落在(71.3% 0.08 0.14

15m:真底那批 0.83 → 4.11,胜率 44% → 70%。

这是交互效应,不是叠加——前三次进攻各自只动了一半,所以全部失败:

只做完美选样(step60 只放宽止损(step58 两个一起(step66
0.70 / 0.83 0.36 2.29 / 4.11

MFE/MAE 给出机制:真底那批逆向行程中位 2.24 ATR5m/ 2.0815m 即 2 ATR 止损打掉了 51~58% 的好单;而非真底那批逆向行程中位 4.76/4.93, 放宽只是亏更多。固定 2 ATR 同时做错两件事:杀掉对的单,又留不住错的单。

⚠️ 这个 2.29/4.11 里有两个未来函数,不是策略,是上界: (a) 选样用了线段端点;(b) 入场仍在 sure_time,而 §3.396 证明实盘还要再晚 15 根。 它证明的是失败原因可修(选样精度 + 止损位),而非这个级别没得做

由此产生的两个待跑实验:

  1. 实时过滤器 + 结构止损 → 见 §3.3993,兑现不了,但换来一个确切门槛
  2. 超时从 48 根放宽(仍未跑)。线段中位时长 113 根,48 根超时在行情走完 42% 时就平仓;真底那批 MFE 中位仅 2.37 ATR,可能是被截断的(而非行情本身小)

3.3993 一类线的门槛量化:全局只有一个变量,精度要 67~73%(step67

把 §3.3992 的天花板换成实时可算ext_run 选样,配结构止损:

5m 15m
全体无过滤 0.34 0.32
ext_run ≥ P75(实时) 0.51 0.48
ext_run≥P75 且 div≥中位 0.60 0.46
★ 真线段端点(未来函数) 2.29 4.11

兑现不了。 但数字对不上——Q4 的真端点浓度已达 44%(基线 28.7%), 若真端点值 2.29,44% 浓度不该只有 0.51。拆开看:

ext_run 档 真端点组 PF (5m / 15m) 非真端点组 PF (5m / 15m)
Q1 最短 2.53 / 2.61 0.18 / 0.11
Q4 最延伸 2.22 / 6.10 0.16 / 0.12

这张表是本节的结论ext_run 在真端点内部毫无反向选样(5m 持平、 15m 单调递增到 6.10),在非真端点内部也毫无区分力(恒在 0.11~0.18)。 全局只有「是不是真端点」这一个变量在起作用,其余特征都是它的噪声代理。

这同时修正了 §3.399 的判定:当时把 ext_run 的符号翻转判为拟合。 现在看它不是拟合——它确实提纯(28.7% → 44%),只是提纯幅度远远不够。

于是 PF 退化成两组按精度 p 的混合,可解出门槛:

实时精度 28.7%(当前) 44%(ext_run) 60% 70% 100%(上界)
PF (5m) 0.34 0.50 0.73 0.93 2.29
PF (15m) 0.33 0.51 0.81 1.10 4.11

盈亏平衡精度:5m 需 72.6%15m 需 67.1%。 当前 28.7%ext_run 做到 44%。

判定:一类线的问题已完全定性,但门槛极高。 要把「这是不是真线段底」的实时 判准精度做到 ~70%(现在 28.7%,最好的特征到 44%),本质上是要求实时抄底摸顶的 准确率达到七成。这是可以尝试的 ML 问题(标签、特征、评估口径本节都已给全), 但先验上很难,且 70% 只是毛平衡,还要再扣 §3.396 的 15 根因果滞后。

这解释了为什么 B4 能做而一类不能B4 是突破后的延续信号, 不需要判断反转;一类的全部难度集中在「这是不是那个底」这一个二分类上。

3.3994 🚨 B4 因果回放:时点干净,但实盘做的不是回测那批单(step63/68)

这条影响正在跑的实盘,优先级高于本文档其余全部内容。

好消息:B4 的时点完全干净,一类那个坑它没有

B1(§3.396 B4
召回 100% 100%
准时率(首现==entry_idx 0% 100%
迟到中位 +15 根 0 根

坏消息:实时回放会多产出一批全量口径里不存在的信号,且它们显著亏钱

实盘口径(2001 根滚动窗口、每 500 根 init_stream 重建、只做当根收盘, 逐行对齐 shadow_signal.py)重放 5 币 × 20000 根:

过滤 留下 额外占比 全部 PF 额外 PF 回测口径 PF
无过滤 789 75% 0.64 0.46 1.37
仅同向 402 77% 0.65 0.35 2.65
仅阶梯 341 68% 0.71 0.31 2.14
仅 ATR 门控 721 76% 0.64 0.46 1.35
三道全开 195 74% 0.73 0.26 4.21

三道滤网挡不住这批信号。 它们把成交量砍掉 75%(789 → 195),但额外信号占比 从 75% 只降到 74%——按同样比例刷掉好的和坏的。实盘口径拆开:

分组 笔数 胜率 PF 余量bp t值
回测里也有的 51 74.5% 4.21 +30.15 +5.90
回测里没有的 144 22.9% 0.26 14.25 6.21
实盘实际会做的 195 36.4% 0.73 4.65 0.59

结论:回测报的 4.21 是拿不到的。 那 51 笔只有事后用全量历史重算才能识别; 实盘在当下拿到 195 个信号,没有任何办法分辨哪 51 个是真的。机制是重画—— 实时算出的中枢,数据变多后被修正掉,信号随之消失。

这与 §3.396 是同一类错误的两种表现:一类错在时点(信号存在但晚 15 根), B4 错在存在性(信号当根就有,但其中 74% 事后会消失)。

顺带闭掉一条挂了很久的待办:窗口长度不是问题。 2001 根滚动窗口与 2 万→4 万根增长窗口跑出完全相同的 789/197/592,中枢是局部结构,截断无影响。 §5.41 那条「9.0% 中枢消失是不是窗口左边界效应」可以判为

⚠️ 两点限定

  • 本轮测的是 5m/30m,实盘跑的是 1m。机制相同但数字必须单独验, 这是下一步第一件事
  • 同向过滤器被我开了未来函数的后门(大级别分型时间线用全量历史算), 真实盘的 HTF 同样会重画,只会更差不会更好

这不否定 B4 的 alpha——回测口径那 51 笔 PF 4.21、t 5.90 是真实的,说明 「真中枢上的 B4」确实赚钱。问题是实时分不出真假中枢。可能的方向(均未测): 要求中枢的构成笔 is_sure(用滞后换稳定性)、或等 N 根看信号是否仍然存在。

3.4 alpha 的来源(step32 消融)

逐条拆掉 fast_bsp3 的条件后发现:alpha 完全来自缠论中枢的上下文定位, 不是「回抽结束、收盘转强」那个触发动作本身。 触发条件只负责压低滞后。

这个结论回答了用户当时的问题(「如果有这个,那就可以去判断任何笔的端点了」): 不能。脱离中枢上下文,那个触发条件没有预测力。

3.5 出场:TP=3.0 把右尾截早了(step41

起因是用户看图指出「止盈没做好」。查下来确实如此。

先量 MFE(每笔在被止损打掉之前最远走到几个 ATR):

分组 级别 笔数 中位 MFE ≥3ATR ≥5ATR ≥8ATR
样本内 15m/30m/5m 2309 3.66 / 4.30 / 4.27 55~62% 41~45% 23~28%
样本外 15m/30m/5m 5859 4.08 / 3.80 / 4.30 57~61% 42~45% 25~28%

中位数就已经高于 TP=3,样本内外一致。抬高 TP 的样本外结果:

出场 胜率 均收益 中位 PF t值 剔10%PF 均持仓
tp3(现用) 62.6% +0.559% +0.588% 2.71 +28.31 1.64 11.2
tp4 58.7% +0.692% +0.579% 2.95 +29.24 1.71 15.3
tp5 56.5% +0.783% +0.485% 3.12 +29.36 1.75 18.8
tp6 55.3% +0.860% +0.369% 3.28 +29.17 1.77 21.7
tp8 54.1% +0.983% +0.284% 3.56 +28.27 1.78 25.7
  • 8 个样本外币逐个看,均收益与 PF 全部提升2020~2026 七年 PF 也全部提升
  • 剔掉最好 10% 后 PF 仍从 1.64 升到 1.75 → 不是几笔暴利撑起来的
  • t 值在 tp5 见顶(+29.36)后走平,tp6/tp8 靠的是越来越薄的右尾
  • 基线复现校验:step41 的 tp3 = 5859 笔 / PF 2.71 / t +28.31 / 剔10% 1.64 对上 §2.2 的 2.73 / +28.50 / 1.66,差在千分位(同根内止损与新高并存时保守 假定止损先到),说明对比是在正确基线上做的

代价不是零:胜率 62.6%→56.5%,中位 +0.588%→+0.485%(过半单子变差, 输在「摸到 3ATR 没走到 5ATR 又反手止损」那批),平均持仓 11.2→18.8 根, §3.3 的并发数据需重算。心理上也更难拿。

分批离场更优(用户提的方案,改一处后成立)

用户方案:到 3 ATR 平一半 + 止损移到开仓价,剩下跑到大目标。 前两步对,「止损移到开仓价」是错的。 用户随后要求把剩余半仓的止损位 也扫一遍(0 / 0.5 / 1 / 1.5 / 2 ATR),结果严格单调,三组初始 SL 全一致

样本外 5859 笔,初始 SL1.5、分批→8 ATR、48 根:

剩余半仓止损位 净均收益 中位 PF t值 剔10%PF
保本损(0 +0.611% +0.420% 2.81 +25.66 1.50
留损 0.5 ATR +0.688% +0.455% 3.03 +27.65 1.65
留损 1.0 ATR +0.732% +0.475% 3.17 +28.64 1.74
留损 1.5 ATR(不动) +0.754% +0.498% 3.23 +29.25 1.79
留损 2.0 ATR(放宽) +0.762% +0.510% 3.25 +29.48 1.81

没有中间最优点,越松越好,但增量在「不动」处饱和 保本→0.5 加 0.077%0.5→1 加 0.044%1→1.5 加 0.022%1.5→2 只加 0.008%。 所以止损保持原位即可,放得比原止损更宽是拿实打实的风险换千分之一的收益

机理与移动止损失败同源(§4):回抽到成本价是突破后的正常结构,不是信号失效。 信号已用「摸到 3 ATR」自证,此时收紧止损等于用最坏价格淘汰掉最好的单子。

胜率与整仓 TP3 完全相同是结构决定的:摸到 3 ATR 的单子在分批下必然是赢家 (半仓 +3 ATR,剩余半仓最坏 1.5 ATR,净 +0.75 ATR)。这正是分批相对整仓 高 TP 的价值——同一批单子在整仓 TP5 下会变成 −1.5 ATR 的亏损。

初始 SL 扫描:必须用 R 倍数口径,否则会把仓位差异算成策略优势

用户要求扫 1 / 1.5 / 2 ATR 初始止损。百分比收益会误导:SL 越宽每笔风险越大, 固定风险仓位下仓位越小,raw % 里 SL2 看着比 SL1.5 好 68%,其中大半是仓位效应。

样本外,分批→8 ATR、留损=初始 SL、48 根,§2.3 的 1%风险 + 20倍上限 + 复利:

配置 均R R夏普 最差1%R 平均杠杆 最大回撤(样本外/内) Sharpe(外/内)
现用 SL1.5 整仓TP3 +0.722 0.494 1.55 1.97x 12.1% / 11.9% 14.79 / 8.33
SL1.0 分批→8 +1.023 0.381 1.93 2.70x 16.0% / 14.7% 11.36 / 6.72
SL1.5 分批→8 +1.023 0.530 1.55 1.97x 13.5% / 9.4% 15.79 / 9.30
SL2.0 分批→8 +0.943 0.638 1.37 1.53x 13.1% / 6.4% 19.00 / 11.35
  • SL=1.0 明确最差:均R 与 SL1.5 打平,但 R夏普 只有 0.381、回撤最大、 最差单笔 −1.93R。止损太紧被噪声打掉,和 §3.2「滞后是第一驱动」是一类问题
  • SL=1.5 期望值最高(均R 1.023),SL=2.0 风险调整最好 R夏普 0.638、回撤 6.4%、Sharpe 11.35,样本内外一致)
  • SL2 只让出 8% 的单位风险期望,换来 20% 更高的 R夏普和更好的最差单笔。 纠正一次误判:修正仓位效应后 SL=2.0 仍然占优,不是纯粹的仓位错觉
  • 按剔10%PF 排全网格,前 14 名全是 SL=2 的分批配置, 第一名 SL2 分批→8ATR 留损2 48根:剔10%PF 2.26(现用 1.59)、 净 +0.920%、PF 3.84、滑点余量 61.79bp(现用 40.05bp
  • 该配置样本外 8/8 币、7/7 年对现用全面提升,无例外

上表的年化数字是 §2.3 的口径 A(复利+杠杆),且把 8 个币当一个账户串起来算, 严重虚高,故意不记录。只有回撤、Sharpe、R 这些比值可以横向比。

换成实际费率(2/0.8bp)后:几乎没变

step41 首轮跑的是错误的 3/1bp(见 §1.3),已用实际费率重算分析段 (feather 存的是毛收益+出场原因,不必重跑模拟):

口径 平均费 净均收益 余量bp 剔10%PF 均R
样本外 现用 SL1.5/TP3/48 3.00→2.00bp 0.579→0.589% 41.34→42.05 2.01→2.05 0.790→0.811
样本外 最优 SL2 分批→8 留损2/48 4.45→3.01bp 0.941→0.955% 62.17→63.13 2.69→2.75 0.975→0.998
样本内 最优 SL2 分批→8 留损2/48 4.43→2.99bp 0.866→0.881% 57.15→58.10 2.91→2.98 0.960→0.984

结论一个都没变,量级也没变(余量动了 2%)。原因还是那条: 成本固定在 bp、目标随 ATR 缩放,所以费率只对 1m 有杠杆—— 同一次改动在 1m 上把均R 抬了 8%,在这里只有 2%。

ATR 门控在这三条腿上是惰性的

1m 上有效的 ATR ≥ 8bp 门控(见 5.3),搬到这里几乎不触发:

级别 ATR中位 <8bp 占比 门控后保留 均R 变化
5m 33.6bp 2.60% 97.4% 1.007 → 1.006
15m 60.2bp 0.16% 99.8% 0.995 → 0.992
30m 82.5bp 0.00% 100% 0.947 → 0.947

无害也无用,所以可以当全局规则统一写进执行层,不必按级别分叉: ATR ≥ 5 + 1.1 × taker费(bp),当前费率下即 ≥ 8bp。 它只在 1m 上真正起作用(那里 21.5% 的信号在阈值以下)。


4. 已验证无效 / 不要重做的方向

方向 结论 出处
动态止盈(小级别三买后等大级别三买再调止盈) 无效。持仓期太短(8~13 根),大级别确认来得太罕见 step27
移动止损(1.5 ATR 跟踪距离) 明显劣于固定 TP:样本外 PF 2.32、剔10%PF 0.94TP=3 是 2.71/1.64)。突破后的正常回抽就能把它洗出去,和 §3.2「滞后是第一驱动」同源 step41
分批后收紧剩余半仓的止损(保本损及一切更紧的位置) 直觉上该做,数据上是负的。止损位 0/0.5/1/1.5/2 ATR 严格单调,越紧越差,三组初始 SL 全一致:保本损比不动少赚 0.14%/笔,剔10%PF 从 1.79 塌到 1.50。与移动止损同源——回抽到成本价是正常结构,不是信号失效。分批要做,止损保持原位 step41 §3.5
初始止损收到 1.0 ATR 5m/15m/30m 上均R 与 1.5 打平但 R夏普 只有 0.3811.5 是 0.530)、回撤 16.0%、最差单笔 1.93R。1m 上更极端:剔10%PF 0.78~0.99、中位收益 0.122%、回撤 25.5%。1 ATR 就是噪声宽度 step41/42
同一中枢重复入场(二次、三次) 质量骤降,只做首次 step25
缠论引擎原生 find_all_bsp 的 B3/S3 统计上呈逆势、显著亏损:胜率 27.4%(低于 SL1.5/TP3.0 的随机基准 33%)、PF 0.66、t 18.76。不是滞后造成的——同一组过滤器把 B4 从 1.59 提到 2.26,对它无效(0.66→0.71),且入场后移 1~4 根只是平滑衰减。它几乎不筛(627 个中枢发 625 个信号),把「价格早已离开、再没回来」的历史区间也当信号发出来。B4/S4 因此单独立类,不是它的提前版 step30/31
刷交易额换 VIP 费率 成本收益不划算,见 5.3。但前提已变:该结论算于「原始 taker 6bp、全 taker、TP=3.0、无门控」,四个前提现在全不成立(实际 2/0.8bp、混合费率、分批出场、有 ATR 门控)。已在返 50% 的档位上,继续压缩的空间本就有限,但若要重估需重跑,不要直接引用旧结论 step23
按 ATR 从大到小选币 / 追高 ATR 时刻 门控之上 ATR 高不加分。币内严格单调递减ATR 最低 20% 分位净均R 1.040,最高 20% 只有 0.878。跨币看似正相关(r=+0.684)但剔除 BTC 后掉到 +0.469,其余 9 币极差仅 0.089。ATR 唯一真正给的是 bp 余量(机械关系)。且追高 ATR 会撞上流动性墙——现有 11 币全是头部流动性,外推到小市值币时多出的余量会被滑点吃回去。ATR 是及格线不是排序键 §3.33
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.617vr60≥3/ 0.858(≥5/ 1.009(≥8),阈值越高越接近基线,最优点是「永不触发」。触发的那批若不平,止盈率 45.7%、止损率 16.6%(全体基线 30.1% / 33.1%),放量根标记的是最好的单子不是最差的,平掉每笔让出 +0.484R。幸存者偏差已控(按持仓 ≥K 根分层 5/5 同向)。同一事件入场为负、持仓为正——入场时你是买方,持仓时资金是来接你货的 step52 §3.31
按时段交易(亚/欧/美) 噪声,已在 7 年长样本上坐实1m 段间毛R极差 0.122、p=0.0895 且美盘两期反号;5m/15m/30m2019-09→2026-088168 笔)p = 0.62 / 0.67 / 0.31,合并 0.64。不是 ATR 混淆——控 ATR 后极差 0.101/0.108,与无条件的 0.122 一样,它本来就小 step54 §3.392
砍周日/周末 1m 上显著但没复现,符号还翻了1m 周末 0.132p=0.0246)、周日 0.199p=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 + 周日 在 020bp 每一档都输给 mom60≥7 单用 step54 §3.392
线段(Chan_XD)做大级别 滞后太大,且中枢极少 早期,用户也这么说

5. 实盘落地的现状与关键约束

5.1 交易所:这是当前最大的未决项 ⚠️

用户实际用 Bitget手续费.xlsx 在项目根目录):

VIP maker taker 升级门槛(月交易额)
1 0.020% 0.060% 0
2 0.016% 0.040% $3M
3 0.014% 0.0375% $20M

返还比例:手动 60%、API 50%

框架支持情况(已查证,2026-08):

框架 Bitget 永续 说明
freqtrade(本地已装 2025.4-dev 源码里搜不到一处 bitgetSUPPORTED_EXCHANGES = binance/bingx/bitmart/bybit/gate/htx/hyperliquid/kraken/okx
NautilusTrader nautilus-bitget 是 0.0.0 空壳无 API;官方适配器列表(2026-06-30)无 Bitget。Bitget 只出现在第三方 Tardis 历史数据里
Hummingbot bitget_perpetual v2.0 连接器,2026 年 Bitget 官方合作。支持单向/对冲、限价/市价,有 Perp Candles Feed

用户最后问的就是「还有没有其他框架支持 Bitget」,答案是 Hummingbot—— 这个问题还没得到他的回应,需要先确认交易所再定框架。

其他信息:Hummingbot V2 的 PositionExecutor 结构恰好匹配我们的 「入场 + 止损 + 止盈 + 超时」,架构上契合。用户的费率表里还有一列空着的 HL Hyperliquid),而 Hyperliquid 在 freqtrade 和 Nautilus 都是原生支持的。

5.2 网络:Bitget 必须走代理 ⚠️

直连  失败 NetworkError: bitget GET https://api.bitget.com/api/v2/spot/public/coins
代理  OK 2.39s  (http://127.0.0.1:7897)

盘口实测(BTC/USDT:USDT 永续):bid 79492.7 / ask 79492.8 价差仅 0.01bp100 档深度。即时价差成本可忽略。

但代理会把延迟从几百毫秒放大到秒级,而 1m 那条腿的滑点预算只有 3.9bp。 实盘这条腿最终必须落到境外 VPS,否则测出来的滑点是代理的账,不是策略的账。

5.3 1m 那条腿的经济性(用户的核心问题)

用户原话:「1m 测的是返佣后是否能够不亏钱」,配合「一边刷交易额,一边走大点周期」。

1m 同向信号实测:3578 笔 / 2.28 年 / 3 币 = 524 笔/年/币, 毛均收益 +0.0991%,胜率 54.2%,平均持仓仅 8.3 分钟。

按 Bitget 真实费率算滑点预算:

⚠️ 下表的费率档位是错的:它假设原始 taker 0.12%、返 50% 得 0.060% 双边。 实际是原始 taker 0.040% / maker 0.016%,返 50% 后 taker 2.0bp / maker 0.8bp (见 §1.3)。整张表连同下面那张「四条腿对比」都只保留跨级别的相对关系 绝对数字全部作废。

档位 双边费率 PF=1 滑点上限 t>2 实用上限
VIP1 taker + API 返50% 0.060% 3.9bp ~2.5bp
VIP1 taker + 手动返60% 0.048% 5.1bp ~3.8bp
VIP2 taker + API 返50% 0.040% 5.9bp ~4.5bp
VIP1 maker + API 返50% 0.020% 7.9bp ~6.5bp

四条腿的滑点余量对比VIP1 taker + API 返50%,即双边费率 0.060%):

级别 笔数 毛均收益 平均持仓 滑点余量
1m 3578 +0.0991% 8.3 根 3.91bp
5m 1984 +0.3253% 9.7 根 26.53bp
15m 689 +0.4436% 12.1 根 38.36bp
30m 340 +0.9504% 11.7 根 89.04bp

1m 和 30m 的余量差 23 倍。

重要判断:1m 若失败,绝不能拿它去否定 5m/30m。 三条腿的成本敏感度不在一个量级上。

⚠️ 上面的 3.91bp 已被 step42 推翻:那是 30m 的参数套在 1m 上量出来的

用户指出:SL1.5/TP3.0/MAXB48 是在 5m/15m/30m 上定的,1m 不该混用。 成本固定 5bp,而目标随 ATR 缩放1m 的 3 ATR 只有 0.39%、30m 是 1.87% 成本占比差 5 倍,最优 TP 不可能相同。查证后确实如此,而且原因比成本更根本:

级别 MFE 中位 ≥6 ATR ≥10 ATR
1m 5.16 ATR 46.1% 28.6%
5m 4.29 37.8% 18.6%
15m 3.98 34.7% 17.0%
30m 3.94 36.6% 18.7%

1m 以 ATR 计的右尾是其他级别的两倍。 机理:1m 的 ATR 量的是分钟级噪声, 但信号一旦成立抓到的是几小时级别的趋势,所以「行程 / ATR」比值天然更大; 30m 的 ATR 本身已经吃进了一部分趋势。所以 TP=3 ATR 在 1m 上是个远比在 30m 上 更紧的目标——这不是调参问题,是量纲问题

(MFE 本身也随初始止损变化,止损越松活得越久、右尾越长: 1m 上 SL1.0 中位 2.37 ATR、SL1.5 是 5.16、SL2.0 是 6.73。 所以 TP 和 SL 必须一起定,不能固定一个扫另一个。)

1m 全网格重测(step4211 币 × 7 年,25476 笔)

⚠️ 本小节的表用的是旧费率 3/1bp(跑的时候费率档位写错了,见 §1.3)。 实际是 2/0.8bp,所以下面所有净收益、余量、均R 都偏保守。 用实际费率重算的版本在再下一小节,决策请用那一版

扫描空间:SL ∈ {1.0, 1.5, 2.0} × TP ∈ {2,3,4,5,6,8,10,12} × MAXB ∈ {48, 96} × 分批(3 ATR 减半 → 剩余目标 {5,6,8,不设} × 留损 {0,0.5,1,1.5,2})。

结论与 5m/15m/30m 同向,但幅度更大,且 1m 上没有取舍——最优解在每个指标上都赢。

样本外(8 个未调参币,17734 笔):

口径 胜率 毛bp 净均收益 中位 PF 剔10%PF 滑点余量 均R R夏普 最大回撤 均持仓
现用 SL1.5 / 整仓TP3 / 48根 60.8% 20.27 +0.141% +0.169% 2.09 1.24 11.06bp +0.434 0.274 14.7% 9.7
SL1 分批→8ATR 留损1 / 48根 45.9% 20.29 +0.133% 0.122% 2.01 0.96 9.07bp +0.649 0.225 25.5% 17.5
SL1.5 分批→8ATR 留损1.5 / 48根 58.9% 28.60 +0.219% +0.132% 2.70 1.49 15.12bp +0.781 0.376 14.1% 23.7
SL2 分批→8ATR 留损2 / 48根 67.6% 34.90 +0.284% +0.233% 3.41 2.01 20.12bp +0.792 0.500 12.6% 28.4

(滑点余量口径已改:分子是毛收益减实际手续费,分母是 taker 名义额, 即每条 taker 腿能承受多少滑点。旧表按双边固定 6bp 扣、不除 taker 腿, 所以数字偏大——上一版写的 14.27bp 就是旧口径,与 11.06bp 是同一件事的两种算法。)

  • 滑点余量 11.06 → 20.12bp,接近翻倍;均 R +0.434 → +0.792+82%
  • 8/8 样本外币、7/7 年份全部提升,无例外。最弱的 2026 年: 现用余量 4.69bp / 剔10%PF 0.92(已跌破 1),最优 9.84bp / 1.45
  • 样本内同向:净 +0.100% → +0.221%,剔10%PF 1.07 → 1.72,回撤 19.7% → 10.2%
  • MAX_BARS=48 不用改:1m 上 96 根在同配置下一致略差(剔10%PF 2.01 → 1.95), 这点与 5m/15m/30m 不同,是 1m 唯一沿用原参数的地方
  • 纯整仓高 TP(TP8/TP10)毛收益更高(4447bp)但胜率跌到 5960%、 中位收益反而更低;分批版 PF 与剔10%PF 更好,是更稳的那一侧

1m 上 SL=1.0 是废的(比其他级别更明确):剔10%PF 只有 0.78~0.99 中位收益 −0.122%(一半以上的交易是亏的),最差 1% 到 −3.69R,回撤 25.5%。 1 ATR 在 1m 上就是噪声宽度,止损放在噪声里必然被反复扫。

减仓后剩余半仓的止损位——三组初始 SL 下都是同一条单调曲线:

初始SL 保本损(0) 留损0.5 留损1 留损1.5 留损2
SL1.0 剔10%PF 0.78 0.91 0.96 0.98 0.99
SL1.5 剔10%PF 1.23 1.38 1.45 1.49 1.50
SL2.0 剔10%PF 1.68 1.86 1.95 2.00 2.01

越松越好,到「不动」(= 初始 SL)为止基本饱和,再放宽只有 +0.01 的边际。 保本损在 SL2 上直接砍掉 0.33 的剔10%PF,是全表最差的一档。 结论与 5m/15m/30m 完全一致:减仓后不要动止损

逐年余量在衰减——那是波动率压缩,不是 alpha 衰减

用户看到余量逐年递减后提的假设:「是不是跟波动率有关,2026 是熊市、2025 是牛市」。 查证成立,而且相关性高到接近恒等式。

余量bp当年 ATR 中位数 的跨年相关系数 r = +0.989n=7)。

ATR中位 毛bp 毛/ATR 余量bp(旧费率) 均R
2020 16.3 39.8 2.44 23.98 0.939
2021 牛 22.1 58.7 2.65 36.49 1.031
2022 15.4 36.5 2.37 21.30 0.876
2023 9.8 24.9 2.53 13.88 0.846
2024 11.7 31.3 2.67 18.07 0.877
2025 11.6 27.8 2.40 15.76 0.883
2026 熊 8.8 19.8 2.26 10.28 0.713

关键是「毛/ATR」列:2.26~2.67,七年无趋势。 信号质量以 ATR 计几乎没衰减。 衰减的是 ATR 本身——2021 的 22.1bp 压到 2026 的 8.8bp,掉了 60%。 余量是 bp 口径,自然跟着掉。这就是 §5.3 的论证从跨级别搬到跨时间: 成本固定在 bp,目标随 ATR 缩放。低波动年份等于「1m 变得更像 1m」。

保留意见:2026 的毛/ATR 2.26 与余量/ATR 1.17 都是七年最低, 可能还有一点真衰减,但 8 个月 1682 笔分不出是噪声还是趋势。

ATR 门控:低 ATR 的信号毛质量不差,是被固定成本吃掉的

按信号根 ATR 分桶看 R(零成本口径),结论与直觉相反:

ATR桶 毛R 净R @2/0.8bp 净R @6/2bp
<6bp 1.156 0.025
6-8 1.160 0.527
8-10 1.227 0.736
12-15 1.203 0.870
>30 0.940 0.829

低 ATR 桶的毛 R 不但不差,还是最高的一批1.16 vs 高 ATR 桶的 0.94)。 断崖只在扣费之后出现。所以「低波动时段信号变差」是错的说法, 正确说法是固定成本在低波动时占比过大

推论:门控阈值是费率的函数,不是市场常数。 换 VIP 档 / 换返佣 / 换交易所都要重算,不能抄:

单边 taker 最优 ATR 阈值
0(假想) 5bp
1.5bp 8bp
3bp 9bp
6bp 12bp

大致 阈值 ≈ 5 + 1.1 × taker费(bp),亚线性。

实际费率(2/0.8bp)下的最终口径——决策用这一版

口径 笔数 平均费 净bp 余量bp PF 剔10%PF 均R R夏普
现用 SL1.5/TP3/48 17734 2.00bp 18.3 13.06 2.73 1.96 0.702 0.482
最优 SL2 分批→8 留损2/48 17734 2.99bp 31.9 21.45 4.18 2.85 0.958 0.639
最优 + ATR≥8bp 门控 13929 3.00bp 36.5 25.39 4.23 2.98 0.987 0.662

逐年(最优 + 8bp 门控,样本外):

ATR中位 无门控余量 门控余量 保留% 笔/周 剔10%PF 均R
2021 牛 22.1 37.47 37.80 98.6% 55.5 3.41 1.064
2023 9.8 14.84 19.45 63.5% 28.4 2.84 0.982
2025 11.6 16.73 20.79 71.2% 45.5 3.11 1.007
2026 熊 8.8 11.21 15.19 55.4% 27.5 2.51 0.824
  • 门控是自适应的:高波动年份几乎不触发(2021 保留 98.6%), 低波动年份才发力(2026 保留 55.4%、余量 +36%)。不是拟合出来的常数
  • 费率降低后门控的边际价值也降低:旧费率下门控带来 +5.6% 均R, 实际费率下只有 +3.0%。阈值曲线在 512bp 之间很平(均R 0.9720.987), 8bp 是峰值但不敏感,不必纠结精确值
  • 影子交易判据:14~15bp(2026 最差年份口径)。近两年合计是 19.17bp, 全样本外 25.39bp。用 2026 那个数做及格线,别用平均值

与旧 3.91bp 的差距来源未完全对齐:旧数字来自 step23(2.28 年数据、 3578 笔、毛均收益 0.0991%),本步是 7 年、25476 笔、毛均收益 0.2027%, 且滤网口径可能不同(§5.3 原文写的是「1m 同向信号」,未提阶梯), 费率口径也已改成混合 maker/taker。在重新对齐之前,两个数字不要混用。

风险点:入场条件恰好是「收盘突破转强」,那一刻价格正朝我们的方向跑, 所以延迟造成的是系统性的追高/追低,不会正负抵消。这正是 「回测漂亮、实盘歇菜」最常见的具体机制。

5.4 实时计算窗口(step39,已跑完)

research/step39_pit_1m.py(新写,已跑完:3 币 × 每币 60 信号 = 180 笔抽检):

窗口(根) 覆盖天数 同根命中 ±3根内 完全消失 同向过滤也成立 假阳性 耗时中位 耗时P95
2000 1.4 100.0% 100.0% 0.0% 100.0% 0.0% 0.20s 0.22s
4000 2.8 100.0% 100.0% 0.0% 100.0% 0.0% 0.40s 0.42s
8000 5.6 100.0% 100.0% 0.0% 100.0% 0.0% 0.81s 0.84s
16000 11.1 100.0% 100.0% 0.0% 100.0% 0.0% 1.68s 1.81s

分币种(最大窗口):BTC/ETH/SOL 各 60 笔全部 100% 命中,零偏移。

结论:1m 在 2000 根窗口(1.4 天)就已完全饱和,单次计算 0.20s,假阳性 0%。 比 15m/30m 的 step38 结果还干净(那里有 0.7% 假阳性)。耗时对窗口严格线性 (约 0.105ms/根),所以没有任何理由带更长的历史。

⚠️ 「假阳性 0%」是 n=180 的结果,不足以排除 0.5% 量级的重画 2026-08-28 更正)。若真实率为 0.5%,180 笔里期望仅出现 0.9 次—— 0% 与 0.5% 在该样本量下无法区分

实测反例:web 端 BTC 1m(10 万根窗口),同一份数据分别截到本地 22:25 与 02:08 两个视角,212 个信号中 1 个消失08-27 22:19 的 B4,约 0.47%), 与 15m/30m 的 0.7% 同量级。用户在界面上先看到、后消失,即此现象。

缓解事实:消失的那个 htf_agree=False, ladder_ok=False,是浅色 b4 本就不交易。 真正要回答的是「双过滤通过的深色信号会不会重画」—— step39 报的「同向过滤也成立 100%」同样基于 n=180,同样不足以排除低频事件。

⚠️ step39 的「假阳性」测法本身是无效的:它从全序列随机抽非信号点,看时点 重建会不会凭空冒信号。1m 信号密度约 474 根 1 个,180 个随机点期望只撞上 0.38 个——测出 0% 几乎不含信息量。重画只发生在「差一点就成型」的结构附近, 不在随机点上。

5.41 重画的根因:available_ts 取的是中枢结束而非形成 ⚠️⚠️

代码审计(比逐根跑数据快得多):find_fast_bsp3 给定 zones 后严格因果 (只用 close[j] / high[j-1]),加未来K线动不了已成型的入场点。 重画只可能来自 zones 表被修订。

zones_from_zs_list 里:

last_bi = bis[-1]                      # ← 中枢的最后一笔
avail = ts_of.get(sure_key) or ...     # available_ts = 它的确认时刻

用户 2026-08-28 指出的缠论定义问题:中枢形成只需三笔有重叠区间; 结束才需要「离开且不返回的笔」确认。判信号只需形成,不必等结束。 而 bis[-1] 只有中枢走完才知道是哪一笔——取的是结束时刻

实测(BTC 1m,30 万根,1651 个中枢):

中枢笔数 占比
恰好 3 笔 25.5%
>3 笔 74.5%(中位 5、均值 8.1、最大 89

「最后一笔确认」比「第三笔确认」晚:中位 62 分钟、p75 142、p90 247、最大 1739。 1m 上 62 分钟就是 62 根 K 线。

三个后果:

  1. 这就是重画源。 中枢每吸收一笔,bis[-1] 就后移一次。300 时点抽样、 3284 个「当时已生效」的中枢:完全一致 84.4%,确认时刻被改 6.5% (推后 198 个 vs 提前 17 个,中位 +100 分钟、p90 +413,中枢消失 9.0%, 阶梯翻转 2.6%。用户看到的 08-27 22:19 B4 消失即此。
  2. 它解释了 docstring 里那个 34%。 「627 个中枢只认 212 个(34%),被拒的 多数是『中枢确认时价格早已离开、此后再没回来』」——「价格早已离开」不是 市场现象,是这个定义造出来的:中枢正是被离开笔终结的,所以扫描起点天然 落在离开之后;代码又要求 was_inside,于是只能等价格再次回到中枢再突破 一次。那 66% 多半不是没机会,是第一次离开时还没开始看。
  3. 方向对回测有利、对实盘不利。 全量的 available_ts 系统性更晚 → 回测扫描起点比实盘晚 → 回测偏保守,不是被高估;但实盘会产出更多、更早 的信号,这部分质量不在回测统计里。

关键性质:bis[2] 是不变量,bis[-1] 不是。 用户 2026-08-28 补充的 判断——「只有没确认的才会重画,确认的都不会」——与实测一致:6.5% 的改动 不是已确认的笔被推翻,而是中枢又吸收了新笔、bis[-1] 变成了另一根笔。 原来那根笔本身没变。而中枢一旦由三笔构成,第三笔就固定,不随延伸改变。

A/B 实测(BTC 1m300 时点,3284 个已生效中枢):

口径 完全一致 确认时刻被改 中枢消失 改动中位
现行 bis[-1](中枢结束) 84.4% 6.5% 9.0% +100 分
改用 bis[2](中枢形成) 89.7% 1.2% 9.0% +16 分

bis[2] 把该重画源压到 1/5。 两种口径全量中枢数都是 1651——纯粹改变 「何时可用」,不增删中枢。

改成「第三笔确认」的预期收益:消除该重画源(第三笔确认后不再变)、 符合缠论定义、滞后大幅下降(§3.2 已证滞后是收益第一驱动)。

⚠️ 剩下 9.0% 的「中枢消失」两种口径完全相同,是另一个源,与笔确认无关 且在改用 bis[2] 后成为主要重画来源。最可能是窗口左边界效应:2000 根窗口 截断笔结构,造出全量视角里不存在的中枢。

⚠️⚠️ 由此牵出一个此前未记录的口径差:回测用全量历史建中枢,实盘用 2000 根 窗口。 若那 9% 确由左边界造成,则它不是重画,而是回测与实盘看到的中枢集合 本就不同——比重画更根本。待查。

⚠️ 但不要直接改。 这会换掉整个信号总体,本文档所有数字都绑定当前实现。 反向风险明确:中枢形成即可用意味着会去做「仍在形成中」的中枢的突破, 价格可能再回来——信号变多但质量可能变差。必须 A/B 实测。

A/B 已跑完(step472026-08-28):bis[2] 作废,不要再试。 详见 §5.42。它把重画压到 1/5 的同时,把毛 R 从 0.933 打到 −0.000—— alpha 归零,不是成本问题。 下面这段「待办」保留仅作推理记录。

(已完成)available_ts = bis[2].sure_time vs bis[-1].sure_time 的完整 A/B (信号数、滞后、PF、剔10%PF、滑点预算),以及深色信号的 大样本重画审计(脚本已写:research/step45_repaint.py)。

对实盘的影响有限但真实:实盘会比回测多开极少量的仓,这部分质量不在回测统计里。 但出场(止损/止盈/超时)不依赖信号是否仍在图上,不会出现「信号消失、仓位卡住」。

这一步顺带解决了一个更重要的问题1m 的回测口径本身是可信的, is_sure 回撤对 1m 同样没有影响。1m 现在唯一的风险就剩执行成本。

⚠️ 延迟预算的分解(这直接决定 1m 生死):

环节 实测 说明
信号计算 0.20s 2000 根窗口,可控
走代理访问 Bitget 约 2.4s 单次 REST 往返(含建连),这才是瓶颈

计算只占延迟的一小部分,网络是主要来源。所以影子交易器必须: 用 WebSocket 订阅而非轮询 REST 拉 K 线,并尽快把实盘迁到境外 VPS。 否则测到的滑点全是代理的账。

5.42 A/B 判决:bis[2] 把 alpha 打成零,重画是必付代价(step47)

8 个样本外币 × 30 万根 1m,两组共用同一个 TF_DF,只切 available_ts 的取法。 实盘口径(深色 ∧ ATR≥8bp):

bis[-1] 现行 bis[2] 中枢成立
笔数 955 989
滞后 2.16 2.01
胜率 68.3% 40.2%
毛 R 0.933 0.000
净均 R 0.798 0.147
R 夏普 0.532 0.107
PF 3.22 0.80
剔10% PF 2.35 0.55
滑点余量 15.07bp 2.20bp

判决依据是「毛 R 0.933 → −0.000」这一行:扣任何费用之前 edge 就没了, 所以不是成本、不是门控、不是出场参数的问题,是信号本身不再有预测力。 逐币 8/8 全部变差,只有 BTC 勉强为正(0.617 → 0.116)。

为什么bis[2] 只要三笔重叠就认为中枢可用,此时中枢尚未发育, 支撑/压力还没立住。bis[-1] 那段「等待」不是可以优化掉的延迟——它就是 alpha 本身

由此得到一条一般性结论,值得推广到别的"降延迟"想法上:

右边缘重画不是 bug,是这个信号质量的必付代价。任何以「让信号更早确定」 为目标的改动,都要先测毛 R,不能只测重画率或滞后。 §5.41 只测了稳定性就给出「唯一能同时改善收益与稳定性」的判断,是过早的。

顺带交叉验证:现行口径本次算出滑点余量 15.07bp,与 §5.3 里 2026 组合口径的 15.19bp 基本吻合——两条独立路径得到同一个数,该预算值可信。

脚本 research/step47_avail_bi_ab.py;开关在 chanlun/analysis/fast_bsp.pyAVAIL_BI_INDEX(环境变量 CHAN_AVAIL_BI),默认 1,保持现行口径

5.5 增量更新已验证:一致且快 12 倍(2026-08-28

pipeline/builders/incremental.py 此前一直标着「需重新验证」。已验完。

一致性:400 根、每 20 根与全量重算对拍一次(共 20 次), 笔数 / 中枢 zg·zd / 信号 entry_idx 全部相同,无漂移。

耗时(本机 arm64 单线程,1m 2000 根窗口):

环节 增量 全量重算
TF_DF / append_bar 14.0ms 192.5ms
中枢 + find_fast_bsp3 7.6ms 10.1ms
1m 侧合计 21.7ms 202.6ms 9.3x
5m 侧(append_bar 7.1 + 分型线 2.9 10.0ms/次 84.4ms 每 5 根一次 → 摊 2.0ms
完整一根 ≈24ms 286ms ≈12x

⚠️ 必须定期重建窗口,否则增量的优势会被自己吃掉。 append_bar 不是 O(1)——pd.concatadd_indicatorscal_bi_list 三处 仍是全量 O(n),而 dataframe 只增不减:

1200 根后行数 中位 前100根 → 后100根
不裁剪 3200 16.3ms 13.9 → 19.4+40%
每 500 根重建 2199 14.4ms 14.2 → 14.0(持平)

IncrementalBuilderMixin 没有裁剪接口,做法是每约 500 根用最近 2000 根 重新 init_stream。单次约 192ms,摊到每根 0.4ms,可忽略。

下一个数量级的线索(用户 2026-08-28 指出)add_indicators 算了很多本策略用不到的指标。它在 append_bar 里是每根全表重算的, 所以浪费不是一次性的,而是每分钟一次、且随窗口长度线性放大。 改它会动到 dataframe 的列集合,web 与回测都依赖,需整体评估。

后续实测(见 §5.6推翻了这条线索的份量add_indicators 只占全量 构建的 1.3%,talib 是向量化 C,便宜。真正的浪费在 ChanKLU.set_indicatorsChanKLC.cal_all_ema_status。方向对(确实有大量无用计算),位置错了。

这是延迟这块唯一有数量级收益的方向find_fast_bsp3 本身只占 0.75ms (全链路的 0.3%),优化信号代码毫无意义;95% 的时间花在 TF_DF 从头重建 2000 根上,而实盘每分钟只新增 1 根——重算了 1999 根没变的东西

服务器侧实测 1m 那条腿 695ms(本机同口径 202.6ms,慢 3.4x)。若两条腿 同比例,那边完整链路约 980ms,已超 §6 定的 800ms lag 告警线,且尚未计 任何网络耗时。改用增量后应降至约 82ms。⚠️ 该外推假设两条腿慢的比例一致, 服务器侧应直接实测一次完整链路。

§5.6 优化后本机复测(同口径 2001 根、单线程、从头算一遍)

口径 优化前 现在 full 现在 lean
1m 腿 202.6ms 71.8ms 50.0ms
完整链路(两腿+信号+过滤) 286ms 178.4ms 120.5ms
增量 append_bar 24ms/根 13.6ms/根

按 3.4x 换算到服务器:完整链路 980ms → 约 611ms(full) / 413ms(lean) 即使完全不上增量也已落回 800ms 告警线以内;上增量约 46ms。 ⚠️ 但 3.4x 是在优化前的代码上量的。优化把工作从逐行 Python 对象操作挪到 numpy 批量操作,若服务器慢在 CPU 主频则比值成立,若慢在内存带宽则未必。 服务器侧必须直接实测,不要只信这个换算。

为什么这一步必要:step38 只验证了 15m/30m,从没验证 1m。而窗口 4000 根 对 15m 是 41 天、对 1m 只有 2.8 天,中枢的左边界效应完全不是一个量级。 窗口同时牵动两头:太短则中枢被截断信号不符,太长则算得慢延迟大滑点高。

5.6 引擎提速 2.6~3.6x,逐位一致(2026-08-28

先建了 step46_engine_parity.py 作为安全网:对 5 个用例(BTC 1m/5m、ETH 5m、 SOL 15m、XRP 30m,各 2 万根)固化 klc/笔/中枢/信号/被消费列的哈希。 没有它不要碰引擎——行为变化是静默的,不报错、不崩,只是信号悄悄换一批, 而 HANDOFF 全部数字都绑在当前实现上。

三处改动,每处都过了对拍:

改动 原因 效果
cal_kl_data 预取 ndarray,不再 df.iloc[i] 每根新建 40 列 Series + 在其上做几十次逐键查找 这一处就占构建的 96%2 万根 1946ms → 824ms
ChanKLC.cal_all_ema_status 改惰性 每 KLC 立即重算,占 25%,而全仓无任何读取方 调用 14322 → 2248 次
get_klc_list 里的 ema_up_list/ema_down_list 累加一整轮后直接丢弃,纯死代码

另外加了 TF_DF(..., lean=True):只构建到中枢,跳过线段/走势中枢/整套 MACD 状态机(这些只服务 bsp_list 和 web 展示,笔与中枢不依赖)。 已验证 lean 与 full 的笔/中枢/信号在 5 个用例上完全一致。

结果(2 万根 5m):full 1946 → 754ms2.6x),lean → 543ms3.6x。 增量路径在两种模式下都仍与全量逐位一致;web API 全字段正常(full 模式一字未动)。

验证做了四层,每改一处都重跑:

  1. 对拍基线(上表所列全部哈希项),full 模式三处改动后全部一致
  2. lean ≡ full:笔/中枢/信号在 5 个用例上完全相同
  3. 增量路径init_stream + append_bar 追加 150~200 根 vs 全量重建, lean/full 两种模式都逐位一致
  4. web 冒烟:真实 HTTP 请求,bsp_list 168 / seg_list 177 / zs_list 17 / klc_trend 齐全

大样本对拍(20 万根 × 5 用例):用 git stash 切回改动前的原始代码存基线, 再切回优化版对拍,逐位一致。这是真正的改前/改后比对,不是自己跟自己比。 同一批工作量 99.9s → 43.3sfull 模式 2.3x,与 2 万根时的 2.6x 一致, 说明提速不随规模衰减。复现:

git stash push -- chanlun/
python step46_engine_parity.py --save  --rows 200000 --out step46_baseline_big.json
git stash pop
python step46_engine_parity.py --check --rows 200000 --out step46_baseline_big.json

关键认识订正:

  • 缩放是线性的,不是 O(n²)。中途一度量到"数据 6 倍、耗时 44 倍",是我自己 开的 tracemalloc 污染了计时。干净重测每翻倍 ×2.06~2.2016 万根 lean 4.2s。

  • add_indicators 只占 1.3%,删无用指标在这里几乎省不到时间。 它有 11 个列(bbup365/bblow30/bbp302 等)Python 与前端都无人读取, 但它们不进 KLU,唯一成本是 web 响应体积(约占 45 列中的 11 列)。

  • 实盘延迟已不是瓶颈:append_bar 约 32ms/根。 继续优化只对研究吞吐有意义。

    「对 800ms 告警线有 25 倍余量」这个说法要小心,两处口径不对:单币的 append_bar 不是信号总延迟(compute() 全程 108mschan 构建只占约 22ms),而多币是同一秒一起收盘、要串行清空的(十币 247ms)。另外 800ms 哨兵测的是数据到达(本地接收 − K线收盘,实测 268~898ms), 计算是叠加在它之上,不共享那条预算。见 §5.6。

剩余热点(lean、8 万根口径):cal_trendset_indicators_from 各约 0.36~0.59s。 它们带序列状态(last_trend + 近 5 根窗口),向量化风险高,收益约 20%,暂不做。

更正(2026-08-28:原先此处写「cal_trend 不能跳过——bi.py:221klc.trend,笔的计算依赖它」。这条不成立。 bi.py:221cal_trend 自己的循环里,读的是它自身的序列状态(前几根已处理 KLC 的 trend), 不是 cal_bi_list 的依赖。

实测定论:init_stream/append_bar 从不调 cal_trend(它只在 get_klc_list 里),所以增量追加出来的 klc 其 trend 恒为 UNKNOWN 而批量构建的有值。verify_incr_parity.py 三币 1,800 根对拍两者逐字段 相同。所以 cal_bi_list 不依赖 klc.trendcal_trend 对「bi → 中枢 → fast_bsp」这条链是可跳的。

这处偏差值得记:它是读代码读出来的(把一个函数的内部自引用误当成外部 依赖),而对拍一次就定论了。同类判断优先用对拍。

5.7 增量在影子路径上的落地(2026-08-28)

shadow_signal.compute 已改为按 (symbol, timeframe) 缓存流式对象。

前提必须先验。 init_stream/append_bar 没有 trimdataframepd.concat 无界增长,所以增量必然让窗口每根 +1,只能周期性重建拉回,两次 重建之间窗口是 [W, W+500] 而非恒定 W。若 compute() 输出随窗口长度变, 增量就等于静默换掉一批信号。verify_window_sens.py 三币 75 个信号窗口、 +200/+500/+1000 三档逐字段一致,前提成立。注意 §5.4 说的是「命中率在 2000 根饱和」——饱和不等于不变,那是两回事。

重建不要用 init_stream 它逐行 dataframe.iloc[idx],正是提速刚修掉 的反模式:2001 根要 238.5ms,批量 TF_DF(df, lean=True) 只 74.3ms,慢 3.2 倍。第一版用它重建,十币启动时各来一次,清空反而从 560ms 涨到 1686ms。 append_bar 能接在批量构建的对象上,_ensure_stream_state 会补出 _klc_feed_last_klu

实测(2001 根窗口): append_bar 21.8ms vs 批量 lean 重建 77.7ms = 3.56x。拆解 = add_indicators 全表 7.5ms34%,为加一根重算 2001 行)+ cal_bi_list 整表重扫 11.1ms51%+ concat 1.4ms。这两项都在引擎侧,是 下一步提速的着力点。

十币 / 2 核的效果: 清空 560→247ms,排队 92→10ms,纯计算 219→108ms 内存 597→598MiB(20 条缓存流的开销在噪声里)。

瓶颈已经换位置了: inner_ms 108ms 里 chan 构建只占约 22ms,其余 86ms 是 build_htf_zones / find_fast_bsp3 / attach_htf_context

⚠️ 上面这段是错的,2026-08-28 撤回,见 §5.72。 那个 86ms 不是测出来的, 是减出来的:22ms 是孤立环境下 1m 腿的 append_bar,108ms 是跑着的十币采集器 里的 inner_ms。一个无争抢一个有争抢,还漏了 5m 腿,这个减法不成立。 实测信号链合计只有 16~21ms,build_htf_zones 是其中最大的一项(13ms), find_fast_bsp3 / attach 合计不到 2%。

5.71 第二轮引擎优化(2026-08-28,服务端反馈驱动)

承上——§5.7 末尾点的那两个引擎侧热点(add_indicators 全表重算 34%、 cal_bi_list 整表重扫 51%)。逐个查下来,四处都是"算了没人要的东西", 不是算法本身慢

改动 性质
cal_trend 挂到 lean 下 见上面那条更正——它不是笔的依赖。web 走非 lean,klc_trend 图层不受影响
check_fx_pattern 删掉拼完就丢的字符串 它把 klu.to_string() 拼成 p 只为一行注释掉的 print。2000 根上近 3 万次 f-string + 6 万次 enum 格式化,在 cal_bi_list 内层。klu.pattern 只被 cal_klu_pattern 自己的双K/三K 判定读,不出模块、不进 web,故整个调用 lean 下也跳
ChanBI.add_klc 去二次方 去重原本线性扫 klc_list,且每加一根就把整笔所有 KLU 的 macdhist 重累一遍 → 往一笔加 k 根是 O(k²)。改下标集合 + macd_hist/macd_div 惰性求值。这两个值只有背驰判定(bsp.py)读,lean 下 bsp 根本不算
add_indicators 批量挂列 2001 行上 TA 计算合计只有 2.5ms,而 30 多次 df['x']= 要 3.6ms——开销大头是 BlockManager 逐列插入,不是计算。改为一次 concat。cal_volume_ratio 里为算一列 rolling 而 dataframe.copy() 整张 40 列表,一并去掉

实测(本机,2001 根窗口)。注意这组数和 §5.7 的 21.8ms 不同机——本机基线 就是 13.9ms,服务端约慢 1.4~1.6 倍,别把两边的绝对值直接比:

改前 改后
append_bar 13.9ms 6.6ms
rebuild_bi_zs 8.7ms 2.8ms
add_indicators 4.4ms 3.5ms
TF_DF lean 49.8ms 32.9ms
TF_DF full 72.7ms 64.9ms

对拍git worktree 检出改动前的提交,同一份 BTC 1m 4000 根, lean/full 两模式 × klc/klu/bi/zs/seg/bsp/指标列/列序,38 项指纹):

  • full 模式 19 项全部一致 → web 那条路一个字节没动。
  • lean 模式差 2 项,且正是设计要它差的两项klc.trend(跳了 cal_trend,现恒为 UNKNOWN)与 klu.pattern(跳了 cal_klu_pattern)。
  • lean 下的 bi/zs/seg/bsp/dataframe 全部一致 —— 这就是"这两个字段没人读"那句断言的实测证据:把它们打空,下游一位不变。

⚠️ 别把这写成"完全一致"。有两项按设计就该变,写成全等会掩盖掉真正要担保的 那件事:变的只有这两个已确认无人消费的字段。 full 模式的 bsp_listmacd_hist 的唯一消费者,它没变才说明惰性求值是对的。

剩下没做的:add_indicators 仍是全表重算(为加一根算 2001 行)。 EMA/MACD/ATR 是递推的、BB/SMA/量比是窗口的,理论上都能 O(1) 更新到精确值, 但 Wilder RSI 需要额外维护 avg_gain/avg_loss 状态(从输出反推不出来)。 做完 append_bar 可到 3~4ms。风险在于一处不精确就静默换掉一批信号, 要做必须先扩对拍。

瓶颈已经换位置了。 本机分档(research/live/probe_inner.py,与服务端 同口径):TF_DF 两条腿占 70%、build_htf_zones 13%、htf_fx_timeline 6%、 find_fast_bsp3+ladder+attach 合计不到 2%。但服务端报的是 chan 构建 22ms / 信号链 86ms,按机器差(×1.36)解释不了四倍差距。 曾怀疑是 payload 反序列化,实测 _rebuild 只有 1.0ms,假设不成立。 两边跑同一个探针对分档表,才能定位那 86ms。

→ 已定位,见 §5.72:那 86ms 不存在,是服务端的减法错了。分档两边一致。

5.72 那 86ms 不存在:inner_ms 是地板 30ms + 缓存浪费 37ms + 争抢 1.5x

服务端跑了同一个 probe_inner.py2 核,采集器十币在跑)。分档占比两边 对得上,四倍差距是伪命题:

本机 服务端
TF_DF 两条腿 70% 68~74%
build_htf_zones 13% 10~12%
htf_fx_timeline 6% 5%
find_fast_bsp3+ladder+attach <2% <2%
信号链合计 16~21ms(不是 86ms

服务端那个 22/86 是无效减法(见 §5.7 的撤回批注)。

但对完表冒出一个真问题: 探针里全量 TF_DF 合计 106~126ms,而采集器走 增量报的 inner_ms 也是 100ms 中位——增量该快得多,两个数却一样。差额去哪了? 排查顺序与结论:

假设 实测 判定
_rebuild 反序列化贵 两腿合计 1.6ms
某些币结构复杂 十币中位 92~105ms,几乎一致
周期性全量重建拉高中位 占 21.5%,且只贵 1.5x133 vs 91ms 部分
批内后段被拖慢 inner_ms 对批内次序相关 0.083,是平的
CPU 争抢 见下 ✓ 主因

「批内平坦」一度被我读成争抢的反证,其实反了:两个 worker 在整段突发期都 满载时,批内每个币被拖慢的程度一样,平坦正是均匀争抢的表现。

用外生指标(到达密集度,仅由 t_data_ms 决定,不含 inner_ms):

±250ms 内到达币数 1 2 4 6 8
inner_ms 中位 67ms 80ms 94ms 105ms 117ms

⚠️ 第一版用 beg = t_signal_ms inner_ms 反推并发区间,得到相关 0.533, 这个数是废的——inner_ms 越大区间越宽、重叠自然越多,相关性有一部分是构造 出来的。换外生指标后相关降到 0.271。凡是用被解释变量去构造解释变量的,先 怀疑循环。

注入合成负载复现(离线,2 核):

背景 compute 放大
空闲 29.9ms 1.00x
1 个满载进程 41.7ms 1.39x
2 个满载进程 80.2ms 2.68x
3 个满载进程 85.4ms 2.86x

⚠️ 别拿这张表算争抢倍数——那个 29.9ms 基线是废的。 它每次喂同一个窗口, append_bar 发现没有新根、一根没追(实测 6 次调用 stream 长度 2001→2001 零 增长),测到的只是信号链本身。拿它去比在场的 inner_ms 得出「3.3 倍争抢」, 又是一次口径不对齐——和被撤回的 22/86 同一类错,隔了一小时又犯一次。

口径对齐后:在场每次调用平均追加 2.81 根,因为 2 个 worker 各存一份缓存, 各自漏掉对方处理过的根(stream_bars 逐根 delta 在 ±1~±4 对称分布,正是两个 独立计数器的指纹;真重建只占 0.31%,此前算的 21.5% 是把换 worker 的小幅 回退误判成重建)。而 add_indicators 每次追加都全表重算,所以追加成本随根数 近线性涨:

离线每次追加 1 根 2 根 3 根 4 根
compute 45.0ms 55.7ms 70.1ms 85.9ms

在场平均 2.81 根 → 离线插值 67.3ms;在场 inner_ms 中位 100ms

结论(已按口径修正): inner_ms 100ms 拆成

耗时 性质
信号链 + _rebuild ~30ms 真实计算,追 0 根时的地板
追加 2.81 根(含 5m 腿) ~37ms 其中约 22ms 是缓存重复的浪费
2 核争抢 ~33ms 1.49x,不是 3.3x

⚠️ 争抢是 1.5 倍而非 3.3 倍,所以「加核」的收益比上一版写的小得多。

新发现的便宜杠杆:按币绑定 worker。 现在 symbol 落到哪个 worker 是随机的, 每个 worker 的缓存都只见到自己处理过的根,于是人人都要追 2.81 根。若把每个 symbol 固定到同一个 workersymbol hash → worker),每次只追 1 根:离线 67.3 → 45.0ms,在场约省 22ms × 1.49 ≈ 33ms/币,占 inner_ms 三分之一。 代价是失去负载均衡,但十币两 worker 本来就是静态五五分。

add_indicators 增量化(§5.71 末尾那条未做项)会同时压掉追加档的大头, 两件事叠加。

⚠️ 这和 §5.7 心跳里「币数 > 核数时加 worker 无用」不矛盾但要分清:加 worker 确实无用(worker 已等于核数);加核有用但只值 1.5 倍那部分。 原判定把两者 混成一句了。


6. 接下来要做的事(按优先级)

第 1 步:跑完 step39,确定实时窗口 已完成

结果见 5.4 节。结论:影子交易器用 2000 根 1m 窗口,单次计算 0.20s。 完整输出在 research/out/step39.logstep39_pit_1m.csv,无需重跑。

(若日后要重跑:python research/step39_pit_1m.py --symbols BTC,ETH,SOL --probe 60 --workers 3,约 4 分钟。瓶颈不在窗口重建,而在 run_one 开头 那次 120 万根 1m 的全量 TF_DF。)

第 2 步:向用户确认交易所 已定:Bitget + Hummingbot

他已选定先只上 1m(在我问「先从哪条腿落地」时选的 1m_first)。

延迟已实测完成(2026-08-27,服务器侧)

四路对照(宿主机 ccxt.pro / 宿主机原始 WS / 容器原始 WS / 容器 Hummingbot, 同一批 K 线对齐),把最初测到的「Hummingbot 慢 1030ms」拆开了:

  • 容器网络 2~18ms
  • Hummingbot 自身处理开销 10~30ms(不慢反快)
  • 剩下 1350~1480ms 全在上游连接器的一个 bug 上

Bug:Bitget 换根时推的是带两根 K 线的消息 [上一根, 新一根] 而上游解析写的是 data["data"][0],拿到的是上一根;新一根要等下一条 单元素消息、约 1.1 秒后才进 deque。ccxt 遍历全部元素,所以没这问题。

修法:不能简单改成 [-1]——那样上一根的收盘价会永远停在换根前 约 1 秒的那次推送上,而我们的信号对 0.25bp 的扰动都会换掉一半结果, 收盘价偏一个 tick 不可接受。正确做法是处理消息里的全部元素: 前面的就地写回,最后一根交基类 append。

20 分钟 / 60 根配对验证:

上游 lag 补丁后 lag 上游漂移 补丁后漂移
BTC 1454ms 547ms 0.81bp 0.50bp
ETH 1683ms 506ms 1.20bp 0.66bp
SOL 1408ms 642ms 1.29bp 0.87bp

补丁后与原始 WS 只差 5~14ms,贴着理论下限;19 根已收盘 K 线 OHLCV 逐根相同。

漂移 0.50~0.87bp 对 15.19bp 的预算只用掉 6%,延迟这一关过了。

⚠️ 但这是无条件漂移(60 根里绝大多数是普通换根),而我们只在 「收盘突破转强」那一刻入场,那一刻价格正朝我们方向跑。§3.2 已量化 滞后与收益严格单调且是系统性追高。信号根上的条件漂移预计显著更高, 影子测量必须按信号根条件化统计,见第 3 步。 另外测的是 BTC/ETH/SOL——既是流动性最好的,又恰好是样本内那三个; 真正要跑的 8 个样本外币盘口更薄,至少补测 TRX 和 ADA。

容器内可行性(同批确认)

Python 3.13.14 + pandas 3.0.5 + numpy 2.4.6,与本机 .venv 的 pandas 同版本。 同一份切片喂进去,三个币的信号下标、中枢数、中枢 checksum 全部逐一相同 容器内 0.26s/币 比本机 0.29s 还快。chanlun 直接挂载进容器即可, 不需要另起信号服务。(装进现有 .venv 走不通:Hummingbot 要 numba>=0.61.2aiohttp<3.14,与本机 Python 3.14 冲突。)

2000 根 1m 够取:单次上限 1000、分两页,1m 限 30 天。

补丁落地方式:子类覆盖(已定)

不改镜像,用子类覆盖连接器的解析方法,升级 Hummingbot 不冲突。

⚠️ 这个方案有一个缺口必须堵:如果上游把被覆盖的方法改名, 子类覆盖会变成死代码,静默退回 1.4s,不报任何错。 所以启动时要断言基类上确实存在该方法名(有条件的话连签名一起校验), 把静默失效转成启动即失败。

⚠️ 无论用哪种补丁方式,都要有运行时 lag 探针——补丁机制只防得住 「上游代码变了」,防不住 Bitget 再改一次消息格式:

  • 每根 K 线收盘记 本地接收时间 K线收盘时间
  • 最近 30 根取滚动中位数
  • 中位数 > 800ms 告警并停止开新仓(补丁后实测 506~642ms 理论下限约 500ms800ms 留足抖动余量又能对 1.4s 的退化一刀切死)

要停开仓而不只是打日志,因为损失是经济性且静默的—— 不会崩、不会报错,只会让收益慢慢变差,几周后才从统计里看出来。

第 3 步:写影子交易器测滑点(核心工作)

关键判断:测滑点不需要任何交易框架。 完整框架解决的是「如何可靠下单」, 而当前的未知量是「成交价会差多少」。所以先写一个不下单的影子跑法:

每根 1m 收盘 → 拉最新 K 线 → 算信号(窗口取第 1 步的结论)
           → 信号触发时抓真实盘口(bid/ask + 深度)
           → 按仓位吃单深度算出真实成交价
           → 等下一根 K 线出来,取其开盘价(回测假设的成交价)
           → 两者相减 = 真实滑点

必须把时间戳拆开记录,否则不知道该优化哪里:

时间戳 含义
t_close K 线收盘时刻
t_data 数据到手时刻 → 拉取延迟
t_signal 信号算完时刻 → 计算延迟
t_book 盘口快照时刻 → 下单时点

滑点应分解成三块:延迟漂移t_book 中间价 次根开盘价)、 盘口价差ask 中间价)、深度冲击(加权成交价 − ask)。 延迟漂移已单独测过(第 2 步,0.50~0.87bp 无条件), 但信号根上的条件漂移才是要测的量

形态已定:Hummingbot V2 controller(不再写独立 shadow.py

  • 信号承载在 V2 controller 里,chanlun 挂载进容器直接用
  • chanlun 计算走 ProcessPoolExecutor0.26s 是纯 CPU 且受 GIL 限制, 直接放进 async 会卡住事件循环
  • 滑点测量读连接器真实盘口,不用 paper trade 的模拟成交

必须记录的字段(否则数据回来无法对判据)

时间戳四件套,拆开才知道该优化哪里:

字段 含义
t_close K 线收盘时刻
t_data 数据到手时刻 → 拉取延迟
t_signal 信号算完时刻 → 计算延迟
t_book 盘口快照时刻 → 下单时点

每笔还必须记 atr_pct——判据是 bp 口径而 ATR 逐年变化(见 5.3), 不记 ATR 就无法把实测滑点换算成 R、也无法验证门控是否正确执行。

统计口径三条硬要求:

  1. 只统计通过全部滤网的信号根(同向 + 阶梯 + ATR ≥ 8bp 门控)。 在未过滤的根上测滑点会把判据算宽——那些单子我们根本不做
  2. 条件漂移与无条件漂移分开报。无条件值(0.5~0.87bp)已知, 要的是信号根上的值。两者的差就是「系统性追高」的大小
  3. 出场腿单独统计:止盈是 maker 不吃滑点,止损/超时是 taker 要吃。 §1.3 的费率模型按出场原因分别计费,滑点也必须这样分, 否则会把 60% 不吃滑点的止盈腿混进平均值里,低估真实成本

对判据时用每条 taker 腿的滑点(入场 + 止损/超时出场), 不是每笔的总滑点——余量 15.19bp 就是这个口径。

记录与报表已在服务器侧实现research/live/shadow_hb.py(采集)与 shadow_report.py(报表)。它的设计比研究侧曾经写过的那版好,不要重复造: 每个信号在 0.5s / 1s / 2s / 5s / actual 五个延迟上各测一次——同信号内的 受控对比,能直接读出「延迟压到 X 秒滑点是多少」,决策不被当前实现拖累; 另外还扫了仓位,滑点也已拆成漂移 / 价差 / 冲击。

判据常数留在研究侧research/lib/shadow_budget.py (逐币 BUDGET_BPATR_GATE_BPLEG_IS_TAKERlag_healthy()verdict())。分工的理由是这些数会变——2026-08-27 一天之内预算就动了四次, 费率也改了一次,写死在 live 侧的任何一份都会静默过期。

其他实现要点:

  • 数据格式必须与 lib/data.py 一致:timestamp(int64 ms), date(tz Asia/Shanghai), open/high/low/close/volume
  • 持仓也要影子管理:出场按 1m 自己的参数(3 ATR 减半 / 留损 2 / 目标 8 ATR / 48 根超时),出场同样记录真实盘口
  • 状态要落盘,重启不能丢

第 4 步:根据滑点结果决策

旧阈值(2.5 / 3.9bp)已作废:那是 TP=3.0、全 taker、原始费率记错 三重错误叠加出来的,见 5.3。新判据如下。

前提:1m 用自己的出场参数(SL2 / 3ATR减半 / 留损2 / 目标8ATR / 48根

  • ATR ≥ 8bp 门控 + 实际费率 2/0.8bp。

判据用 2026 那个最差年份的 15.19bp,不要用全样本的 25.39bp。 低波动环境是当前状态,不是尾部情形。

实测滑点(每条 taker 腿) 判断
≤ 5bp 1m 可行,各年份都有厚余量,进真实 dry run
5~10bp 可行但只在中高波动期,门控阈值要上调(见 5.3 的费率-阈值关系)
10~15bp 仅 2021 型牛市能做,常态环境不要开
> 15bp 1m 放弃

5m/30m 不受影响这一句仍成立(余量 26bp / 89bp,且那是旧费率下的保守值)。

另外两点:

  • 滑点必须用 WebSocket 测。代理下 REST 单次往返约 2.4s,而信号计算只要 0.20s(§5.4),REST 测出来的全是代理的账
  • 入场条件是「收盘突破转强」,那一刻价格正朝我们方向跑, 延迟造成系统性追高、不会正负抵消(§3.2 已量化滞后与收益严格单调)

第 5 步(后续):1m 与 5m 分实例

用户问过「1m 和 5m 分成两个实例跑呢?」——对,而且是硬要求 freqtrade 一实例只能一个 timeframe;另有资金池隔离、统计独立、 API 限流风险隔离三个好处。

⚠️ 有个坑要提前处理:两个实例可能在同一个币上同时持反向仓位 (1m 出三卖做空、5m 出三买做多),单向持仓模式下会互相平掉或直接报错。 要么开对冲模式,要么两个实例分配不同币种(币种够多,分开还能看出品种间差异)。


7. 环境与数据

7.1 数据

  • 位置:data/binance/futures/{SYM}_USDT_USDT-{tf}-futures.feather
  • BTC/ETH/SOL:全周期 1m1w21722543 天
  • 另有 8 个样本外币种(BNB/XRP/DOGE/ADA/AVAX/LINK/LTC/TRX): 48 个文件已全部校验,2020~2026-08-26,零缺口零重复
  • 读取统一走 research/lib/data.pyfetch_ohlcv(symbol, tf, limit) 本地优先,回落到 https://provider.jackyu66.com(该服务只有 BTC/ETH/SOL, 且小周期仅 90 天,别指望它)

7.2 代理

本地代理 127.0.0.1:7897。Binance 和 Bitget 的 API 都需要它。

7.3 已修过的两个 bug(别再踩)

  1. 时间戳精度lib/data.py):不能用 date.astype("int64")//10**6 该值单位取决于列精度([ns] 给纳秒、[ms] 给毫秒),对毫秒精度的文件 会把时间戳砸平,再被 drop_duplicates 删掉九成数据。 正确写法:(date - pd.Timestamp("1970-01-01", tz="UTC")) // pd.Timedelta("1ms")
  2. 相邻中枢撞同一 entry_idx:会让下游 set_index("entry_idx")InvalidIndexError。已在 find_fast_bsp3 末尾按 ["entry_idx","occ","zone_i"] 排序后 drop_duplicates("entry_idx") 去重。

7.4 跑长任务的注意事项

  • 用 shell 工具的原生后台执行(block_until_ms=0), 不要用 nohup——早期用 nohup 的后台任务多次莫名消失
  • 1m 全量数据(120 万根)的 TF_DF 约需 2 分钟,任何涉及 1m 全量的脚本 都要预留时间
  • 多进程用 ProcessPoolExecutor,记得在子进程里重新 sys.path.insertwarnings.filterwarnings("ignore")
  • 内存很大(用户说「随便用」),但 1m 全量 × 多进程仍可能吃掉几十 GB

8. 代码地图

8.1 研究库 research/lib/

文件 作用
data.py 数据层,本地 feather 优先
fast_bsp3.py 实现已移入引擎chanlun/analysis/fast_bsp.py),这里只剩转发导入。所有 step 脚本的 from lib.fast_bsp3 import find_fast_bsp3 不用改
nested_level.py build_htf_zones 同样移入引擎并转发;annotate_position 仍在本地
nested_bsp.py htf_fx_timeline / attach_htf_context:区间套上下文。
confirm_ts+period 修正 K 线收盘时刻
fx_signal.py 分型信号提取与背驰
breakout.py 事件驱动回测。run_trades 支持 entry_delay/slippage/
boost_dir(动态止盈,已验证无效)

8.2 缠论引擎 chanlun/

  • TF_DF(df, 1, tf) 是入口,.dataframe 拿到含缠论标注的 DataFrame
  • analysis/fast_bsp.py核心,自研第四类买卖点 B4/S4(滞后 2.2 根), 2026-08-27 从 research/lib/ 搬来,回测与 web 图表现在共用同一份代码。 搬运时逐条比对过 BTC/ETH/SOL × 15m/30m 六组,中枢与信号完全一致。 它不是「B3/S3 提前几根」:判据(收盘价实时 vs 笔端点事后)、方向来源 (突破侧 vs 离开笔)、选样口径(627 个中枢里认 212 个 vs 引擎发 625 个)都不同。 step30 同条件对拍见 §4——同一组过滤器把 B4 从 PF 1.59 提到 2.26,对引擎 B3/S3 无效(0.66→0.71);引擎那批胜率 27.4% 低于 SL1.5/TP3.0 的随机基准 33%, 是系统性反向样本,不是滞后造成的衰减 除 find_fast_bsp3 / build_htf_zones 外,还有过滤用的 add_zone_ladder (中枢阶梯,§1.4)与 htf_fx_timeline / attach_htf_agree(区间套同向,§1.1 第三层)
  • pipeline/builders/fast_bsp.pyTF_DF.cal_fast_bsp(),把上面那套包成 ChanFastBSP(类型 Chan_BSP_TYPE.B4/S4)。大级别由同一份 df 重采样得到, 配对表 FAST_BSP_HTF_PAIR 就是 §1.5 那张表。 不在 init_TF_DF 里默认计算,要显式调用
  • web 端:/api/analyze 返回 fast_bsp_list / element_fast_bsp_list / sub_sub_fast_bsp_list,每条带 htf_agreeladder_ok 两个过滤标志。 图上深色 B4/S4 = 两个标志都满足,浅色 = 未通过过滤
  • pipeline/builders/incremental.py:增量更新(init_stream / append_bar / replace_last_bar / rebuild_bi_zs)。注释写明「最后一笔 is_sure 允许收回」, 这是 step38 要验证的那个隐患(已证实无影响)。 实盘若要用增量而非全量重算,需重新验证
  • pipeline/orchestrator.pyTF_DF 方法的门面
  • web/:图表与分析服务,无下单/订单管理功能,实盘用不上

8.3 实验索引

step 一句话
1~14 早期探索:信号有效性、滞后测量、直接预测收益(后发现有未来函数偏差,已弃)
15~18 区间套雏形;fast_bsp3 诞生(降滞后)
19~20 级别配对批量扫描 + 并行化
21 最优配置的尽调(尾部依赖、成本敏感)
22 执行压力:收盘价 vs 次根开盘、滑点
23 费率分档 + 刷量测算1m 经济性的数据来源)
24 信号聚簇:同一大级别分型下的多信号是否独立(是)
25 同中枢重复入场(只做首次)
26 中枢阶梯序列(趋势 vs 盘整,印证缠论定义)
27 动态止盈(无效)
28 全级别矩阵(最优配置来源)
29 信号漏斗诊断 + 参数敏感性
30/31 引擎原生 B3/S3 对比 + 方向反转诊断(引擎信号因滞后而亏损)
32 消融研究(alpha 来自中枢上下文,非触发动作)
33 require_touch=False 的影响(显著提升)
34 tol 扫描(滞后与收益严格单调)
35 高收益审计(口径、滑点、并发)
36 偏差审计(生效时刻、多空、时间样本外)
37 跨品种样本外8 个新币)
38 时点重建(无未来函数)
39 1m 时点重建 + 窗口扫描2000 根窗口饱和)
40 第四类买卖点的过滤消融(web 端原始 vs 过滤)
41 出场口径全扫SL × TP × MAX_BARS × 分批 × 剩余半仓止损位 + 真实费率模型)。TP=3 截早了;分批要做但止损保持原位;SL=1.0 最差
42 1m 单独定出场(同一张全网格,11 币 7 年 25476 笔)。1m 右尾是其他级别 2 倍,TP 不能混用;SL2 分批→8ATR 留损2 48根 在均R/R夏普/回撤/剔10%PF 四项全赢,滑点余量 11.06→20.12bpMAX_BARS=48 反而不用改
44 1m 过滤消融:浅色信号毛R 只有深色的 1/6,差在质量不在成本,不能做
45 重画审计脚本(时点重建,深色口径)——待跑
46 引擎逐位对拍基线klu/klc/bi/seg/zs/信号/消费列哈希),重构安全网
47 available_ts bis[2] A/B → 作废,毛R 被打成零(§5.42)
48 多币开仓时间分布、并发、簇内顺序(首发是未来信息)
49 「有前序」样本外验证(10 币 80 万根)→ 通过,余量 +6bp,6/6 时段同向
50 信号根成交量(用户假设「有资金的趋势才是好趋势」)→ 方向相反,高量毛R 0.794 vs 低量 1.421ATR 4/4 + 时段 7/7 同向;根因是在突破根上给别人接盘
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 开仓时段(亚/欧/美)(用户提议)→ 无效。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 的输出(早期方法论 已被推翻,含未来函数偏差)与旧口径备份一并删除,只留支撑当前结论的证据。 脚本都还在,需要时可重跑。step31 及之后的 .py 都在 research/ 下。


9. 与用户协作的注意事项

  • 用中文回复(用户规则)
  • 用户技术判断力强,会主动纠正方向(他纠正过我对区间套的理解、 指出内存回收、指出结论印证缠论定义)。他的领域直觉值得认真对待
  • 他反复强调不要再调参,要落地验证
  • 他讨厌长时间等待,早期多次问「还在跑吗」「好了吗」。 长任务要后台跑并主动汇报进度,不要让他干等
  • 报数字时必须交代口径(复利/杠杆/费率),否则会误导

10. 待办清单

  • 🚨 B4 实盘口径 PF 是 0.73,回测报 4.21 —— 最高优先级(§3.3994)。 时点干净(100% 准时,一类那个坑没有),但实时会多产出 74% 的信号, 它们 PF 0.26 / t 6.21三道滤网按同比例刷除、完全挡不住。 回测那 51 笔要事后全量重算才能识别,实盘当下分不出来。要做三件事
  • ① 在 1m 上复验(本轮测的是 5m/30m,实盘跑 1m)。机制相同但数字要单独出, step68_live_window.py --ltf 1m --htf 5m,这是决定是否要动实盘的依据
  • ② 试「中枢构成笔 is_sure」与「等 N 根看信号是否仍在」(均未测)。 前者用滞后换稳定性,后者直接过滤会消失的信号。目标是把那 74% 压下去
  • ③ 通知服务器侧:当前实盘在做一批回测里不存在的单。在 ① 出结果前 不建议改参数,但应知晓风险
  • 窗口左边界效应判为否(§3.3994)。2001 根滚动窗口与 2万→4万根增长窗口 跑出完全相同的 789/197/592,中枢是局部结构,截断无影响
  • 一类线:问题已完全定性,等一个决策(§3.3992 / §3.3993)。 全局只有一个变量——「是不是真线段端点」:是则 PF 2.29(5m)/4.11(15m) 否则恒为 0.13,其余特征都只是它的噪声代理。盈亏平衡精度 5m 72.6%、 15m 67.1%,当前 28.7%,最好的实时特征 ext_run 到 44%。 要继续就是做一个「实时判真底」的分类器打到 ~70%,标签/特征/评估口径 §3.3993 已给全,但先验很难,且 70% 只是毛平衡,还要再扣 15 根因果滞后。 这条不阻塞任何实盘工作
  • 一类超时从 48 根放宽(§3.3992,仍未跑,代价很低)。线段中位时长 113 根, 48 根在行情走完 42% 时平仓,真底那批 MFE 中位仅 2.37 ATR 疑似被截断
  • 二类关闭step64,§3.3991)。与一类不同,二类是信号消失而非信号指反: 两个方向 t 都贴零,且入场离结构止损位 4.87 ATR(一类 2.90), §3.3992 的结构止损解法对它不适用
  • step391m 时点重建 + 窗口扫描 → 2000 根窗口饱和,计算 0.20s, 假阳性 0%,1m 回测口径可信
  • 对齐 step23 与 step42 的 1m 数字3.91bp vs 11.06bp)。差距可能来自 数据年限(2.28 年 vs 7 年)或滤网(§5.3 原文只提「同向」,未提阶梯)。 §6 第 4 步的三条决策阈值全部依赖这个数字,对齐前不要据它做去留判断
  • 决定是否改出场口径(step41/42 样本外均已过,见 3.5 与 5.3)。 出场参数要按级别分开定,不能一套走天下。 5m/15m/30m 的首选是 「初始 SL 2.0 ATR、到 3 ATR 平一半、剩余半仓止损保持原位、跑到 8 ATR、 48 根超时」;若更看重单位风险期望而非回撤,初始 SL 用 1.5。 1m 用同一套形状,但 SL=2.0 是无争议的最优(均 R、R夏普、回撤、 剔10%PF 四项全赢,见 5.3),MAX_BARS=48 不变。 改的话 run_trades 要支持分批(现在只支持整仓单目标), 并重跑 step28/35/37 刷新本文档的年化/回撤数字——不要新旧口径混用。 1m 的并发已在 3.31 重算完(0.043→0.120,峰值 6),5m/15m/30m 尚未
  • 用实际费率(2/0.8bp)重算 step41/42 的分析段 → 1m 见 5.3 末尾 (均R +8%,判据 15.19bp);5m/15m/30m 见 3.5 末尾(余量只动 2%,结论不变)
  • ATR 门控搬到 5m/15m/30m 验证 → 惰性(30m 触发 0%、15m 0.16%、5m 2.6%), 可作全局规则 ATR ≥ 5 + 1.1×taker费(bp),当前即 ≥ 8bp
  • 确认交易所与框架 → Bitget + Hummingbot,先只上 1m
  • 测执行延迟 → 上游连接器 bug 已定位并修好,补丁后 lag 506642ms、 无条件漂移 0.500.87bp,占预算 6%。见 §6 第 2 步
  • 实盘信号计算改用增量 已上线(§5.7):清空十币 560 → 247ms。 配套的窗口裁剪也做了,但重建不要用 init_stream(它逐行 iloc 比批量 TF_DF(lean=True) 慢 3.2 倍,第一版用它反而涨到 1686ms)
  • 按币绑定 workersymbol hash → worker 当前最便宜的一刀。 现在 symbol 随机落 worker,每个 worker 的缓存只见过自己处理的根, 于是人人都要追 2.81 根,其中约 22ms 是纯重复。绑定后每次只追 1 根: 离线 67.3 → 45.0ms,在场约省 33ms/币(inner_ms 的三分之一)。 代价是失去负载均衡,但十币两 worker 本来就是静态五五分。见 §5.72
  • add_indicators 增量化(§5.71 末尾)。它是上面那个「追加档」的大头 ——每追一根都全表重算 2001 行,所以追加成本随根数近线性涨。 与绑定 worker 是叠加关系,不是二选一。 拦路的是 Wilder RSIEMA/MACD/ATR 递推、BB/SMA/量比是窗口,都能 O(1) 更新到精确值,但 RSI 要额外维护 avg_gain/avg_loss(从输出反推 不出来)。一处不精确就静默换掉一批信号,要做必须先扩对拍
  • available_ts 改用 bis[2](中枢形成)而非 bis[-1](中枢结束)的 完整 A/B —— 已完成,结论是不换step47,见 §5.42)。 当时预判的「反向风险:会去做仍在形成中的中枢的突破,质量可能变差」 正是实际发生的事,且比预期严重:毛 R 0.933 → −0.0008/8 币全变差。 这条已关闭,不要重开。
  • 查那 9.0% 的「中枢消失」是不是窗口左边界效应(§5.41)。若是,则 「回测用全量历史建中枢、实盘用 2000 根窗口」是比重画更根本的口径差。 注意这条与 bis[2] 无关,没有被 step47 否掉,仍然要查
  • 深色信号大样本重画审计,脚本已写:research/step45_repaint.py (逐根时点重建,替换掉 step39 那个随机抽点的无效测法)。 §5.42 之后这条的意义变了:不再是为了「修掉重画」,而是为了量化实盘 会多开多少仓、那部分的质量如何——重画本身已确认是必付代价
  • 写 V2 controller + 盘口缓冲,跑影子测量(当前第一件事)。 字段与统计口径见 §6 第 3 步,三条硬要求别漏:只统计过滤后的信号根、 条件漂移与无条件漂移分开报、出场腿按 maker/taker 分开统计
  • 改掉 shadow_report.pyBUDGET_BP 已改为从 lib/shadow_budget.py import。原先硬编码的 BTC 0.13 / ETH 4.02 / SOL 2.92 由六处差异叠加而来(只有同向没有阶梯过滤、费率按 6bp 双边 taker、TP=3.0、余量没除 taker 名义额、无 ATR 门控,且 BTC/ETH/SOL 恰是 ATR 最低的三个币),正确值 8.58 / 20.64 / 16.83。 这条当时优先级最高:报表里 drift > bdrift > b*0.6 是自动 停机开关,用错的预算会让它比真实情况早约五倍触发,误杀一个可行的策略
  • live 信号路径补上中枢阶梯过滤与 ATR 门控 已补 shadow_signal.py:11-18:同向 + 阶梯 + atr_pct ≥ ATR_GATE_BP)。 原先只有 h1_agree == 1,测的不是我们要交易的那批信号
  • 子类覆盖加启动断言 + 运行时 lag 探针(>800ms 停开仓),见 §6 第 2 步
  • 补测 ADA / DOGE / AVAX 的漂移——真正要交易的是这批(预算 15~22bp)。 BTC/ETH/SOL 流动性最好,测滑点偏乐观是安全方向,但判可行性不能只看它们。 BTC 大概率不该做 1mATR 中位 2026 仅 6.5bp11 币最低), 门控刷掉 58.5%,修正后预算 8.58bp 仍是最低。TRX 2026 门控后只剩 4.2%
  • 收集 1~2 周影子数据,与回测口径逐笔对比
  • 按 §6 第 4 步的四档判据决策 1m 是否可行
  • 若可行:真实 dry run
  • 补一项研究阶段的缺口:资金费率从未计入任何回测。 注:1m 新参数下平均持仓 28.4 根 = 28 分钟,很少跨 8 小时结算点, 这一项对 1m 影响小;30m 腿才是真问题。 30m 腿平均持仓 6.5 小时会跨结算点,需要评估影响
  • 保证金约束仍未建模,且比原来估的要紧。原注「有仓位时间仅 8.6%、 预计影响小」是旧出场口径下的;新口径是 10.2%,峰值并发 6 且 92.7% 同向,平均杠杆 3.6x 时峰值约 21.6 倍名义额。见 3.31。 这条是扩币的前置条件——加币不分散,只把峰值敞口推得更高
  • 若要扩币:按 3.33 的两条标准筛(ATR 对门控 + 流动性), 并留一批筛完不看、直接进实盘验证,以保住样本外的说服力
  • 因子化仓位已评估完(step51,§3.39),结论与分层表给的印象相反: 量因子做成开关vr60 ≥ 4 不做),前序因子不进仓位。 剩下两件事:
  • 上「mom60 ≥ 7 不做」这个开关(§3.391 已取代原来的 vr60 ≥ 4)。 与其他开关不同,这个不需要等滑点数据:它在 0bp 到 20bp 的每一档上 都不输给等权,5~12bp 区间还大幅领先,且总R 比不砍更高(657.7 vs 596.6) ——被砍的那 22% 期望为负。唯一的前置动作是确认阈值附近没有断崖敏感 (阈值 7 是贴着 Q4 边界取的整数,看过分位表才取的)。 ⚠️ live 路径目前没有这一层shadow_signal.py 的三道过滤是 同向 + 阶梯 + ATR 门控,mom60 连算都没算。要上得先在信号侧补出这个字段
  • 若真实滑点实测 ≥15bp,再考虑叠加 vpre10 ≥ 1.5vr60 ≥ 4 "三个都砍",保留 42%)。滑点 <12bp 时这个叠加是亏的,别提前上
  • 有前序 的余量优势改用放宽 ATR 门控兑现(多做几笔而非每笔做大)。 §3.31 已记,未回测
  • 持仓中放量 → 延长 runner 目标 / 加仓(step52 的建设性反面)。 已知:触发后止盈率 45.7% vs 全体 30.1%,控存活期后 5/5 档同向。 但基线已隐含吃到这部分(拿着不动就是),要多拿必须主动改目标位, 那是新参数,要重新回测。R差 随触发时点递减(0.785 → 0.281), 窗口应偏前段