的筛选器跑出来一个结果:某个标的日均成交额 800 万,深度够,成本可覆盖。

数字看着很正常,你信了。

而那 800 万里有六成是刷出来的——你的管线没有报错,也不会报错。它忠实地把交易所给的数字加了起来。

⚠️ 这一篇原本是第 15 篇的后四节。 那一篇越写越长,而它其实混了两件不同的事:

回答什么
第 15 篇 盘口和成交数据怎么读
本篇 你自己采集和计算这些数据时会遇到什么

⭐ 而它和第 26 篇也有明确分工:

第 26 篇给判据(阈值、否决顺序);本篇给实现(这些数怎么算才是对的)。

本系列仅用于记录与普及基础知识,不构成投资建议。本篇是工程内容,不含任何交易规则。

零、⭐ 贯穿全篇的一句话

数据错误不会报错。它只会静默地给出一个看起来合理的结果。

打个比方

代码错误像汽车抛锚:车不走了,你立刻知道出事了,然后去修。

数据错误像里程表少算了 10%:车照常开,仪表盘一切正常,你所有的油耗计算都基于一个错的数——而它永远不会提醒你。 你会一直用着,直到某天在别的地方对不上账。

⚠️ 这就是为什么这一篇的组织方式和一般的工程文章不同:它不按"功能模块"排,而是先列出所有会静默出错的地方,再讲怎么给它们造出一个能报警的机制。在这个领域,“没报错"从来不是"没出错"的证据。

代码错误会崩、会抛异常、会被测试抓住。数据错误不会——它产出的是一个数,而那个数落在合理区间里,你没有任何理由怀疑它。

⚠️ 这和第 38 篇第九节讲的回测引擎问题是同一类:规则自洽、代码正确、结果偏乐观,没有任何一处会报错。

⭐ 所以这一篇的组织方式是:先讲会静默出错的地方(第一节),再讲怎么造出有已知答案的校验(第二节)。

一、⚠️ 五个会静默出错的地方

① 刷量(Wash Trading)

部分交易所的成交量含虚假成分(自成交、激励性刷量),这直接污染 RVOL 和成交速度这类指标。

判断方向:优先用流动性最深的几家;对小平台的绝对成交量保持怀疑;交叉比对不同来源。而第 15 篇那条推论在这里就是解法——刷量能做大成交额,做不出真实的买单深度,因为挂真单要承担被成交的风险。

② 时间戳与 K 线口径

K 线区间是左闭右开还是左开右闭?
时间戳是成交时间还是撮合引擎接收时间?
时区与夏令时(⚠️ 美股时段会漂移一小时,见第 3 篇)
不同平台对同一根 K 线的切分可能不一致

⚠️ 后果:跨平台比对时,你可能在拿两根不同时间范围的 K 线做对比,而两边都是"正确"的数据

一条工程纪律全链路存 UTC 时间戳,只在展示层做时区转换;交易日历(开收盘、假期、夏令时切换)作为独立的数据源维护,不要从时间戳硬推。

⚠️ 而第 40 篇第六节说过,加密的「日线」起点纯粹是约定——这不只是分析问题,它首先是一个数据管道的配置项,而这个配置必须被显式写下来

③ WebSocket 断线与补数据

实时流会断。断线期间要用 REST 补齐,而补齐逻辑很容易出错:

重复数据    补的区间与已有数据重叠
缺失数据    ⚠️ 断线未被检测到
顺序错乱    补进来的数据插在了错误的位置

正确做法是用连续性做校验,而不是假设流是完整的:用成交 ID 或 updateId 的连续性判断,检测到缺口就明确记录,不要静默跳过

增量维护订单簿的场景尤其严重:漏一条更新,本地簿就永久偏了,而且之后每一次读数都是错的——它同样不会报错

④ REST 与 WebSocket 不一致

两个接口可能有不同的聚合方式、精度和延迟。

同一个指标用两条路算出来对不上,通常不是 bug,是口径不同。

先别假设是口径——第二节会说明,这个差异恰恰可以被做成一个校验。

⑤ 幸存者偏差

已下架、已归零的币会从数据源上消失。用「现在还能拿到数据的币」做历史回测,结果必然偏乐观(第 7 篇第 26 篇)。

这一条的性质和前四条不同:前四条是采集问题,这一条是存储问题——它要求你在标的还活着的时候就把它记下来,事后无法补救。

point-in-time 标的池不是一个查询,是一个必须从第一天就开始积累的资产。

二、⭐ 造出有已知答案的校验

⭐ 这一节做的就是给里程表配一个已知长度的路段:先造出一段你知道正确答案的数据,让管线跑一遍,看它算出来的对不对。没有这个动作,你的所有指标都是没校准过的仪表。

第 38 篇第九节给了一个思路:你所有的回测都没有已知答案,所以它们无法验证引擎;只有那个随机策略测试可以,因为它有已知答案。

