日期时间管理
在发布1.5.0之前,backtrader使用了一种直接的时间管理方法,因为数据源计算的任何日期时间都只是按面值使用。
对于任何用户输入,如可提供给任何数据源的参数fromdate
(或sessionstart
)的情况,也是如此
考虑到对冻结的数据源进行回溯测试的直接控制,这种方法很好。很容易假设输入日期时间在进入系统之前已经处理好了。
但在 1.5.0 中,支持live数据源,这迫使我们考虑日期时间管理。如果以下情况始终为正确,则无需进行此类管理:
-
纽约的一位交易员交易 ES Mini。
US/Eastern
中两者的时区(或其中一个别名) -
柏林的一位交易员交易 DAX 期货。在这种情况下,
CET
(或Europe/Berling
时区均适用
上面的直接输入-输出日期时间方法是可行的,因为交易员(例如柏林的交易员)总是可以这样做:
class Strategy(bt.Strategy):
def next(self):
# The DAX future opens at 08:00 CET
if self.data.datetime.time() < datetime.time(8, 30):
# don't operate until the market has been running 30 minutes
return #
当柏林的同一位交易员决定交易ES-Mini
时,直接法的问题就出现了。因为从DST到的变化发生在一年中的不同时间点,这会导致时差在一年中的几周内不同步。以下情况并不总是有效:
class Strategy(bt.Strategy):
def next(self):
# The SPX opens at 09:30 US/Eastern all year long
# This is most of the year 15:30 CET
# But it is sometimes 16:30 CET or 14:30 CET if a DST switch on-off
# has happened in the USA and not in Europe
# That's why the code below is unreliable
if self.data.datetime.time() < datetime.time(16, 0):
# don't operate until the market has been running 30 minutes
return #
时区操作
为了解决上述情况,并且仍然与直接输入输出时间方法兼容,backtrader
向最终用户提供以下内容
日期时间输入
-
默认情况下,平台不会接触数据源提供的日期时间
-
最终用户可以通过以下方式覆盖此输入:
-
向数据源提供一个
tzinput
参数。这必须是与datetime.tzinfo
接口兼容的对象。用户很可能会提供一个pytz.timezone
实例
根据该决定,
backtrader
内部使用的时间被认为是UTC-like
格式,即:-
如果数据源已经以
UTC
格式存储 -
通过
tzinput
进行转换后 -
它不是真正的
UTC
,但它是用户的参考,因此UTC-like
-
日期时间输出
-
如果数据馈送可以自动确定输出的时区,这将是默认值
这在实时提要的情况下是有意义的,尤其是在柏林(
CET
时区)的交易员与US/Eastern
时区进行产品交易的用例中。因为交易者总是得到正确的时间,在上面的例子中,开盘时间在
09:30 US/Eastern
保持不变,而不是一年中的大部分时间15:30 CET
,但有时16:30 CET
有时14:30 CET
。 -
如果无法确定,则输出将是在输入期间(即
UTC-like
时间)确定的任何内容 -
最终用户可以覆盖并确定输出的实际时区
- 向数据源提供一个
tz
参数。这必须是与datetime.tzinfo
接口兼容的对象。用户很可能会提供一个pytz.timezone
实例
- 向数据源提供一个
笔记
来自用户的输入,例如参数fromdate
或sessionstart
预期与实际tz
同步,无论是由用户提供的数据源自动计算,还是作为默认值(None
,表示日期时间的直接输入输出)
考虑到这些,让我们回忆一下柏林交易员,他在US/Eastern
交易:
import pytz
import bt
data = bt.feeds.MyFeed('ES-Mini', tz=pytz.timezone('US/Eastern'))
class Strategy(bt.Strategy):
def next(self):
# This will work all year round.
# The data source will return in the frame of the 'US/Eastern' time
# zone and the user is quoting '10:00' as reference time
# Because in the 'US/Eastern' timezone the SPX index always starts
# trading at 09:30, this will always work
if self.data.datetime.time() < datetime.time(10, 0):
# don't operate until the market has been running 30 minutes
return #
对于能够自动确定输出时区的数据源:
import bt
data = bt.feeds.MyFeedAutoTZ('ES-Mini')
class Strategy(bt.Strategy):
def next(self):
# This will work all year round.
# The data source will return in the frame of the 'US/Eastern' time
# zone and the user is quoting '10:00' as reference time
# Because in the 'US/Eastern' timezone the SPX index always starts
# trading at 09:30, this will always work
if self.data.datetime.time() < datetime.time(10, 0):
# don't operate until the market has been running 30 minutes
return #
甚至比上面更少的工作。
显然,上面例子中的MyFeed
和MyFeedAuto
只是虚名。
笔记
在编写时,分发中唯一能够自动确定时区的数据源是连接到交互代理的数据源