日期时间管理#

1.5.0版本之前backtrader *使用了一种直接的时间管理方法,即以 数据来源*计算的任何日期时间都是直接使用的。

在任何用户输入方面都是如此,例如在 参数 fromdate (或 sessionstart )可以提供给任何* 数据来源*

这种方法在进行回测时没有问题。可以很容易地假设输入的日期时间在它们进入系统之前已经得到了处理。

但是从1.5.0开始,支持 实时数据来源 ,这就迫使我们考虑 日期时间管理 。如果始终满足以下条件,则不需要进行这种管理:

  • 纽约的交易员交易ES-Mini期货。它们的时区都是 US/Eastern (或其别名之一)

  • 柏林的交易员交易DAX期货。在这种情况下,适用于 CET (或 Europe/Berling )时区

上述的直接输入输出日期时间方法将起作用,因为例如在柏林的交易者可以始终执行类似以下这样的操作:

class Strategy(bt.Strategy):

def next(self):# DAX 期货于中欧时间08:00开盘

if self.data.datetime.time() < datetime.time(8, 30):

# 在市场运行30分钟之前不进行操作 return #

直接方法的问题出现在当柏林的交易员决定交易“ES-Mini”时。因为从夏令时(DST)修改的时间点在一年中的不同时间,并且这导致了一年中有几周的时间差不一致。下面的方法不总是有效: class Strategy(bt.Strategy):

def next(self):

# SPX指数全年都在美国/东部时间9:30开盘 # 这对应大部分时间在中欧时间15:30 # 但如果美国发生守时调整(DST),而欧洲没有发生守时调整,则会变为中欧时间16:30或14:30

# 这就是为什么下面的代码是不可靠的

if self.data.datetime.time() < datetime.time(16, 0):

# 在市场运行30分钟之前不进行操作 return #

时区操作#

为了解决上述情况并仍然与直接输入输出时间方法兼容, backtrader 向最终用户提供以下解决方案

时间日期输入 ==============- 作为默认设置,平台不会修改数据源提供的 datetime 数据。

  • 最终用户可以通过以下方式覆盖此输入:

    • 为数据源提供一个 tzinput 参数。这必须是一个与 datetime.tzinfo 接口兼容的对象。用户很可能提供一个 pytz.timezone 实例。

根据这个决定, backtrader 内部使用的时间被认为是以 UTC 格式为基准的,即:

  • 如果数据源已经以 UTC 格式存储它。

  • 在通过 tzinput 进行转换之后。

  • 实际上它并不是真正的 UTC ,但它是用户的参考,因此称为 UTC-like

Datetime输出#

  • 如果数据源可以自动确定输出的时区,那么这将是默认设置。

    这在直播数据源的情况下是有意义的,特别是在像一个柏林( 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”,表示直接输入输出的 datetime

考虑到这一切,让我们回顾一下在“US/Eastern”进行交易的柏林交易者:

import pytz

import bt

data = bt.feeds.MyFeed('ES-Mini', tz=pytz.timezone('US/Eastern'))```python

class Strategy(bt.Strategy):

def next(self):

# 全年有效的方法 # 数据源以’US/Eastern’时区返回,并且用户引用’10:00’作为参考时间 # 因为在’US/Eastern’时区,标普指数始终在09:30开始交易,所以这个方法总是有效的

if self.data.datetime.time() < datetime.time(10, 0):

# 直到市场运行了30分钟才进行操作 return #

在自动确定输出时区的 数据源 的情况下:

```python import bt

data = bt.feeds.MyFeedAutoTZ(‘ES-Mini’)

class Strategy(bt.Strategy):

def next(self):

# 全年有效的方法 # 数据源以’US/Eastern’时区返回,并且用户引用’10:00’作为参考时间 # 因为在’US/Eastern’时区,标普指数始终在09:30开始交易,所以这个方法总是有效的

```if self.data.datetime.time() < datetime.time(10, 0):

# 在市场运行30分钟之前不进行操作 return #

比上面的工作量还少。

显然,上面示例中的“MyFeed”和“MyFeedAuto”只是虚拟名称。

注意

写作时,分发包中唯一能够自动确定时区的数据源是连接到 Interactive Brokers 的数据源。