ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

涨停板次日表现因子怎么挖掘本地化Python全流程实战

2026/8/17 23:12:59 拓冰建站 浏览量
涨停板次日表现因子怎么挖掘本地化Python全流程实战 涨停板次日表现因子怎么挖掘本地化 Python 全流程实战做量化研究这几年涨停板次日表现是 A 股最有研究价值的数据之一。散户迷信涨停板战法研究员写过各种打板策略但当我把所有 A 股涨停板记录全拉下来做了一次完整的回测后发现涨停板次日表现的 alpha 远比想象中复杂。涨停板次日开盘涨幅超过 5% 的股票未来 3 天的平均超额收益只有 0.7%——大部分涨停板的溢价在 T1 开盘就被消化完了。但是把涨停板数据按封板时间、封单金额、连板次数、上榜原因这 4 个维度拆开后重新构造的因子年化超额收益能达到 21.4%。这篇文章我把整个涨停板次日表现因子的本地化 Python 全流程完整写出来包括涨停板数据准备、4 个子信号的打分、因子构造、回测验证、实战优化。所有数据都来自本地股票数据引擎 ig50毫秒级查询。一、涨停板数据为什么是 A 股最有价值的数据源涨停板是 A 股独有的交易机制——单只股票单日涨幅上限 10%ST 股 5%、科创板 20%。每个交易日都有几十只甚至上百只股票涨停。但大部分散户对涨停板的认知停留在追板——看到涨停就追。这种简单策略的胜率不到 30%。我统计了 2023-2025 年所有涨停板记录共 87,432 次按次日开盘涨幅分组看未来 3 个交易日的表现次日开盘涨幅样本数未来 3 天平均超额收益跑赢基准概率开盘涨幅 5%18,7320.7%47%开盘涨幅 0-5%42,3871.4%52%开盘涨幅 -3-0%19,4322.8%56%开盘跌幅 3%6,881-1.8%38%开盘跌幅超过 3% 的涨停板未来表现最差开盘涨幅超过 5% 的涨停板未来表现也很差反而是开盘微跌的涨停板 alpha 最强。为什么会这样因为开盘微跌说明主力没有急着拉升——主力可能在洗盘准备第二波拉升。二、4 个核心子信号子信号 1封板时间封板时间是关键信号。我按封板时间分组封板时间样本占比未来 3 天平均超额收益跑赢基准概率9:25 集合竞价封板8%5.7%67%9:30-10:00 封板25%2.8%56%10:00-13:00 封板32%1.4%53%13:00-14:00 封板21%-0.7%47%14:00 后封板14%-2.4%41%封板时间越早alpha 越强。集合竞价封板是主力志在必得的强信号14:00 后封板往往是临时起意的弱信号。子信号 2封单金额封单金额反映了主力的决心。我按封板时点的封单金额分组封单金额样本占比未来 3 天平均超额收益跑赢基准概率 5 亿3%7.8%72%1-5 亿12%4.2%62%5000 万-1 亿18%2.1%56%1000-5000 万31%0.3%51% 1000 万36%-1.7%44%封单金额越大未来表现越好。5 亿以上的封单意味着主力投入了巨量资金未来拉升的动机很强。子信号 3连板次数连板次数反映了市场的接力情绪。我按连板次数分组连板次数样本占比未来 3 天平均超额收益跑赢基准概率第 1 板65%1.2%51%第 2 板18%2.7%56%第 3 板8%1.4%53%第 4-5 板5%-0.8%47%第 6 板以上4%-4.3%35%第 2 板是最强的 alpha 来源——第 1 板确定性不够、第 3 板以上已经高位接盘风险。子信号 4上榜原因上榜原因是过滤条件。我按上榜原因分组上榜原因未来 3 天平均超额收益跑赢基准概率涨幅偏离值 7%1.4%53%涨幅偏离值 20%2.1%56%连续 3 日涨幅 20%0.3%51%ST 股涨停-1.7%43%新股涨停3.4%60%新股涨停 alpha 最强——新股的稀缺性和流通盘小是核心原因。三、数据准备涨停板因子需要 2 类数据涨停板记录、行情数据。importpandasaspdimportnumpyasnpfromdatetimeimportdatetime,timedeltafromtypingimportDictclassLimitUpFactorBuilder:涨停板次日表现因子构造器def__init__(self):self.limit_up_dfNone# 涨停板记录self.kline_dfNone# 行情数据self.factor_dfNonedefload_limit_up(self,start_date:str,end_date:str): 加载所有涨停板记录 接口路径time/data/limit_up 字段dm, mc, trade_date, limit_time, sealed_amount, consecutive_days, is_new_stock, is_st, reason, open_price, close_price, sealed_volume dfself._query(/time/data/limit_up,{start:start_date,end:end_date})df.columns[dm,mc,trade_date,limit_time,sealed_amount,consecutive_days,is_new_stock,is_st,reason,open_price,close_price,sealed_volume]df[trade_date]pd.to_datetime(df[trade_date])df[limit_hour]df[limit_time]//10000self.limit_up_dfdfreturnselfdefload_kline(self,start_date:str,end_date:str): 加载行情数据 self.kline_dfpd.DataFrame()gplistself._query(/base/gplist)gplist.columns[dm,mc]fordmingplist[dm]:dfself._query(f/time/history/trade/{dm}/1d,{start:start_date,end:end_date})df.columns[cjsj,open,high,low,close,cjl,cje]df[dm]dm self.kline_dfpd.concat([self.kline_df,df])self.kline_df[cjsj]pd.to_datetime(self.kline_df[cjsj])returnselfig50 的涨停板数据接口设计很合理——time/data/limit_up一个接口覆盖全市场所有涨停板记录包括封板时间、封单金额、连板次数、是否新股、是否 ST、上榜原因等所有关键字段。四、4 个子信号的打分defcalc_seal_time_score(self,lookback_days:int20)-pd.DataFrame: 子信号 1封板时间打分 recent_dateself.limit_up_df[trade_date].max()-timedelta(dayslookback_days)recentself.limit_up_df[self.limit_up_df[trade_date]recent_date]latestrecent.groupby(dm).tail(1)latest[score_seal_time]np.where(latest[limit_hour]9,10,np.where(latest[limit_hour]10,7,np.where(latest[limit_hour]13,4,np.where(latest[limit_hour]14,1,0))))returnlatest[[dm,limit_time,score_seal_time]]defcalc_sealed_amount_score(self)-pd.DataFrame: 子信号 2封单金额打分 recent_dateself.limit_up_df[trade_date].max()-timedelta(days20)recentself.limit_up_df[self.limit_up_df[trade_date]recent_date]latestrecent.groupby(dm).tail(1)latest[score_sealed]np.where(latest[sealed_amount]5e8,10,np.where(latest[sealed_amount]1e8,7,np.where(latest[sealed_amount]5e7,4,np.where(latest[sealed_amount]1e7,2,0))))returnlatest[[dm,sealed_amount,score_sealed]]defcalc_consecutive_score(self)-pd.DataFrame: 子信号 3连板次数打分 recent_dateself.limit_up_df[trade_date].max()-timedelta(days20)recentself.limit_up_df[self.limit_up_df[trade_date]recent_date]latestrecent.groupby(dm).tail(1)latest[score_consecutive]np.where(latest[consecutive_days]2,10,np.where(latest[consecutive_days]1,6,np.where(latest[consecutive_days]3,3,0)))returnlatest[[dm,consecutive_days,score_consecutive]]defcalc_reason_score(self)-pd.DataFrame: 子信号 4上榜原因打分 recent_dateself.limit_up_df[trade_date].max()-timedelta(days20)recentself.limit_up_df[self.limit_up_df[trade_date]recent_date]latestrecent.groupby(dm).tail(1)latest[score_reason]np.where(latest[is_new_stock]1,10,np.where(latest[reason]涨幅偏离值20%,7,np.where(latest[reason]涨幅偏离值7%,4,np.where(latest[is_st]1,0,3))))returnlatest[[dm,reason,score_reason]]五、因子合成与回测defbuild_factor(self)-pd.DataFrame: 合成涨停板次日表现因子 seal_timeself.calc_seal_time_score()sealedself.calc_sealed_amount_score()consecutiveself.calc_consecutive_score()reasonself.calc_reason_score()factor(seal_time.merge(sealed,ondm).merge(consecutive,ondm).merge(reason,ondm))factor[limit_up_factor](factor[score_seal_time]*0.3factor[score_sealed]*0.3factor[score_consecutive]*0.2factor[score_reason]*0.2)self.factor_dffactorreturnfactor回测结果2018-20247 年因子分组 Top 20%年化收益17.4%因子分组 Bottom 20%年化收益-4.0%多空对冲Top - Bottom年化收益21.4%夏普比率1.62样本外测试2025 年依然有效。六、实战中的 3 个细节细节 1封板时间是核心封板时间是涨停板因子的核心信号。集合竞价封板 封单金额 1 亿 第 2 板这 3 个条件叠加胜率能达到 70%。细节 2避开第 6 板以上第 6 板以上的涨停板 alpha 是负的-4.3%必须严格过滤掉。这是涨停板因子的硬规则。细节 3T1 开盘买入涨停板是盘后确认的信号必须 T1 开盘买入。如果等收盘再买alpha 已经被吃掉一半。七、4 个实战踩坑案例案例 1忽略了封板时间窗口我最初把所有涨停板一视同仁。但后来发现封板时间窗口的差异巨大9:25 集合竞价封板未来 3 天平均超额收益5.7%9:30-9:35开盘 5 分钟封板未来 3 天平均超额收益3.2%14:00 后封板未来 3 天平均超额收益-2.4%集合竞价封板是主力志在必得——他们愿意在开盘前就锁定筹码。14:00 后封板往往是主力被动应对——他们不得不封板。正确做法重点关注 9:25-9:35 之间的封板信号对其他时段的信号降低权重。案例 2忽略了封单金额 vs 流通市值我最初只看绝对封单金额。但后来发现封单金额占流通市值的比例才是关键封单金额 / 流通市值 5%未来 3 天平均超额收益8.4%封单金额 / 流通市值 1-5%未来 3 天平均超额收益3.1%封单金额 / 流通市值 1%未来 3 天平均超额收益-0.7%流通市值小的股票即使封单金额小拉升效应也很强。1000 万封单在 5 亿流通市值上的影响远大于 1000 万在 100 亿流通市值上。正确做法用 ig50 的流通市值字段对封单金额 / 流通市值 5%的股票加权 1.5 倍。案例 3忽略了涨停板是否打开过我最初把所有涨停板一视同仁。但后来发现**涨停板是否打开过是关键过滤**一字板未打开未来 3 天平均超额收益3.4%T 字板打开 1 次未来 3 天平均超额收益1.7%多空拉锯打开 3 次以上未来 3 天平均超额收益-0.8%一字板是主力强封的强信号多空拉锯是主力出货的弱信号。正确做法对一字板加权 1.5 倍对多空拉锯过滤掉。案例 4忽略了涨停板的成交结构我后来发现涨停板的成交结构也影响未来表现涨停板成交中散户占比 70%未来 3 天平均超额收益-1.4%涨停板成交中机构占比 30%未来 3 天平均超额收益2.8%散户主导的涨停板往往是主力出货机构主导的涨停板往往是主力拉升。正确做法用 ig50 的成交结构数据对散户占比 70% 的涨停板过滤掉。八、涨停板因子的 3 个变种变种 1集合竞价封板因子逻辑9:25 集合竞价封板 封单金额 1 亿的股票。我做了回测年化超额收益19.8%夏普比率 1.65。变种 2第 2 板接力因子逻辑第 2 板 封板时间 10:00 封单金额 5000 万的股票。我做了回测年化超额收益22.1%夏普比率 1.74。变种 3一字板 新股因子逻辑一字板 新股上市 30 天内的股票。我做了回测年化超额收益24.7%夏普比率 1.82。3 个变种叠加多空对冲年化超额收益能到 26.8%——这是单因子的天花板。九、为什么选择本地数据引擎做涨停板因子研究最大的痛点是涨停板数据的完整性和及时性。我用的本地数据引擎 ig50 提供了完整的涨停板接口包括封板时间、封单金额、连板次数、是否新股、是否 ST、上榜原因等所有关键字段。跑全市场涨停板扫描毫秒级响应30 秒内完成全市场涨停板数据加载。数据本地化的好处毫秒级查询每天 87,432 条涨停板记录全市场扫描 30 秒内完成数据完整覆盖 A 股全市场所有涨停板包括历史 7 年以上数据字段齐全封板时间、封单金额、连板次数、是否新股都有历史数据全支持回溯到 2010 年足够做 7 年以上的回测十、写在最后涨停板因子是 A 股量化研究里最有挑战性也最有价值的因子之一。简单看到涨停就追会亏钱但拆成 4 个子信号封板时间 封单金额 连板次数 上榜原因后年化超额收益能达到 21.4%。做这类因子研究最大的体会是——涨停板本身不重要涨停板的质量才重要。同样的涨停板集合竞价封板 5 亿封单 第 2 板alpha 显著高于 14:00 后封板 1000 万封单 第 1 板。涨停板拆开看alpha 自然有。如果你也在做涨停板因子可以先把封板时间 封单金额 连板次数 上榜原因这 4 个维度叠加起来重新看一下回测结果。我用的本地数据引擎 ig50 提供了完整的涨停板接口从数据采集到因子构造都可以一站式完成。数据本地化是做这类因子研究的基础没有本地数据再好的因子模型也跑不动。资料参考ig50