zipline-trader数据摄入datetime处理报TypeError及NaT问题修复问询
最初假设可通过乘以1e9的操作为datetime对象补充毫秒精度(该假设存在错误),相关代码及运行结果如下:
- 执行
print(df.index)输出原始索引信息:
Index(['2022-04-04T04:00:00Z', '2022-04-05T04:00:00Z'], dtype='object', name='time')
- 第一版索引转换代码:
df.index = pd.to_datetime(df.index) df.index = pd.to_datetime((df.index * 1e9).astype('int64'), utc = True).tz_convert(NY)
运行代码后抛出TypeError异常,错误栈指向/opt/anaconda3/envs/python3-6-13/lib/python3.6/site-packages/alpaca_trade_api/entity.py文件第137行,核心报错信息为TypeError: cannot perform __mul__ with this index type: Index,即当前Index类型不支持乘法运算。
- 调整后的第二版转换代码:
df.index = pd.to_datetime((df.index.astype(np.int64) * 1e9).astype('int64'), utc = True).tz_convert(NY)
修改后执行转换,所有datetime结果均为NaT,输出索引为:
DatetimeIndex(['NaT', 'NaT'], dtype='datetime64[ns, America/New_York]', name='time', freq=None)
问题触发位置为alpaca_trade_api的entity.py文件。
- 第一版代码报错原因:原始索引是存储ISO时间字符串的object类型Index,第一行
pd.to_datetime(df.index)的赋值在alpaca实体类的封装逻辑下没有成功将索引转为DatetimeIndex,仍然保留object类型,object类型索引不支持和数值直接做乘法运算,因此抛出类型错误。 - 第二版代码全返回NaT原因:直接对存储字符串的object索引执行
astype(np.int64)时,时间字符串无法被直接解析为整数,转换结果全为无效值,后续的乘法、转datetime操作自然只能得到NaT。 - 核心逻辑错误:乘以1e9补充毫秒精度的操作,仅适用于存储为秒级Unix时间戳的数值型数据,当前原始索引是ISO标准格式的时间字符串,并非数值型时间戳,这套乘法转换逻辑从适用场景上就不匹配。
不需要做多余的时间戳乘法转换,pd.to_datetime原生支持直接解析带Z后缀的UTC时区ISO格式时间字符串,解析完成后直接做时区转换即可,正确代码如下:
import pandas as pd # 提前确保NY时区对象定义正确,示例定义方式: # from pytz import timezone # NY = timezone('America/New_York') # 直接解析字符串为UTC时区的DatetimeIndex df.index = pd.to_datetime(df.index, utc=True) # 转换为纽约时区 df.index = df.index.tz_convert(NY)
如果需要强制设置毫秒精度,可在解析完成后通过类型转换实现,不需要手动做单位乘法:
# 强制转换为毫秒精度后再做时区转换 df.index = pd.to_datetime(df.index, utc=True).astype('datetime64[ms]').tz_convert(NY)
执行后可正常得到时区正确、无NaT的DatetimeIndex,不会触发entity.py中的类型报错。
内容的提问来源于stack exchange,提问作者Huy Nguyen

