Skip to content

A 股实盘约束:T+1、涨跌停与流动性 ​

回测里一行 buy,看起来像点外卖下单:想买就买,想卖就卖。可 A 股实盘更像节假日排队买票:窗口有开门时间,队伍有先后顺序,票卖完了你再想买也没用。

这是什么 ​

A 股实盘约束,就是程序化交易在真实 A 股里必须处理的 T+1、涨跌停、集合竞价和流动性限制。说白了,它提醒你:回测引擎里出现买卖信号,不等于真实市场一定能按你想要的价格成交。

如果把回测引擎比作纸上记账,A 股实盘约束就是柜台规则。纸上写“今天卖出 200 股”很容易,但柜台会问:这 200 股是不是今天刚买的?价格有没有碰到涨停或跌停?现在是不是集合竞价时段?这只股票当天成交够不够活跃?

入门阶段先把四类约束写进脑子里:

约束对程序的影响新手常见误读
T+1当日买入的普通股票通常次日才能卖出回测里当天买当天卖
涨停/跌停价格触及上限或下限时,买卖可能排队很久以为有信号就一定成交
集合竞价开盘前和收盘前有集中撮合规则把所有时间都当成普通交易
换手率成交活跃程度不同,买卖难度不同忽略“想买多少就能买多少”

经验

第一版实盘约束不用写得像券商系统,但至少要做到:不能卖今天刚买的普通股票,不能假装涨停随便买、跌停随便卖,不能忽视成交是否活跃。

为什么回测信号会骗你 ​

回测报告里的收益、回撤、胜率、盈亏比都建立在一个前提上:回测引擎的成交假设要接近真实市场。假设太松,报告就会变漂亮;约束一加,很多“好策略”会露出问题。

比如一条短线策略在早上发出买入信号,下午价格跌破止损线。回测如果允许当天买当天卖,它可能只亏一点就离场;但普通 A 股股票通常 T+1,当天买入后当天不能卖,这笔持仓要扛到下一个交易日。中间如果遇到跌停,卖出还可能排队。

再比如策略看到涨停就追涨。回测里一行代码可以按涨停价买入,但真实市场里,涨停时可能有很多买单排在前面,你的下单未必能成交。反过来,跌停时想卖,也可能排在卖单后面,不能按回测想象立刻清仓。

这不是程序问题,是交易规则问题。A 股实盘约束越早写进模型,越不容易被虚假的漂亮曲线骗。

一个具体场景 ​

以贵州茅台(600519,白酒行业,上交所主板,2001 年 8 月 27 日上市)作为真实 A 股公司例子;下面数字是教学样本,不代表真实历史行情。

假设某条量化策略规则在三天里给出这些信号:

timeprice_snapshotsignalmarket_statenote
2024-01-10 10:00100.00buy正常交易买入 200 股
2024-01-10 14:3098.00sell正常交易当天买入,普通股票不能当天卖
2024-01-11 10:0090.00sell跌停可以下单,但可能排队卖不掉
2024-01-12 10:0092.00sell正常交易若能成交,才真正离场

纸面回测如果写得很松,可能在 2024-01-10 就按 98.00 元卖掉,亏 400 元。但更贴近 A 股规则的处理是:当天买入的普通股票不能当天卖,2024-01-10 的卖出信号只能记录为“不可卖”;2024-01-11 即使能卖,也要考虑跌停下卖单排队,不能默认马上成交。

这会直接改变回测报告。原来只亏 400 元的交易,可能变成更大的亏损;原来很浅的回撤,可能变深;原来正的期望值,也可能被实盘约束压低。

风险

方向性做法:写回测引擎时,先把“能不能成交”拆出来单独判断。适用条件是策略要从教学样本走向更真实的检验;反例是只要有买卖信号就按收盘价成交;风险是回测报告高估收益、低估回撤,真实交易时落差很大。

四个约束怎么落到程序里 ​

第一,T+1 要有持仓日期。程序不能只知道“有 200 股”,还要知道这 200 股是哪天买的。当天买入的普通股票,卖出判断要先挡住。

python
def can_sell_today(row, account):
    return account["shares"] > 0 and account["buy_date"] < row["date"]

第二,涨停和跌停要改变成交假设。出现涨停时,买入不能默认成交;出现跌停时,卖出不能默认成交。入门版可以先保守处理:涨停不追买,跌停不默认卖出成功。

python
def can_fill(signal, market_state):
    if signal == "buy" and market_state == "涨停":
        return False
    if signal == "sell" and market_state == "跌停":
        return False
    return True

更稳的做法,是让数据里直接带上涨停、跌停状态,或者按上交所、深交所、创业板、科创板、北交所等不同规则表去判断;不要把全市场都写成同一个固定阈值。

第三,集合竞价要单独标记。集合竞价是集中撮合,不是普通连续下单体验。入门版可以先规定:用日线策略时,不把集合竞价价格当成随便能成交的价格;需要用它时,必须在数据里单独标明。

第四,换手率要限制交易规模。换手率很低时,说明成交不活跃。你想买卖的数量越大,越不能假装一点影响都没有。入门版可以定一条保守规则:如果换手率太低,就少买或不买。

下面示例假设换手率单位是百分数,1 表示 1%,3 表示 3%。

python
def size_by_turnover(base_size, turnover_rate):
    if turnover_rate < 1:
        return 0
    if turnover_rate < 3:
        return base_size * 0.5
    return base_size

这些代码都很粗糙,但方向是对的:先判断能不能卖,再判断能不能成交,最后才谈买多少。

新手最容易踩的坑 ​

第一个坑,是把 T+1 写成一句提醒,却不写进程序。嘴上知道当天买入不能当天卖,代码里却还是当天买当天卖,回测报告自然会虚高。

第二个坑,是把涨停和跌停当成普通价格。涨停不是“随便买入的高价”,跌停也不是“随便卖出的低价”。真正麻烦的是排队和成交不确定。

第三个坑,是忽略换手率。散户小资金有时感觉不到,但程序一旦把仓位放大,成交不活跃的股票就会很难按理想价格买卖。主力和机构做交易会非常在意这件事,普通人至少不能完全无视。

大坑

不要让回测引擎默认“所有信号都能成交”。一旦默认太宽松,策略会在纸面上变得很聪明,在真实市场里变得很脆。

总结 ​

A 股实盘约束是在提醒你:量化交易不是只看信号,还要尊重 A 股交易规则。T+1 决定能不能卖,涨停和跌停影响能不能成交,集合竞价不能当普通时段随便处理,换手率提醒你成交是否活跃。

自检 3 问:

  1. 为什么普通股票当天买入后,回测里不能默认当天卖出?
  2. 涨停和跌停为什么会让“有信号就成交”的假设失真?
  3. 换手率低时,为什么策略应该更保守?

股市有风险,入市需谨慎。本文不构成任何投资建议。

本章新学到:A 股实盘约束。

内容仅用于学习交流,不构成任何投资建议。股市有风险,入市需谨慎。