时间戳处理:让每一笔数据都有“正确的时间”

做期权做市,时间就是金钱。这句话一点都不夸张。

我见过太多团队,策略模型跑得飞起,结果因为时间戳没对齐,回测和实盘完全是两码事。说白了,时间戳处理是数据清洗里最基础、也最容易翻车的一环。今天我们就来聊聊这块。

一、时间格式统一:别让“时间”变成“时差”

交易所给的数据,时间格式五花八门。有的给Unix时间戳,有的给ISO 8601字符串,还有的给交易所本地时间。你想想看,如果混在一起处理,不出错才怪。

1.1 Unix时间戳

Unix时间戳是从1970年1月1日UTC开始的秒数(或毫秒数)。我个人习惯在内部存储时统一用毫秒级Unix时间戳,计算快,排序也方便。

import pandas as pd
import numpy as np

# 假设原始数据是秒级Unix时间戳
df['timestamp_sec'] = [1633046400, 1633046460, 1633046520]
# 转为毫秒级
df['timestamp_ms'] = df['timestamp_sec'] * 1000
print(df)

1.2 ISO 8601字符串

交易所API经常返回这种格式:2021-10-01T09:30:00Z。嗯,这里要注意,Z代表UTC时间,如果是美东时间,后面会跟-04:00或-05:00。

# ISO 8601 转 Unix 毫秒
df['iso_time'] = ['2021-10-01T09:30:00Z', '2021-10-01T09:31:00Z']
df['timestamp_ms'] = pd.to_datetime(df['iso_time']).astype(np.int64) // 10**6
print(df)

1.3 交易所本地时间

比如CBOE给的是芝加哥时间,Eurex给的是法兰克福时间。我在项目中遇到过,有人直接把本地时间当成UTC存进去,结果回测时发现所有数据都偏移了几个小时。

避坑指南: 我曾经因为没注意CBOE的夏令时切换,导致某天所有数据都差了1小时。后来我养成了一个习惯:拿到数据第一件事,先确认时间戳的时区信息。

二、时区转换:UTC、美东时间、北京时间

做期权做市,你大概率会同时接触多个市场。美国市场用美东时间,国内市场用北京时间,而数据存储最好统一用UTC。为什么?因为UTC没有夏令时,不会出现一年两次的“时间跳跃”。

2.1 统一转UTC

import pytz

# 美东时间转UTC
eastern = pytz.timezone('US/Eastern')
utc = pytz.timezone('UTC')

df['eastern_time'] = ['2021-10-01 09:30:00', '2021-10-01 09:31:00']
df['eastern_dt'] = pd.to_datetime(df['eastern_time']).dt.tz_localize(eastern)
df['utc_dt'] = df['eastern_dt'].dt.tz_convert(utc)
print(df[['eastern_time', 'utc_dt']])

2.2 北京时间与美东时间的互转

如果你同时做国内和美股期权,这个转换就特别重要。北京时间比UTC快8小时,美东时间比UTC慢4或5小时(取决于夏令时)。

# 北京时间转美东时间
beijing = pytz.timezone('Asia/Shanghai')
df['bj_time'] = ['2021-10-01 21:30:00', '2021-10-01 21:31:00']
df['bj_dt'] = pd.to_datetime(df['bj_time']).dt.tz_localize(beijing)
df['eastern_dt'] = df['bj_dt'].dt.tz_convert(eastern)
print(df[['bj_time', 'eastern_dt']])
小技巧: 我个人习惯在数据库里统一存UTC时间,前端展示时再转成用户本地时间。这样数据迁移、跨市场对比都方便。

三、交易日历对齐:剔除节假日、非交易时段

这一步很多人会忽略,但恰恰是回测准确性的关键。你想想看,如果节假日的数据混在训练集里,模型学到的规律能对吗?

3.1 交易日历数据

交易所每年都会发布交易日历。我建议你提前把全年交易日历下载下来,存成CSV或数据库表。

# 示例交易日历(简化版)
trade_calendar = pd.DataFrame({
    'date': pd.date_range('2021-01-01', '2021-12-31', freq='B'),  # 仅工作日
    'is_trading_day': True
})
# 剔除美国节假日
us_holidays = ['2021-01-01', '2021-01-18', '2021-02-15', '2021-04-02',
               '2021-05-31', '2021-07-05', '2021-09-06', '2021-11-25',
               '2021-12-24']
trade_calendar.loc[trade_calendar['date'].isin(us_holidays), 'is_trading_day'] = False

3.2 剔除非交易时段

美股期权交易时间是美东时间9:30到16:00。盘前盘后的数据,除非你专门做这个策略,否则最好剔除。

# 过滤非交易时段
df['time'] = df['utc_dt'].dt.time
market_open = pd.Timestamp('09:30', tz='US/Eastern').time()
market_close = pd.Timestamp('16:00', tz='US/Eastern').time()
df = df[(df['time'] >= market_open) & (df['time'] <= market_close)]
核心要点: 交易日历对齐不是简单的“去掉周末”。不同市场的节假日不同,比如美国有马丁·路德·金纪念日,中国有春节。一定要用对应交易所的官方日历。

四、知识体系总览

下面这张图,是我自己整理的时间戳处理流程。每次做数据清洗前,我都会对照着走一遍。

时间戳处理知识体系 原始时间戳 Unix / ISO 8601 / 本地时间 格式统一 统一为毫秒级Unix时间戳 时区转换 统一为UTC 交易日历对齐 剔除节假日 + 非交易时段 清洗后的时间戳数据 可直接用于回测和实盘 常见坑点 • 夏令时切换 • 节假日遗漏 • 时区信息丢失 • 毫秒/秒混淆 • 盘前盘后数据 目标:每一笔数据都有准确、统一、可对比的时间戳 原始数据 → 格式统一 → 时区转换 → 日历对齐 → 清洗完成

五、实战中的避坑指南

最后,分享几个我踩过的坑,希望能帮你少走弯路。

  • 夏令时切换: 每年3月和11月,美东时间会切换夏令时/冬令时。我曾经因为没处理这个,导致某天数据全部偏移1小时。建议用pytz库自动处理,不要手动加减。
  • 节假日数据: 不要只剔除周末。美国有十几个联邦假日,中国有春节、国庆等。我习惯每年年初从交易所官网下载交易日历,存成配置文件。
  • 毫秒与秒的混淆: 有些交易所给的是秒级时间戳,有些是毫秒级。如果不统一,排序和计算都会出错。我统一用毫秒级存储。
  • 盘前盘后数据: 除非你专门做盘前盘后策略,否则建议剔除。这些时段流动性差,数据质量也低。
我的习惯: 每次拿到新数据源,我会先随机抽100条记录,手动检查时间戳是否正确。虽然费点时间,但能避免后面的大坑。

时间戳处理看似简单,但细节决定成败。希望今天的分享能帮你少踩几个坑。


公众号:蓝海数据掘金营,微信deep3321