3. 开板次数统计的字段设计与数据表构建

做涨停板复盘,最怕的不是数据少,而是数据散。行情软件里能看到“曾涨停”“开板”这类标记,但真要统计某只股票在某个阶段开板几次、每次开板持续多久、回封时封单有多大,靠盘中截图和手工记录很快就会失控。因此本节的核心任务,是把“开板”这件事拆成可存储、可查询、可复盘的字段,并落到一张结构清晰的数据表中。

先明确统计口径。所谓开板,指股票当日触及涨停价后,买一价位被卖单打穿、涨停价不再被封住的状态;一次开板从“涨停价被打开”开始,到“再次封住涨停价”结束。若当日多次打开又多次回封,则形成多次开板记录。这个定义决定了我们既需要“按次记录”的明细表,也需要“按日汇总”的统计表,两者不能混为一张表。

一、字段设计:从“一次开板”出发

字段设计应围绕一次开板事件的生命周期展开。最基础的标识是股票代码与交易日期,二者组合加上开板序号,才能唯一确定一条记录。价格维度需要涨停价,它是判断“是否处于涨停”的基准;时间维度需要首次封板时间、开板时间、回封时间,三者构成一次开板的起止区间;数量维度需要开板时的封单量(封单金额或封单手数,需统一口径)以及回封时的封单量,用来衡量封板强度。此外还应保留开板持续时长、当日开板次数、是否最终封住(收盘是否涨停)等派生或汇总字段。

这里有一个容易踩的坑:封单量必须注明单位与取值时点。是开板瞬间的封单,还是开板前最后一刻的封单?建议统一取“开板前最后一个涨停状态快照的封单量”,并在字段注释中写清楚。同理,回封时间应精确到秒,因为集合竞价尾盘的回封与盘中回封,复盘意义完全不同。

一次开板事件的字段结构与两表关系 时间 首次封板 封板时间 开板 开板时间 回封 回封时间 开板持续时长 = 回封时间 − 开板时间 开板明细表 kb_detail stock_code 股票代码 trade_date 交易日期 limit_price 涨停价 open_seq 当日开板序号 first_seal_time 首次封板时间 open_time 开板时间 reseal_time 回封时间 seal_vol_before 开板前封单量 seal_vol_reseal 回封时封单量 日汇总表 kb_daily stock_code 股票代码 trade_date 交易日期 open_count 当日开板次数 total_open_dur 累计开板时长 max_seal_vol 最大封单量 final_sealed 收盘是否封住 first_open_time 首次开板时间 last_reseal_time 最后回封时间 按日聚合 COUNT / SUM 明细表按“股票+日期+开板序号”唯一;汇总表按“股票+日期”唯一

二、建表语句与约束

下面给出可直接执行的建表参考(以常见关系型数据库为例,字段类型可按实际库调整)。关键约束有三点:明细表用联合主键防止重复入库;时间字段统一用带时分的类型;封单量统一用数值型并约定单位。

CREATE TABLE kb_detail (
  stock_code      VARCHAR(10)  NOT NULL,
  trade_date      DATE         NOT NULL,
  open_seq        SMALLINT     NOT NULL,
  limit_price     DECIMAL(10,2) NOT NULL,
  first_seal_time DATETIME     NULL,
  open_time       DATETIME     NOT NULL,
  reseal_time     DATETIME     NULL,
  seal_vol_before DECIMAL(18,2) NULL,
  seal_vol_reseal DECIMAL(18,2) NULL,
  PRIMARY KEY (stock_code, trade_date, open_seq)
);

CREATE TABLE kb_daily (
  stock_code      VARCHAR(10) NOT NULL,
  trade_date      DATE        NOT NULL,
  open_count      SMALLINT    NOT NULL DEFAULT 0,
  total_open_dur  INT         NULL,
  max_seal_vol    DECIMAL(18,2) NULL,
  final_sealed    TINYINT     NOT NULL DEFAULT 0,
  first_open_time DATETIME    NULL,
  last_reseal_time DATETIME   NULL,
  PRIMARY KEY (stock_code, trade_date)
);

注意 reseal_time 允许为空:若当日开板后直到收盘都未回封,该字段留空,同时汇总表 final_sealed 记为 0。这种“空值即未回封”的约定必须在字段注释中写明,否则后续统计会把空值误当成缺失数据。

三、历史数据入库的实操要点

入库前先做一次数据清洗。以某只示例股票为例(以下为教学假设数据):假设 2024-06-12 该股涨停价 12.50 元,首次封板 09:42:15,10:05:30 开板,10:18:02 回封,13:20:11 再次开板,13:31:40 回封,收盘封住。则明细表应写入两条记录,open_seq 分别为 1 和 2;汇总表 open_count 为 2,total_open_dur 为两次开板时长之和(约 12 分 32 秒 + 11 分 29 秒,按秒计约 1441 秒),final_sealed 为 1。

入库时建议采用“先删后插”的幂等策略:按 stock_code + trade_date 删除当日旧记录,再批量插入新记录,避免重复跑批导致数据翻倍。批量插入时用事务包裹,明细与汇总要么同时成功,要么同时回滚。若数据源是逐笔成交或快照,需先按“涨停价被打开—再次封住”的规则切分出事件区间,再映射到上述字段,切分逻辑应单独写成可复用的处理函数,而不是散落在入库脚本里。

建议在明细表中额外保留一个 data_source 字段(如“逐笔”“快照”“手工补录”),复盘时能快速区分数据可信度,也便于后续核对。

四、入库后的校验

数据入库不等于完成,必须做一致性校验。常用检查包括:明细表按股票与日期分组后的记录数,应等于汇总表的 open_count;open_time 必须晚于 first_seal_time,reseal_time 必须晚于 open_time;同一股票同一日期的 open_seq 应连续无跳号;final_sealed 为 1 时,最后一条明细的 reseal_time 不应为空。把这些校验写成 SQL 查询,每次入库后跑一遍,比事后翻记录可靠得多。

字段与表结构定好之后,后续的开板次数分布统计、回封强度对比、连板股开板特征分析,才有稳定的数据底座。结构设计阶段多花十分钟把口径和约束写清楚,能省掉复盘阶段大量返工。