TT Lab
开始
学习 学习路径 课程

资本市场与清结算

夏令时切换之后,两个市场的收盘落在了同一时刻

在 TT Lab 中继续学习

目标

用时区规则把四个市场的当地时间成交记录转换成 UTC,区分夏令时切换日的特殊时间,标出交易时段阶段和交易日标签,然后找出各市场收盘在 UTC 中重叠的日子,以及日历本身的矛盾。

为什么重要

如果用固定偏移量来做时间转换,不会出现异常。只是一个带着一小时偏差的值被存了下来,而这一事实,要等到切换周末过去、对账对不上的时候才会暴露。在资本市场里,这种偏差会直接触及收盘批处理和汇总。而且各市场的切换日期不同,每年总有几个星期,一边已经是夏令时,另一边还是冬令时。只有在这几个星期里,两个市场的收盘才会落在同一个瞬间,这种事是真的会发生的。

步骤

  1. 用 python3 在 /root/session/data 中生成 markets.json、calendar.json 和 trades.csv。
  2. 用时区规则把当地时间转换成 UTC,以 trade_id,market,utc_ms 写入 /root/session/normalized.csv。在该当地时间里不存在的时间不要放进去。
  3. 把同样的成交用固定的冬令时偏移量来转换,把结果不同的写入 /root/session/fixed_diff.csv。
  4. 把不存在的时间写入 /root/session/nonexistent.csv,把出现两次的时间写入 /root/session/ambiguous.csv。
  5. 把每笔成交的交易时段阶段写入 /root/session/phase.csv,格式为 trade_id,phase。
  6. 把日历日与交易日不一致的成交写入 /root/session/tradingday.csv。
  7. 把每个基准日各市场的常规收盘写入 /root/session/close_utc.csv,把收盘时间接近的市场对写入 /root/session/overlap.csv。
  8. 把日历本身的矛盾写入 /root/session/calendar_defects.csv,并把前面各步骤的数量汇总到 /root/session/summary.json。

参考

生成四个市场的交易时段定义、日历和成交数据

用 python3 在 /root/session/data 中生成 markets.json、calendar.json 和 trades.csv。请原样使用不使用随机数的生成脚本。

不能直接使用客户数据,所以要做出形态相同的合成数据。不使用随机数,是为了无论谁运行多少次都得到同样的数据。评分器会把数据转换成标准形式来核对指纹,所以如果手工修改,后面的步骤就会全部被堵住。

用时区规则把当地时间转换成 UTC

在 /root/session/normalized.csv 中,首行写 trade_id,market,utc_ms,并把成交以 UTC 毫秒写出。在该当地时间里不存在的时间不要放进去。

用 zoneinfo.ZoneInfo 附加时区。要判断是不是不存在的时间,可以转换到 UTC 再回到同一个时区,看墙上时钟的值是否保持不变。出现两次的时间,采用先经过的一方。

用固定偏移量转换,找出出现偏差的日子

在 /root/session/fixed_diff.csv 中,首行写 trade_id,tz_utc_ms,fixed_utc_ms,diff_min,并写出用固定冬令时偏移量转换的值,与用时区规则转换的值不同的成交。

冬令时偏移量是该时区在 2025-01-15 12:00 的偏移量。不要把值写在代码里,请从时区中求出。diff_min 是用固定偏移量的值减去规则值得到的以分钟计的差。不存在的时间不放进这张表。

区分不存在的时间和出现两次的时间

在 /root/session/nonexistent.csv 中写入 trade_id,market,local_ts,在 /root/session/ambiguous.csv 中写入 trade_id,market,local_ts,first_utc_ms,second_utc_ms。

在春天把时钟拨快的市场里,被跳过的那一小时是不存在的。在秋天拨回去的市场里,同一个墙上时钟的值会经过两次。看 fold 为 0 与为 1 时的偏移量是否不同,就能同时抓住这两种情况,至于是其中哪一种,则用往返测试来区分。

为每笔成交标出交易时段阶段

在 /root/session/phase.csv 中,首行写 trade_id,phase,并为所有成交标上 pre、regular、post、closed、holiday 之中的一个。

最先判定休市日。然后按盘前、常规、盘后的顺序来看,哪里都不在,就是已收盘的时间。有半日市的日子,只改变常规收盘。阶段包含起点,不包含终点。

为跨过午夜的交易时段贴上交易日标签

在 /root/session/tradingday.csv 中,首行写 trade_id,calendar_date,trading_day,只写出两个值不同的成交。

有跨过午夜的交易时段的市场,写在数据里。在这些市场里,早于盘后阶段结束时间的成交,属于前一天的交易时段。其他市场始终与日历日相同。

把各市场收盘汇总成 UTC,找出重叠的批处理窗口

在 /root/session/close_utc.csv 中写入 market,date,close_utc_ms,在 /root/session/overlap.csv 中写入 date,market_a,market_b,gap_min。

基准日列表和接近的标准在数据里。处于休市日的市场,那一天没有收盘。跨过午夜的交易时段的收盘在第二天,所以日期必须加一天。市场对按字典序靠前的一方先写。

找出日历本身的矛盾,并汇总全部

在 /root/session/calendar_defects.csv 中写入 market,date,defect,并在 /root/session/summary.json 中汇总 trades、nonexistent、ambiguous、fixed_diff、phases、trading_day_differs、overlaps 和 calendar_defects。

矛盾有两种。同一天既是休市日又被写成半日市的情形,以及半日市收盘比常规收盘晚的情形。汇总中的数量不要用手数,请从与前面步骤相同的计算中取得。phases 是以阶段名称为键的计数对象。