数据管道可以用同样的方法,而且更容易——因为数据本身带着好几个恒等式。

⭐ ① 聚合可加性:这是恒等式,不是近似

第 27 篇第三节那条结论——周期之间是恒等关系不是相关关系——在这里变成了一个可执行的断言:

1 根 1 小时 K 线  ≡  它内部那 12 根 5 分钟 K 线

⇒ 成交量:  Σ(12 根 5min 的量)  ==  1 根 1h 的量
⇒ 最高价:  max(12 根 5min 的高) ==  1h 的高
⇒ 最低价:  min(12 根 5min 的低) ==  1h 的低
⇒ 开盘价:  第 1 根 5min 的开     ==  1h 的开
⇒ 收盘价:  第 12 根 5min 的收    ==  1h 的收

这五条必须精确成立(浮点误差以内)。不成立就是数据有问题,没有第二种解释。

⚠️ 它能抓到的东西非常多:口径不一致、缺 K 线、时区错位、补数重复。而且它不需要你知道"正确答案"是什么——恒等式自己就是答案。

② OHLC 的不等式:逐根可断言

low ≤ min(open, close)   且   max(open, close) ≤ high
volume ≥ 0
成交额 ≥ 0,且 (成交额 ÷ 成交量) 落在 [low, high] 之内

最后一条最有用成交额 ÷ 成交量 就是这根 K 线的 VWAP(第 15 篇第一节),它必然落在最高价和最低价之间。落在区间外,说明两个字段来自不同的口径或不同的时间范围。

③ 盘口的不等式

best_bid < best_ask                      (交叉了说明快照撕裂)
买单价格严格递减,卖单价格严格递增
相对价差 = (ask − bid) / mid  ⚠️ 不应为负,也不应大到离谱
深度累计量单调不减

⚠️ 「快照撕裂」是增量维护订单簿最常见的静默故障:买一价高过卖一价,而程序照样算出一个 OBI 数值给你。

④ 两条路径的交叉校验

第一节 ④ 说 REST 与 WS 口径可能不同。把它反过来用

每天定时,用 REST 拉一段历史,和 WS 落库的同一段比对
记录差异的分布,而不是只看"对不对"

差异应当是有界且稳定的。 差异的分布突然变化,说明有一边出了问题——这比"某天发现数字不对"要早得多。

⑤ 回填与实时必须走同一条代码路径

这一条是工程结论,但它的后果直接落在第 38 篇上:

如果历史回填走一套代码、实时计算走另一套,你回测的和你实盘跑的就是两个不同的指标——而两边都不会报错。

正确做法是:指标计算只写一份,回填和实时都调它,区别只在数据从哪来。

顺带一条:本节这几个校验有一个很实用的性质——它们不在乎代码是谁写的。所以让 AI 写实现是安全的,只要校验由你定义、且是有已知答案的那种第 47 篇第四节)。

三、一个筛选器该算什么(指标层)

📌 这里给的是指标层——该算哪些数。把它们组装成一台每天能跑一遍、输出「今天哪些能做」的完整漏斗,见 第 26 篇,那里有阈值、分层否决顺序和三个数据陷阱。

必须有(回答「能不能交易」)

□ 相对波动率    ATR / 价格
□ 波动扩张      当前 ATR / 历史 ATR 均值
□ 成交量异常    同时段 RVOL 或 Z-score   ← ⚠️ 注意基准(第 15 篇第三节)
□ 价差成本      (Ask − Bid) / 中间价,bps
□ 冲击成本      逐档吃穿目标仓位(第 15 篇第五节)
□ 出场压力比    仓位 ÷ ±1% 买单深度        (深度口径,第 26 篇判据 > 0.3 出局)
□ 出场流量比    仓位 ÷ 最差时段分钟成交量   (成交量口径)
□ ⭐ 数据健康    成交 ID 连续性、最后更新时间、第二节那几条断言

最后一行是这份清单里最容易被跳过、也最该有的一项

如果你不知道数据是不是好的,上面六个数算出来是多少都没有意义。

⚠️ 两个「出得去吗」不是同一个数

清单里那两行经常被当成同义词,但它们口径不同、失效方式也不同——⭐ 而区别正好是第 33 篇第五节那张时态表:

分母 时态 ⚠️ 它的弱点
出场压力比 ±1% 买单深度 现在·快照 挂单可撤,所以它偏乐观
出场流量比 最差时段分钟成交量 过去·流量 是历史,未必代表今天

两个都要算:深度告诉你「此刻簿子上有多少」,成交量告诉你「这个时段通常能吸收多少」。深度好但成交量薄,意味着那些买单可能是一次性的第 15 篇第五节:补充速度才是真流动性)。

而无论用哪个口径,两条纪律相同(第 2 篇:能买到 ≠ 能卖出去):用买单侧,用最差时段——因为你需要出场的时候,很可能就是那种时刻。

可选(描述当前状态,不产生信号)

