时间戳处理:让每一笔数据都有“正确的时间”
做期权做市,时间就是金钱。这句话一点都不夸张。
我见过太多团队,策略模型跑得飞起,结果因为时间戳没对齐,回测和实盘完全是两码事。说白了,时间戳处理是数据清洗里最基础、也最容易翻车的一环。今天我们就来聊聊这块。
一、时间格式统一:别让“时间”变成“时差”
交易所给的数据,时间格式五花八门。有的给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存进去,结果回测时发现所有数据都偏移了几个小时。
二、时区转换: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']])
三、交易日历对齐:剔除节假日、非交易时段
这一步很多人会忽略,但恰恰是回测准确性的关键。你想想看,如果节假日的数据混在训练集里,模型学到的规律能对吗?
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)]
四、知识体系总览
下面这张图,是我自己整理的时间戳处理流程。每次做数据清洗前,我都会对照着走一遍。
五、实战中的避坑指南
最后,分享几个我踩过的坑,希望能帮你少走弯路。
- 夏令时切换: 每年3月和11月,美东时间会切换夏令时/冬令时。我曾经因为没处理这个,导致某天数据全部偏移1小时。建议用pytz库自动处理,不要手动加减。
- 节假日数据: 不要只剔除周末。美国有十几个联邦假日,中国有春节、国庆等。我习惯每年年初从交易所官网下载交易日历,存成配置文件。
- 毫秒与秒的混淆: 有些交易所给的是秒级时间戳,有些是毫秒级。如果不统一,排序和计算都会出错。我统一用毫秒级存储。
- 盘前盘后数据: 除非你专门做盘前盘后策略,否则建议剔除。这些时段流动性差,数据质量也低。
时间戳处理看似简单,但细节决定成败。希望今天的分享能帮你少踩几个坑。
公众号:蓝海数据掘金营,微信deep3321