我有同样的问题,至少关于
有没有一种由 Pandas 驱动的方法来生成一个 DatetimeIndex,比如说,5 分钟的频率,遵循交易时间的规则?
我在下面有一个答案,但首先,关于:
pandas 是否具备正确处理这种时间结构所需的能力?
“一起工作”这个词相当含糊。你想做什么“工作”?
Pandas 绝对可以在这种时间结构下正常工作,做一些事情,但也许不能做其他事情。
和关于。
例如,是否可以定义自定义交易时间 [9:30AM, 10:30AM, ... 3:30PM] ...?
答案是肯定的,但是我将在下面描述一些限制。也就是说,我将主要关注生成遵循交易时间和交易日规则的日期时间索引的能力,并在下面演示如何使用 pandas 来做到这一点。首先我会提到一些现有的 pandas 工具及其局限性。
我昨天晚上大部分时间都在研究这个。pandas 必须生成日期时间索引范围的大多数函数都接受输入频率freq
作为字符串(例如'15T'
15 分钟或'D'
每天)。
这些相同的函数通常也会接受pandas 时间序列偏移对象来代替频率。有许多不同类型的偏移量:每种都定义了一个可以有规则的频率,例如跳过周末(例如,offsets.BusinessDay )或仅针对营业时间(例如仅从上午 9 点到下午 5 点)生成日期时间索引。
我遇到的频率和偏移对象的主要问题是(在大多数情况下)没有办法将它们组合起来。
例如,使用BusinessHour 偏移类,我可以指定我想生成一个只包含营业时间(交易时间)的索引,我什至可以只在工作日(超过一堆日期)这样做,但我不能将它与指定频率,例如每分钟一次或每 15 分钟一次。相反,BusinessHour偏移类似乎默认为仅每小时一次的频率,并且我没有发现任何方法可以更改它。
或者,例如,我可以使用pandas.bdate_range()
指定频率'30T'
每 30 分钟生成一个索引点,但将包括非工作日。如果我将频率设置'B'
为仅工作日,那么它会跳过非工作日,但我每天只能获得一个索引点。我发现没有办法将这两个频率结合起来。
我想出的最简单的解决方案是生成一个工作日列表(交易日),然后循环遍历该列表,从开盘开始以所需的频率(1 分钟、5 分钟或 15 分钟)为每个日期生成一个索引直到每个日期的关闭时间。然后我使用 pandasDatetimeIndex.union_many()
方法将日期时间索引合并为一个。代码如下所示:
def trading_day_range(bday_start=None,bday_end=None,bday_freq='B',
open_time='09:30',close_time='16:00',iday_freq='15T',weekmask=None):
if bday_start is None: bday_start = pd.Timestamp.today()
if bday_end is None: bday_end = bday_start + pd.Timedelta(days=1)
daily = []
for d in pd.bdate_range(start=bday_start,end=bday_end,freq=bday_freq,weekmask=weekmask):
topen = pd.Timestamp(open_time)
d1 = d.replace(hour=topen.hour,minute=topen.minute)
tclose = pd.Timestamp(close_time)
d2 = d.replace(hour=tclose.hour,minute=tclose.minute+1)
daily.append(pd.date_range(d1,d2,freq=iday_freq))
index = daily[0].union_many(daily[1:])
return index
以下是一些使用它的示例:
ix = trading_day_range()
print('len(ix)=',len(ix))
print(ix[20:40])
print(ix[-20:])
len(ix)= 54
DatetimeIndex(['2021-04-13 14:30:00', '2021-04-13 14:45:00',
'2021-04-13 15:00:00', '2021-04-13 15:15:00',
'2021-04-13 15:30:00', '2021-04-13 15:45:00',
'2021-04-13 16:00:00', '2021-04-14 09:30:00',
'2021-04-14 09:45:00', '2021-04-14 10:00:00',
'2021-04-14 10:15:00', '2021-04-14 10:30:00',
'2021-04-14 10:45:00', '2021-04-14 11:00:00',
'2021-04-14 11:15:00', '2021-04-14 11:30:00',
'2021-04-14 11:45:00', '2021-04-14 12:00:00',
'2021-04-14 12:15:00', '2021-04-14 12:30:00'],
dtype='datetime64[ns]', freq=None)
DatetimeIndex(['2021-04-14 11:15:00', '2021-04-14 11:30:00',
'2021-04-14 11:45:00', '2021-04-14 12:00:00',
'2021-04-14 12:15:00', '2021-04-14 12:30:00',
'2021-04-14 12:45:00', '2021-04-14 13:00:00',
'2021-04-14 13:15:00', '2021-04-14 13:30:00',
'2021-04-14 13:45:00', '2021-04-14 14:00:00',
'2021-04-14 14:15:00', '2021-04-14 14:30:00',
'2021-04-14 14:45:00', '2021-04-14 15:00:00',
'2021-04-14 15:15:00', '2021-04-14 15:30:00',
'2021-04-14 15:45:00', '2021-04-14 16:00:00'],
dtype='datetime64[ns]', freq=None)
ix1 = trading_day_range('01/01/2021 09:30','01/13/2021 16:00',
bday_freq='C',iday_freq='30T',weekmask='Wed Thu Fri')
print('len(ix1)=',len(ix1))
print(ix1[20:40])
print(ix1[-20:])
len(ix1)= 70
DatetimeIndex(['2021-01-06 12:30:00', '2021-01-06 13:00:00',
'2021-01-06 13:30:00', '2021-01-06 14:00:00',
'2021-01-06 14:30:00', '2021-01-06 15:00:00',
'2021-01-06 15:30:00', '2021-01-06 16:00:00',
'2021-01-07 09:30:00', '2021-01-07 10:00:00',
'2021-01-07 10:30:00', '2021-01-07 11:00:00',
'2021-01-07 11:30:00', '2021-01-07 12:00:00',
'2021-01-07 12:30:00', '2021-01-07 13:00:00',
'2021-01-07 13:30:00', '2021-01-07 14:00:00',
'2021-01-07 14:30:00', '2021-01-07 15:00:00'],
dtype='datetime64[ns]', freq=None)
DatetimeIndex(['2021-01-08 13:30:00', '2021-01-08 14:00:00',
'2021-01-08 14:30:00', '2021-01-08 15:00:00',
'2021-01-08 15:30:00', '2021-01-08 16:00:00',
'2021-01-13 09:30:00', '2021-01-13 10:00:00',
'2021-01-13 10:30:00', '2021-01-13 11:00:00',
'2021-01-13 11:30:00', '2021-01-13 12:00:00',
'2021-01-13 12:30:00', '2021-01-13 13:00:00',
'2021-01-13 13:30:00', '2021-01-13 14:00:00',
'2021-01-13 14:30:00', '2021-01-13 15:00:00',
'2021-01-13 15:30:00', '2021-01-13 16:00:00'],
dtype='datetime64[ns]', freq=None)