1. 课程导入与数据准备

在涨停板复盘中,“开板”是一个信息量极高的动作。它意味着涨停价上的封单被卖盘打穿,价格短暂离开涨停价,随后又可能重新封回。同样是一只最终收于涨停的股票,全天一次未开板与反复开板五六次,背后反映的资金分歧、承接强度和次日溢价预期完全不同。本课程的目标,就是把这件凭盘感判断的事,转化为一套可量化、可复现、可横向比较的统计流程:从原始行情数据出发,计算每只涨停股当日的开板次数、开板时长、回封速度等指标,再据此做分类复盘。

学习目标可以拆成三层。第一层是概念清晰:明确什么算一次开板、什么算回封、集合竞价和尾盘异动如何处理。第二层是数据可靠:能独立完成日线、分钟线与涨停板名单的采集和清洗,得到一份字段规范、时间对齐的原始数据集。第三层是统计可用:能基于分钟数据算出开板次数等核心指标,并知道这些指标在复盘中怎么用。整体流程是“确定口径 → 采集三类数据 → 清洗对齐 → 生成涨停样本表 → 计算开板指标 → 分类复盘”,本节聚焦前四步,也就是把地基打好。

核心概念:先定义,再统计

开板次数统计最容易出错的地方不是代码,而是口径。必须先约定参照系:以涨停价为基准,价格低于涨停价即视为“离开涨停”,重新回到涨停价并维持到该分钟结束视为“回封”。在这个约定下,一次完整的开板由“离开涨停”开始,到“再次封住”结束;若当日收盘仍未回封,则记为一次未回封的开板。

需要特别区分的几种边界情况:其一,一字板全天最低价等于涨停价,开板次数为 0;其二,集合竞价阶段的价格波动通常不计入开板,统计区间一般取 9:30–11:30 与 13:00–15:00;其三,尾盘开板未回封应单独标记,因为它对次日预期的影响与盘中回封不同;其四,不同板块涨停幅度不同(主板 10%、创业板与科创板 20%、ST 5%),涨停价必须按规则计算而非固定乘 1.1。这些口径一旦确定,就要在整门课程中保持一致。

数据准备与开板指标生成链路 三类原始数据 → 清洗对齐 → 涨停样本表 → 分钟级开板判定 → 复盘指标 日线行情 开高低收、成交量、复权 分钟线行情 1 分钟最高/最低/收盘 涨停板名单 代码、日期、涨停价 清洗与对齐 去重 · 补缺 · 复权统一 剔除停牌与新股 时间戳标准化 涨停样本表 每行 = 一只股 × 一日 含涨停价与涨停时间 按板块校验涨跌幅 开板判定 价格 < 涨停价 → 记一次开板 回封则闭合区间 输出指标(供复盘使用) 开板次数 累计开板时长 首次开板时间 是否尾盘未回封

数据采集:三类数据各司其职

日线数据用于确定“谁涨停了”以及涨停价、涨停时间、是否一字板等基础事实。关键字段包括:交易日期、股票代码、开盘价、最高价、最低价、收盘价、前收盘价、成交量、成交额、复权因子。涨停价可由前收盘价按板块规则计算,例如主板股票涨停价 = round(前收盘价 × 1.10, 2),创业板与科创板用 1.20,ST 股用 1.05,计算结果按交易所规则四舍五入到分。用日线可以快速筛出“收盘价等于涨停价”的样本,但要注意曾涨停但收盘未封住的股票不在其中,这类样本需要靠分钟数据或涨停板名单补充。

分钟线数据是计算开板次数的核心。1 分钟 K 线包含每分钟的最高价、最低价和收盘价,判定逻辑是:若某分钟最低价低于涨停价,说明该分钟内价格曾离开涨停,记为开板;若随后某分钟收盘价回到涨停价,则视为回封。若只有 5 分钟线,粒度会变粗,开板次数可能被低估,因此课程统一采用 1 分钟数据,并在结果中注明数据粒度。

涨停板名单(涨停池)通常包含股票代码、名称、涨停时间、首次封板时间、最后封板时间、封单额、开板次数等字段。不同数据源的“开板次数”口径可能不同,有的按分时价格穿越统计,有的按封单变化统计。因此我们把它作为交叉校验的参照,而不是直接照搬:自己算出的次数与名单差异较大时,回到分钟数据逐笔核对,往往能发现停牌、集合竞价或数据缺失的问题。

清洗与对齐:让数据能“对得上”

采集完成后,至少要做四类清洗。第一,去重与主键统一:以“股票代码 + 交易日期”为主键,避免同一股票重复入库。第二,缺失处理:分钟数据缺失的交易日应剔除该样本或标记为“数据不完整”,不能默认按 0 次开板处理,否则会系统性低估。第三,复权统一:计算涨停价必须用未复权的前收盘价,而做跨期收益分析时用复权价,两者不能混用。第四,异常值过滤:剔除停牌日、上市首日(无涨跌幅限制或规则特殊)、以及价格明显错误的记录。

下面是一段可直接参考的 Python 示例,演示如何用日线筛出涨停样本并计算涨停价。示例参数为教学假设,实际使用时替换为本地数据即可。

import pandas as pd

# daily: 列含 date, code, open, high, low, close, pre_close, board
def limit_rate(board):
    return {"主板": 0.10, "创业板": 0.20, "科创板": 0.20, "ST": 0.05}[board]

daily["rate"] = daily["board"].map(limit_rate)
daily["limit_price"] = (daily["pre_close"] * (1 + daily["rate"])).round(2)

# 收盘涨停样本
zt = daily[daily["close"] == daily["limit_price"]].copy()
# 一字板:最低价也等于涨停价
zt["is_one_word"] = zt["low"] == zt["limit_price"]
print(zt[["date", "code", "limit_price", "is_one_word"]].head())

得到涨停样本表后,再与分钟数据按“代码 + 日期”左连接,只保留交易时段内的分钟记录。连接后建议先做一次完整性检查:每只股票当日应有的分钟数约为 240 根(不含集合竞价),若某样本分钟数明显偏少,应标记为可疑并人工复核。这一步看似繁琐,却是后续开板次数可信的前提。

建议在原始数据集之外,单独保留一张“数据质量日志表”,记录每个交易日的样本数、缺失分钟数的股票数、与涨停池名单开板次数不一致的股票数。复盘时若发现某日指标异常,先查日志往往比重新跑一遍程序更快定位问题。

本节小结与检查标准

完成本节后,你应当拥有一份结构清晰的原始数据集:日线表、分钟线表、涨停池名单三张基础表,以及一张以“代码 + 日期”为主键、包含涨停价、是否一字板、分钟数据完整性标记的涨停样本表。判断是否达标,可以看三个信号:涨停价按板块规则计算且与交易所公布值一致;分钟数据缺失样本已被显式标记而非静默丢弃;随机抽取 5 只涨停股,能用手工核对分钟数据的方式复现其开板过程。做到这三点,后续的开板次数统计才有可靠基础。