回测里最漂亮的那条曲线,可能一行都执行不了——流动性是量化“实验室到现实“的死亡谷

先抛一个会让很多回测党脸色一变的判断——

一套策略在回测里跑出漂亮的净值曲线,不等于它能在实盘里赚到这笔钱。中间隔着一道叫"流动性"的死亡谷。你成交不了的收益,在回测里是净值,在实盘里是幻觉。

大部分人研究"买什么",研究了一辈子也不研究"能不能卖出来"。但在一套系统化选股的框架里,流动性是几道独立硬筛之一,跟基本面、技术形态一样重要——甚至更靠前。这一讲不讲交易代码:源文里没有任何回测收益、胜率,我也不会硬凑。我讲的是一件更靠前的事:为什么流动性必须做硬筛,以及冲击成本这个"看不见的成本"是怎么吃掉散户利润的。

一、先把"流动性"定义成三个可判定的问题

简单说,流动性 = 你想交易的时候,能不能以接近当前价格成交。它可以拆成三个问题——

  • 你想买的时候,有没有人卖给你
  • 你想卖的时候,有没有人买你
  • 你的成交价格,会不会因为你的交易而被推走

一只票流动性好,意味着这三个答案都是"是"。这三个问题翻译成工程语言,就是三个必须在下单前回答的约束——它们不是"买什么"的问题,是"这笔交易能不能落地"的问题。

二、最直观的指标:日均成交额(但要小心单日噪声)

最容易看的流动性指标是日均成交额。A 股的粗略分档——

日均成交额流动性状态
10 亿以上极好,进出无忧
1-10 亿正常,普通投资者无压力
5000 万 - 1 亿偏弱,大资金需分批
1000 万 - 5000 万差,谨慎参与
1000 万以下流动性陷阱区,能买进未必卖得出

关键工程细节:这个数字必须是滚动均值,单日不算数。一只票"今天成交了 5 个亿",可能只是因为它今天涨停了,不代表平时也有这个水平。系统里用单日成交额做筛选,等于被一次异常值骗进一个陷阱。

三、为什么"卖不出"比"买不到"更可怕——冲击成本的数学

新手最容易忽略后者。买不到最多是错过一笔交易,只是机会成本;卖不出就要命了。

想象你重仓的票出了利空,开盘 -7%,你想割肉,但盘口卖一只挂着 200 手,你 5000 手砸下去:

卖 1 (-7.0%) 吃掉 200 手 卖 2 (-7.5%) 吃掉 300 手 卖 3 (-8.0%) 吃掉 500 手 …… 最终成交均价 ≈ -9.5%

比你看到的开盘价还差 2.5 个点。这就是冲击成本——你的交易行为本身在拖低你的成交价。流动性差的票,单这一项就能吃掉你的利润。所以系统里光有"信号"不够,还要有冲击成本估算:模拟以策略所需仓位下单后的成交均价,作为"可执行性"的二次校验。

四、把四种流动性陷阱做成"排除标签"

源文列了四种典型陷阱,每一种都对应一个系统该识别的状态——

  • 微盘股:20 亿以下小票,日均成交可能只有几千万。100 万资金进去都要分批。
  • 长期阴跌的"僵尸股":连续阴跌、无人问津,日成交只有 1-2 千万。你看它"低估"想抄底,结果套进去出不来。
  • 重组停牌前的"突然冷清":临近重大事项停牌前,成交极低、价格不动的"诡异平静"。看起来稳定,其实是预期被锁定,消息一出你来不及反应。
  • 涨停/跌停后的"假满":涨停封单 5 亿看起来流动性极好——但你想卖时需要价格回到板下,那时已经雪崩了;跌停反之,封单巨大恰恰是你出不去。

注意最后一条:涨停封单大 = 流动性好,是一个必须在系统里显式反转的幻觉。封单代表的是"想买进不来",不是"想卖能卖掉"。

五、流动性是时变的——昨天的流动性 ≠ 你出货那天的流动性

很多人以为某只票"一直流动性都还行",但实际上:利好出来流动性会突然激增(一天几百亿都可能);利空、退市风险、停牌预期,流动性会突然枯竭;行业进熊市,整个板块流动性集体下台阶。

昨天的流动性 ≠ 今天的流动性,更 ≠ 你出货那天的流动性。

所以系统在配置一只票前,不能只看当前成交额,还要看历史最差成交额、类似情形下的成交模式——你要为"最坏的那天"留出口,而不是为"平均的那天"。

六、流动性和持仓规模强相关——这是散户的隐形天花板

10 万、100 万、1000 万,对流动性的要求完全不同:

  • 10 万:基本不挑票,连小盘都能玩。
  • 100 万:要避开微盘,至少日均 5000 万以上。
  • 1000 万:要找日均 5 亿以上,不然分批都费劲。
  • 1 亿以上:基本只能在沪深 300 + 中证 500 里挑。

很多散户从 10 万做到 100 万很快,但从 100 万到 500 万就突然不顺——不是策略失效了,是策略撞上了流动性天花板。这意味着系统的成交额下限,本质上是"资金量"的函数,不是一个固定常数。

七、一段诚实的伪 schema

fromdataclassesimportdataclass@dataclassclassLiquidityCheck:adv_rolling:float# 滚动日均成交额——绝不用单日值adv_worst:float# 历史最差成交额,为"出货那天"留出口est_impact_cost:float# 按本策略仓位模拟下单的冲击成本估算is_limit_locked:bool# 是否处于涨停/跌停封单的"假满"状态near_suspension:bool# 是否临近停牌等预期锁定情形# —— 显式声明 ——# 1. 成交额一律取【滚动均值】:单日放量(如涨停)会骗过筛子。# 2. 流动性下限是【资金量的函数】,不是固定常数。# 3. is_limit_locked=True 时,封单大 ≠ 能卖掉,必须反转"流动性好"的直觉。# 4. 本结构不含任何收益/胜率;仅回答"这笔交易能否落地"。

这段 schema 的全部价值,是把"能不能卖出来"翻译成了下单前的硬约束——没有流动性校验的策略,回测里看着漂亮,实盘可能一行都执行不了。这是量化最经典的"实验室到现实"的死亡谷。

八、给系统的三条纪律(也是给人的)

  1. 成交额用滚动均值,且下限随资金量浮动。单日放量是噪声,固定阈值会在大资金上失效。
  2. 给每个信号配一次冲击成本估算。信号说"该买",冲击成本说"买得起吗、卖得掉吗"。
  3. 把"5 分钟内能否全部卖出"当作一道硬测试。答案是"不行"的票,不该出现在这个仓位的候选池里。

九、思考题

  1. 如果让你给LiquidityCheck再加一个字段,去防住"重组停牌前诡异平静"这种陷阱,你会加什么?它对抗的是哪种直觉?
  2. 源文说流动性是"资金量的函数"。如果要让系统的成交额下限随账户规模自动调整,你会怎么设计这个映射?
  3. 冲击成本在回测里通常被忽略。你认为一个诚实的回测,应该怎样把冲击成本近似进净值曲线?

风险提示:本文为系统科普与个人思考分享,不构成任何投资建议。低流动性股票存在显著流动性风险,请审慎参与。投资有风险,入市需谨慎。