3. 交易日历的生成与维护
交易日历是交易系统的“时间基准表”。它决定了某一天是否开市、属于哪个交易日、结算日如何顺延、节假日如何回补。时钟同步解决“现在几点”,而交易日历解决“今天算不算交易日、算哪一天”。两者共同构成 Session 管理的时间语义基础。本节聚焦交易日历的生成规则、数据来源与更新维护流程。
一、核心原理:交易日历不是简单节假日表
很多初学者把交易日历理解为“节假日列表”,这是最常见的认知偏差。真正的交易日历至少包含四类信息:
- 自然日序列:连续的日历日期,作为主键骨架。
- 交易日标志:该自然日是否为交易日(is_trading_day)。
- 归属交易日:夜盘、跨零点交易时段归属到哪个交易日(trading_day)。
- 阶段与顺延规则:如 T+1 结算、节假日顺延、临时休市。
以国内期货夜盘为例,周五 21:00 至次日凌晨 02:30 的交易,其自然日跨周五和周六,但归属交易日通常是下周一(若周一为交易日)。因此交易日历必须显式记录“归属交易日”映射,而不能靠日期加减推算。
二、数据源:权威来源与工程化选择
交易日历的数据源可分为三类,工程上通常组合使用:
| 数据源类型 | 典型来源 | 优点 | 风险 |
|---|---|---|---|
| 交易所官方公告 | 上交所、深交所、中金所、大商所等 | 权威、准确 | 格式不统一、需人工整理 |
| 行情/柜台接口 | CTP、恒生、券商柜台 | 与交易系统一致 | 依赖接口可用性 |
| 第三方日历库 | 交易所日历包、开源财经库 | 开箱即用 | 更新滞后、覆盖不全 |
推荐策略:以交易所公告为最终权威,第三方库作为初始种子和交叉校验,柜台接口用于运行时兜底。任何单一来源都不足以支撑生产级日历。
三、生成流程:从年度公告到可查询日历
交易日历的生成通常按年度进行,流程如下:
- 采集:抓取或录入各交易所下一年度休市安排公告。
- 解析:将公告文本解析为结构化记录(日期、休市类型、备注)。
- 展开:以自然日为骨架,逐日标注 is_trading_day。
- 映射:根据夜盘规则,计算每个自然日对应的 trading_day。
- 校验:检查连续性、节假日顺延、跨年边界。
- 入库:写入日历表,供交易、结算、风控查询。
下面是一个简化的日历表结构与生成伪代码:
CREATE TABLE trading_calendar (
cal_date DATE PRIMARY KEY,
is_trading_day BOOLEAN NOT NULL,
trading_day DATE NOT NULL,
exchange VARCHAR(16) NOT NULL,
session_type VARCHAR(16),
remark VARCHAR(128)
);
# 生成逻辑(伪代码)
for d in natural_days(year):
is_td = d not in holidays and d.weekday() < 5
td = resolve_trading_day(d, is_td, night_session_rule)
insert(cal_date=d, is_trading_day=is_td, trading_day=td)
四、更新流程:年度、临时与运行时
交易日历的更新分为三个层次,节奏和风险各不相同:
- 年度更新:每年末交易所发布次年安排,提前生成并冻结。
- 临时更新:台风、疫情、系统故障等导致临时休市或调整。
- 运行时更新:交易系统启动或每日初始化时加载最新日历。
五、案例与复盘:一次夜盘归属错误
某系统在国庆节前最后一个交易日(9 月 30 日,周二)的夜盘,将 21:00 后的交易归属为 10 月 1 日。由于 10 月 1 日至 7 日休市,系统在 10 月 8 日开盘时无法找到对应交易日,导致订单被拒绝、持仓对账失败。
复盘发现:日历生成时仅按“自然日 + 1”推算归属交易日,未考虑节假日顺延。修复方式是引入归属交易日映射表,并在生成阶段显式处理跨节场景。该案例说明,交易日历的生成规则必须覆盖夜盘、节假日和跨年三类边界。
六、维护要点与检查清单
为保证交易日历长期可靠,建议建立以下维护机制:
- 每年 Q4 启动次年日历生成,预留复核与冻结窗口。
- 日历表按交易所维度存储,避免多市场混用。
- 所有消费方统一从日历服务读取,禁止各自硬编码节假日。
- 每日开盘前执行日历自检:当日 trading_day 是否存在、是否连续。
- 临时变更必须记录操作人、时间、影响范围与回滚方案。
交易日历的生成与维护,本质是把交易所规则转化为系统可查询、可校验、可追溯的时间数据。规则清晰、数据源权威、更新流程闭环,才能让 Session 管理在夜盘、节假日和跨年场景下保持正确。