□ 主动买卖比    第 15 篇第二节
□ 成交速度      笔/分钟
□ CVD           累计,仅作状态观察
□ 资金费率      第 4 篇(⚠️ 封顶后失真)
□ 未平仓量变化  第 4 篇 + 第 33 篇第五节的四象限

明确不要做的

✗ 把任何单一指标设成阈值就触发「买入提示」
✗ 用 OBI 做分钟级判断        (第 15 篇第六节:时间尺度不匹配)
✗ 用「前几根 K 线」作成交量基准(第 15 篇第三节)
✗ 回填和实时用两套计算代码     (第二节 ⑤)
✗ 在没过第 38 篇那条流水线之前,把任何组合当成策略

四、⭐ 写这些代码到底值多少

回到第 7 篇的四个优势来源:

信息优势   ❌ 对个人基本封死
速度优势   ❌ 彻底封死——你不可能赢过专业做市商的机房
分析优势   🟡 有限,且会衰减
⭐ 行为与结构优势   ✅ 开放

一个能自动筛选、自动算仓位、自动记日志的工具,作用的是最后一项。(这一项的完整展开见第 46 篇。)

它让你更可能按计划执行,而不是让你比别人更快。

⚠️ 这一条值得说死,因为自建数据管道最常见的动机是错的:很多人写这些代码是为了"更早发现信号”——而那是速度优势,是封死的那一格。

⭐ 而它真正能兑现的价值有三项,全部可查证:

为什么确定
降低执行成本 第 26 篇:往返成本从 0.2% 压到 0.04%,可交易比值提高 5 倍
消除情绪干扰 第 9 篇:七种可预测的失败,规则化能挡掉大部分
让检验成为可能 第 38 篇:没有干净的数据,整条检验流水线都无从谈起

第三项是最容易被低估的:数据管道本身不产生任何收益,但没有它,你连"这个想法有没有用"都无法回答。

五、能回答和不能回答什么

问题
我的 K 线数据有没有问题 ✅ ⭐ 聚合可加性是恒等式,不成立就是错的
这两个字段口径一致吗 成交额 ÷ 成交量 必须落在 [低, 高] 内
我的订单簿本地副本还准吗 ✅ 连续性校验 + 买一卖一不交叉
我回测用的指标和实盘一样吗 ✅ ⭐ 只写一份计算代码,问题就不存在
我该算哪些量 ✅ 第三节清单
这些量的阈值该定多少 ❌ 那在第 26 篇
这个平台的成交量是真的吗 ⚠️ 不能直接判定——但可以改用深度,刷量伪造不了它
我能补回已下架标的的历史吗 ❌ ⚠️ 不能,必须从第一天开始存
写了这套工具我能不能赚更多 它作用于行为与结构优势,不是速度优势

六、这一篇的结论

  • 贯穿全篇的一句话:数据错误不会报错,只会静默地给出一个看起来合理的结果。 这和第 38 篇的回测引擎问题是同一类——规则自洽、代码正确、结果错误。
  • ⚠️ 五个静默出错的地方:刷量、K 线口径与时区、断线补数、REST 与 WS 不一致、幸存者偏差。⭐ 而幸存者偏差性质不同——前四个是采集问题,它是存储问题:point-in-time 标的池不是一个查询,是必须从第一天就开始积累的资产。
  • 对付静默错误的唯一办法是造出有已知答案的校验,而数据本身带着好几个恒等式
  • 聚合可加性:12 根 5 分钟的量之和 必须精确等于 1 根 1 小时的量,高低开收同理。不成立就是数据有问题,没有第二种解释。 它能抓到口径不一致、缺 K 线、时区错位、补数重复——⚠️ 而且不需要你知道正确答案,恒等式自己就是答案。
  • 成交额 ÷ 成交量 必然落在 [最低价, 最高价] 之内——落在区间外,说明两个字段口径不同。
  • 快照撕裂(买一价高过卖一价)是增量维护订单簿最常见的静默故障,而程序照样能算出一个 OBI 给你。
  • 把 REST 与 WS 的差异做成日常校验,看的是差异的分布而不是"对不对"——分布变了比某天数字不对要早得多。
  • 回填和实时必须走同一条代码路径,否则你回测的和实盘跑的是两个指标,而两边都不会报错
  • 指标清单里最该有、也最常被跳过的一项是「数据健康」:不知道数据好不好,其余六个数算出来是多少都没有意义。第二容易漏的是:「出得去吗」有两个不同口径的数——出场压力比(深度·现在,但挂单可撤所以偏乐观)和出场流量比(成交量·过去)。两个都要算,且都必须用买单侧、最差时段。
  • 写这些代码的价值不在"更早发现信号"——那是速度优势,对个人是封死的。它作用的是行为与结构优势:降低执行成本、消除情绪干扰,以及让检验成为可能——数据管道本身不产生收益,但没有它,你连「这个想法有没有用」都无法回答。