客户在 App 上输入一个价格,柜台要在毫秒内回答"这个价格合不合法"。合法性的判定不是一道检查,而是三层:粒度够不够细(最小变动价位)、幅度有没有越界(涨跌停)、偏离有没有出圈(价格笼子)。三层规则的依据完全不同,校验失败的废单原因码也不同。这篇把三层拆开,顺便讲清那些零碎价格数字的来历。
第一层:最小变动价位,价格的"像素"
股票价格不是连续实数,是有刻度的。A 股的最小变动价位(tick size)是 0.01 元——申报 10.015 元直接废单。债券是 0.001 元,基金是 0.001 元,权证历史上是 0.001 元。港股复杂得多,按价格区间分档:0.25 元以下 tick 0.001,20~100 元区间 tick 0.05,越贵的股票刻度越粗。
工程落点很直接:tick 是品种级参数(甚至可以按价格区间分档),价格校验的第一步是检查申报价是否为 tick 的整数倍。用浮点判断 price % 0.01 == 0 是经典 bug——0.01 在二进制浮点里不是精确值,19.97 % 0.01 的余数不是 0。正确做法要么价格全程用整数分(price_fen = 1997)存储和比较,要么用定点小数类型。证券系统里"价格用整型存分"几乎是行业共识,源头就在这里。
第二层:涨跌幅限制,价格的"天花板和地板"
涨跌停价的定义:以前一交易日收盘价为基准,按涨跌幅比例计算,四舍五入到最小变动价位。普通 A 股 ±10%,ST 股 ±5%,科创板/创业板 ±20%,北交所 ±30%,新股上市首日另有安排。
$$ P_{\text{涨停}} = \operatorname{round\_to\_tick}\big(P_{\text{昨收}} \times (1 + r)\big), \qquad P_{\text{跌停}} = \operatorname{round\_to\_tick}\big(P_{\text{昨收}} \times (1 - r)\big) $$
举个具体例子:昨收 18.16,涨 10% 得 19.976,四舍五入到 0.01 即 19.98;跌停 16.344 → 16.34。注意这里会产生一个微妙的偏差:19.98/18.16 - 1 = 10.02%,实际涨幅略超 10%。这不是 bug,是舍入规则允许的正向越界——规则写的是"计算结果四舍五入至最小变动价位",而不是"不得超过 10%"。做清算核对或风控校验时,如果按 10% 严格反算就会误报。
实现上还有两个坑:
- 基准价不总是昨收。除权除息日的基准是除权除息参考价(公司行动篇讲怎么算),新股首日、恢复上市首日另有基准。涨跌停参数表必须有"基准价来源"这个字段,每天开盘前由初始化任务刷入,不能假定永远是昨收。
- 无涨跌幅的日子。新股上市首日(主板注册制后前 5 日无涨跌幅)、股改复牌等场景涨跌停放开,参数表要支持"本日无涨跌幅"的显式标记,而不是把上下限设成一个巨大数字糊弄过去——风控报表会把这个巨大数字当真值展示。
第三层:价格笼子,申报价的"活动半径"
涨跌停管的是全天边界,价格笼子(有效申报价格范围)管的是连续竞价阶段每一笔申报的瞬间偏离度。沪深主板现行规则(2023 年全面注册制后统一):买入申报价不得高于买入基准价(卖一价;无卖一则取买一/最新价的递进规则)的 102%,卖出申报不得低于卖出基准价的 98%。科创板/创业板此前就是 ±2% 笼子,注册制后向主板推广,并叠加了"0.1 元保底偏离"等细节条款。
笼子和涨跌停的关系:笼子是更紧的瞬时约束。一只股票距涨停还有 5% 空间,你按涨停价挂单买入,在笼子里照样废单。设计意图是挡掉"乌龙指"和瞬时拉抬——偏离市价太远的单子大概率是输错或操纵,直接拒在门外。
校验在哪一层做:柜台预审 + 交易所终审
三层校验在交易所侧全量执行,废单从交易所回来。但券商柜台必须预审,原因有两个:客户体验(等交易所废单回来,几秒过去了,App 上委托挂着不动会被投诉);报盘通道带宽(无效申报占通道额度,极端行情下无效单会挤垮网关)。
预审的麻烦在于笼子校验依赖实时行情:基准价是动中取值的卖一价。这意味着事前风控链路必须消费行情流——这是行情系统和交易系统一个容易被忽略的耦合点。实践中的折中是柜台缓存最近一档行情做预审,允许微小误差,最终以交易所终审为准。预审放过的边界单被交易所废掉,属于可接受损耗;预审误杀合法单才是问题,所以预审的笼子通常略微放宽(比如按 102.5% 算),宁可漏过不可错杀。
参数化是唯一出路
复盘这三层规则,没有一个数字是永恒的:tick 按品种分、涨跌幅按板块分、笼子比例被注册制改过、新股规则单独一套。把它们写进代码常量的系统,每次监管调规则都要改代码、过测试、走发布窗口。正确的形态是一张交易规则参数表:品种/板块 × 规则类型 × 生效日期,校验引擎按交易日取当期有效的参数。
生效日期这个维度特别关键。规则调整总是"自 X 月 X 日起施行",历史委托的校验口径必须按当时的规则留存,否则事后审计复现不了当时的判定。所有交易参数都该有时效区间,这条原则在风控参数热更新那篇还会再出现。
三层规则串起来,客户输入一个价格到收到"已报",中间过了粒度检查、边界检查、偏离度检查三道毫秒级关卡。每个废单原因码背后都是一条具体的交易所业务规则——理解规则出处,校验代码才写得理直气壮。