计时器#
在 backtrader 中,版本 1.9.44.116
新增了 计时器 这个功能,这个功能可以在指定的时间点通过 notify_timer
(在 Cerebro
和 Strategy
中可用)回调,并提供了细粒度的终端用户控制。
注意
在 1.9.46.116
中进行了一些修正
选项#
基于绝对时间输入的计时器,或者基于会话的开始/结束时间
时间规范的时区指定,可以直接指定或使用 pytz 兼容对象或数据源会话结束时间
与指定时间的起始偏移量
重复间隔
周日筛选器(带有传递选项)
月日筛选器(带有传递选项) - 自定义回调过滤器
使用模式#
在 Cerebro
和 Strategy
子类中,计时器回调将会在以下方法中接收到。
def notify_timer(self, timer, when, *args, **kwargs):
'''接收一个计时器通知,其中 ``timer`` 是由 ``add_timer`` 返回的计时器,
``when`` 是调用时间。 ``args`` 和 ``kwargs`` 是传递给 ``add_timer`` 的
任何附加参数。
实际的 ``when`` 时间可能稍晚,但系统可能未能在此之前调用计时器。该值是计时器的
时间值而不是系统时间。
'''
添加计时器 - 通过策略#
使用以下方法进行操作
def add_timer(self, when,
offset=datetime.timedelta(), repeat=datetime.timedelta(),
weekdays=[], weekcarry=False,
monthdays=[], monthcarry=True,
allow=None,
tzdata=None, cheat=False,
*args, **kwargs):
'''
它返回一个创建的 Timer
实例。
请参阅下文以了解参数的解释。添加计时器 - 通过Cerebro#
使用相同的方法并添加了参数 strats
。如果设置为 True
,计时器不仅会通知 cerebro ,还会通知系统中所有运行的策略。
def add_timer(self, when,
offset=datetime.timedelta(), repeat=datetime.timedelta(),
weekdays=[], weekcarry=False,
monthdays=[], monthcarry=True,
allow=None,
tzdata=None, cheat=False, strats=False,
*args, **kwargs):
'''
它返回创建的 Timer
实例。
计时器何时被调用#
如果 cheat=False
#
这是默认设置。在这种情况下,计时器将在以下情况下被调用:
在数据源加载当前柱的新值之后
在经纪人评估订单并重新计算投资组合价值之后
在指标重新计算之前(因为这是由策略触发的) - 在调用任何策略的
next
方法之前
如果 cheat=True
#
在这种情况下会调用一个计时器:
在数据源加载了当前K线的新值之后
在经纪人评估订单并重新计算投资组合价值之前
因此,在指标重新计算和调用任何策略的
next
方法之前
这允许例如以下日线K线的情景:
在经纪人评估新的K线之前,计时器被调用
指标在前一天的收盘价上有值,并可以用于生成入场/出场信号(或在上次“next”评估时可能已设置标志)
由于新的价格可用,可以使用开盘价计算头寸。这假设例如通过观察开盘竞价可以获得关于开盘价的良好指示。使用日线进行回测
示例 scheduled.py
默认使用 backtrader 分发的标准日线进行回测。策略的参数如下:
class St(bt.Strategy):
params = dict(
when=bt.timer.SESSION_START,
timer=True,
cheat=False,
offset=datetime.timedelta(),
repeat=datetime.timedelta(),
weekdays=[],
)
数据的交易时间如下:
开市时间:09:00
收市时间:17:30
只使用特定时间进行回测
$ ./scheduled.py --strat when='datetime.time(15,30)'
strategy notify_timer with tid 0, when 2005-01-03 15:30:00 cheat False
1, 2005-01-03 17:30:00, 第1周, 第1天, 开盘价 2952.29, 最高价 2989.61, 最低价 2946.8, 收盘价 2970.02
strategy notify_timer with tid 0, when 2005-01-04 15:30:00 cheat False
2, 2005-01-04 17:30:00, 第1周, 第2天, 开盘价 2969.78, 最高价 2979.88, 最低价 2961.14, 收盘价 2971.12
strategy notify_timer with tid 0, when 2005-01-05 15:30:00 cheat False
3, 2005-01-05 17:30:00, 第1周, 第3天, 开盘价 2969.0, 最高价 2969.0, 最低价 2942.69, 收盘价 2947.19
strategy notify_timer with tid 0, when 2005-01-06 15:30:00 cheat False
...
如上所述,定时器在 15:30
开始计时。没有什么意外。现在我们加上一个偏移量,为30分钟。
$ ./scheduled.py --strat when='datetime.time(15,30)',offset='datetime.timedelta(minutes=30)'策略 notify_timer,tid 0,在 2005-01-03 16:00:00 时触发,作弊为 False
1,2005-01-03 17:30:00,第一周,第一天,O 2952.29,H 2989.61,L 2946.8,C 2970.02 策略 notify_timer,tid 0,在 2005-01-04 16:00:00 时触发,作弊为 False 2,2005-01-04 17:30:00,第一周,第二天,O 2969.78,H 2979.88,L 2961.14,C 2971.12 策略 notify_timer,tid 0,在 2005-01-05 16:00:00 时触发,作弊为 False …
并且计时器的时间从 15:30
改为 16:00
。没有意外。让我们尝试相同的操作,但是使用会话开始时间作为参照。
$ ./scheduled.py --strat when='bt.timer.SESSION_START',offset='datetime.timedelta(minutes=30)'
策略 notify_timer,tid 0,在 2005-01-03 09:30:00 时触发,作弊为 False
1,2005-01-03 17:30:00,第一周,第一天,O 2952.29,H 2989.61,L 2946.8,C 2970.02
策略 notify_timer,tid 0,在 2005-01-04 09:30:00 时触发,作弊为 False
2,2005-01-04 17:30:00,第一周,第二天,O 2969.78,H 2979.88,L 2961.14,C 2971.12
...
Et voilá! 回调函数被调用的时间是 09:30
。而会话开始时间,如上所述,是 09:00
。这使得可以简单地说,希望在会话开始后 30分钟 执行一个动作。
让我们加上重复:
$ ./scheduled.py --strat when='bt.timer.SESSION_START',offset='datetime.timedelta(minutes=30)',repeat='datetime.timedelta(minutes=30)'
策略 notify_timer,tid 0,在 2005-01-03 09:30:00 时触发,作弊为 False
1,2005-01-03 17:30:00,第一周,第一天,O 2952.29,H 2989.61,L 2946.8,C 2970.02
策略 notify_timer,tid 0,在 2005-01-04 09:30:00 时触发,作弊为 False
2,2005-01-04 17:30:00,第一周,第二天,O 2969.78,H 2979.88,L 2961.14,C 2971.12
策略 notify_timer,tid 0,在 2005-01-05 09:30:00 时触发,作弊为 False
...
没有重复发生 。原因是价格的分辨率是每天一次。计时器在 09:30
第一次调用,与之前的示例相同。但当系统获取下一批价格时,它们发生在下一天。计时器只能调用一次,这是显而易见的。所以需要更低的分辨率。
但在降低分辨率之前,让我们通过在会话结束之前调用计时器来作弊。 ::```
$ ./scheduled.py –strat when=’bt.timer.SESSION_START’,cheat=True
strategy notify_timer with tid 1, when 2005-01-03 09:00:00 cheat True – 2005-01-03 创建购买订单 strategy notify_timer with tid 0, when 2005-01-03 09:00:00 cheat False 1, 2005-01-03 17:30:00, 第一周,第一天,开盘价 2952.29,最高价 2989.61,最低价 2946.8,收盘价 2970.02 strategy notify_timer with tid 1, when 2005-01-04 09:00:00 cheat True strategy notify_timer with tid 0, when 2005-01-04 09:00:00 cheat False – 2005-01-04 以 2969.78 的价格执行购买交易 2, 2005-01-04 17:30:00, 第一周,第二天,开盘价 2969.78,最高价 2979.88,最低价 2961.14,收盘价 2971.12 strategy notify_timer with tid 1, when 2005-01-05 09:00:00 cheat True strategy notify_timer with tid 0, when 2005-01-05 09:00:00 cheat False …
该策略添加了一个 cheat=True
的第二个计时器。这是第二个添加的计时器,因此将获得第二个计时器ID( timer id ),即 1
(请参考上面的示例,分配的计时器ID为 0
)。
而且,由于这个计时器在系统中许多事件发生之前进行“作弊检测”,它会在其他计时器之前被调用(请参考上面的解释)。
由于价格的*每日*分辨率不会有太大的差异,除了:
该策略还会在开盘前下达订单……并且下一个交易日将与开盘价匹配
即使通过在开盘前行动进行作弊,这仍然是正常的行为,因为在经纪人中也没有激活 开盘作弊(cheating-on-open) 。
同样,对于经纪人,我们使用 coo=True
的命令:
```
$ ./scheduled.py –strat when=’bt.timer.SESSION_START’,cheat=True –broker coo=True
strategy notify_timer with tid 1, when 2005-01-03 09:00:00 cheat True – 2005-01-03 创建购买订单 strategy notify_timer with tid 0, when 2005-01-03 09:00:00 cheat False – 2005-01-03 以 2952.29 的价格执行购买交易 1, 2005-01-03 17:30:00, 第一周,第一天,开盘价 2952.29,最高价 2989.61,最低价 2946.8,收盘价 2970.02 strategy notify_timer with tid 1, when 2005-01-04 09:00:00 cheat True strategy notify_timer with tid 0, when 2005-01-04 09:00:00 cheat False 2, 2005-01-04 17:30:00, 第一周,第二天,开盘价 2969.78,最高价 2979.88,最低价 2961.14,收盘价 2971.12 strategy notify_timer with tid 1, when 2005-01-05 09:00:00 cheat True strategy notify_timer with tid 0, when 2005-01-05 09:00:00 cheat False …
在作弊计时器上发布的命令是于
2005-01-03
生效的在以开盘价执行的命令是于
2005-01-03
生效的实际上,就好像在市场真正开盘前几秒钟做了开盘竞价价格一样。
运行5分钟间隔的数据#
示例 scheduled-min.py
默认以 backtrader 发行版中提供的标准5分钟间隔数据运行。策略参数扩展了 monthdays
和 carry 选项
class St(bt.Strategy):
params = dict(
when=bt.timer.SESSION_START,
timer=True,
cheat=False,
offset=datetime.timedelta(),
repeat=datetime.timedelta(),
weekdays=[],
weekcarry=False,
monthdays=[],
monthcarry=True,
)
数据具有相同的交易时间:
开始时间:09:00
结束时间:17:30
让我们做一些实验。首先是一个单一的计时器。
:: $ ./scheduled-min.py --strat when='datetime.time(15, 30)'
1, 2006-01-02 09:05:00, 第 1 周, 第 1 天, 开盘价 3578.73, 最高价 3587.88, 最低价 3578.73, 收盘价 3582.99 2, 2006-01-02 09:10:00, 第 1 周, 第 1 天, 开盘价 3583.01, 最高价 3588.4, 最低价 3583.01, 收盘价 3588.03 … 77, 2006-01-02 15:25:00, 第 1 周, 第 1 天, 开盘价 3599.07, 最高价 3599.68, 最低价 3598.47, 收盘价 3599.68 策略通知计时器,ID 0,在 2006-01-02 15:30:00,作弊模式 没有 78, 2006-01-02 15:30:00, 第 1 周, 第 1 天, 开盘价 3599.64, 最高价 3599.73, 最低价 3599.0, 收盘价 3599.67 … 179, 2006-01-03 15:25:00, 第 1 周, 第 2 天, 开盘价 3634.72, 最高价 3635.0, 最低价 3634.06, 收盘价 3634.87 策略通知计时器,ID 0,在 2006-01-03 15:30:00,作弊模式 没有 180, 2006-01-03 15:30:00, 第 1 周, 第 2 天, 开盘价 3634.81, 最高价 3634.89, 最低价 3634.04, 收盘价 3634.23 …
计时器按照要求在 15:30
开始执行。日志显示了它在前两天期间执行的情况。
将 15分钟
的重复加入到混合中
$ ./scheduled-min.py --strat when='datetime.time(15, 30)',repeat='datetime.timedelta(minutes=15)'
...
74, 2006-01-02 15:10:00, 第 1 周, 第 1 天, 开盘价 3596.12, 最高价 3596.63, 最低价 3595.92, 收盘价 3596.63
75, 2006-01-02 15:15:00, 第 1 周, 第 1 天, 开盘价 3596.36, 最高价 3596.65, 最低价 3596.19, 收盘价 3596.65
76, 2006-01-02 15:20:00, 第 1 周, 第 1 天, 开盘价 3596.53, 最高价 3599.13, 最低价 3596.12, 收盘价 3598.9
77, 2006-01-02 15:25:00, 第 1 周, 第 1 天, 开盘价 3599.07, 最高价 3599.68, 最低价 3598.47, 收盘价 3599.68
策略通知计时器,ID 0,在 2006-01-02 15:30:00,作弊模式 没有
78, 2006-01-02 15:30:00, 第 1 周, 第 1 天, 开盘价 3599.64, 最高价 3599.73, 最低价 3599.0, 收盘价 3599.67
79, 2006-01-02 15:35:00, 第 1 周, 第 1 天, 开盘价 3599.61, 最高价 3600.29, 最低价 3599.52, 收盘价 3599.92
80, 2006-01-02 15:40:00, 第 1 周, 第 1 天, 开盘价 3599.96, 最高价 3602.06, 最低价 3599.76, 收盘价 3602.05
策略通知计时器,ID 0,在 2006-01-02 15:45:00,作弊模式 没有
81, 2006-01-02 15:45:00, 第 1 周, 第 1 天, 开盘价 3601.97, 最高价 3602.07, 最低价 3601.45, 收盘价 3601.83
82, 2006-01-02 15:50:00, 第 1 周, 第 1 天, 开盘价 3601.74, 最高价 3602.8, 最低价 3601.63, 收盘价 3602.8
83, 2006-01-02 15:55:00, 第 1 周, 第 1 天, 开盘价 3602.53, 最高价 3602.74, 最低价 3602.33, 收盘价 3602.61
策略通知计时器,ID 0,在 2006-01-02 16:00:00,作弊模式 没有
84, 2006-01-02 16:00:00, 第 1 周, 第 1 天, 开盘价 3602.58, 最高价 3602.75, 最低价 3601.81, 收盘价 3602.14
85, 2006-01-02 16:05:00, 第 1 周, 第 1 天, 开盘价 3602.16, 最高价 3602.16, 最低价 3600.86, 收盘价 3600.96
86, 2006-01-02 16:10:00, 第 1 周, 第 1 天, 开盘价 3601.2, 最高价 3601.49, 最低价 3600.94, 收盘价 3601.27
...
策略通知计时器,ID 0,在 2006-01-02 17:15:00,作弊模式 没有
99, 2006-01-02 17:15:00, 第 1 周, 第 1 天, 开盘价 3603.96, 最高价 3603.96, 最低价 3602.89, 收盘价 3603.79
100, 2006-01-02 17:20:00, 第 1 周, 第 1 天, 开盘价 3603.94, 最高价 3605.95, 最低价 3603.87, 收盘价 3603.91
101, 2006订单的创建时间是 ``09:05:00`` ,执行时间是 ``09:10:00`` ,因为经纪人不处于 *cheat-on-open* 模式。让我们设置它...
$ ./scheduled-min.py --strat when='bt.timer.SESSION_START',cheat=True --broker coo=True
strategy notify_timer with tid 1, when 2006-01-02 09:00:00 cheat True
-- 2006-01-02 09:05:00 创建买入订单
strategy notify_timer with tid 0, when 2006-01-02 09:00:00 cheat False
-- 2006-01-02 09:05:00 买入执行 @ 3578.73
1, 2006-01-02 09:05:00, 第一周, 第一天, 开盘价 3578.73, 最高价 3587.88, 最低价 3578.73, 收盘价 3582.99
2, 2006-01-02 09:10:00, 第一周, 第一天, 开盘价 3583.01, 最高价 3588.4, 最低价 3583.01, 收盘价 3588.03
...
发行时间和执行时间都是 09:05:00
,执行价是 09:05:00
的开盘价。
附加场景#
通过传递一个包含星期几的列表(按照 ISO 规范,星期一为 1,星期日为 7)来指定定时器在哪些天执行,例如:
weekdays=[5]
表示定时器仅在星期五有效。如果星期五不是交易日,定时器应在下一个交易日开始计时,可以添加
weekcarry=True
类似地,可以决定在每个月的第15天采取行动,例如:
monthdays=[15]
如果第15天恰好是非交易日,计时器应该在下一个交易日启动,可以添加monthcarry=True
。
对于类似于“三月、六月、九月和十二月的第三个星期五”(期货/期权到期日)这样的事物,还没有实现,但可以通过传递以下规则来实现:
传入
allow=callable
,其中可调用的函数接受datetime.date
实例。请注意,这不是一个datetime.datetime
实例,因为 allow 可调用函数只是为了决定某一天是否适合用作计时器。
要实现以上规则的功能,可以使用以下代码:
```python class FutOpExp(object):
- def __init__(self):
self.fridays = 0 self.curmonth = -1
- def __call__(self, d):
_, _, isowkday = d.isocalendar()
- if d.month != self.curmonth:
self.curmonth = d.month self.fridays = 0
# Mon=1 … Sun=7 if isowkday == 5 and self.curmonth in [3, 6, 9, 12]:
self.fridays += 1
- if self.fridays == 3: # 第三个星期五
return True # 允许计时器
return False # 不允许计时器
```创建计时器时,可以将``allow=FutOpeExp()``传递给它的参数。
这将允许在那些月份的第三个星期五启动计时器,并且可能在期货到期前平仓。
add_timer
的参数#
when
:可以是
datetime.time
实例(参见下面的tzdata
)
bt.timer.SESSION_START
用于引用会话开始
bt.timer.SESSION_END
用于引用会话结束
offset
必须是一个datetime.timedelta
实例用于对
when
的值进行偏移。它在与SESSION_START
和SESSION_END
组合使用时具有有意义的用途,可以表示会话开始后的15分钟
调用计时器。
repeat
必须是一个datetime.timedelta
实例指示在第一次调用后,进一步的调用是否将在同一会话中按预定的
repeat
时间间隔进行安排。一旦计时器超过会话结束,它将重置为
when
的初始值。 -weekdays
:一个 有序 的可迭代对象,其中的整数表示计时器可以在哪些日子(ISO代码,星期一为1,星期日为7)实际被调用如果没有指定,计时器将在所有日子上都有效
weekcarry
(默认为False
)。如果为True
,并且未观察到工作日(如交易假期),则计时器将在下一个工作日执行(即使是新的一周)
monthdays
: 一个 有序 的可迭代对象,其中的整数表示计时器必须在每个月的哪些日子执行。例如,始终在每个月的第15天执行如果没有指定,计时器将在所有日子上都有效
monthcarry
(默认为True
)。如果未观察到该天(周末,交易假期),则计时器将在下一个可用日执行。
allow
(默认为None
)。一个回调函数,接收一个datetime.date
实例,并在该日期允许计时器时返回True
,否则返回False
tzdata
可以是None
(默认值),pytz
实例或data feed
实例。
None
:when
按面值解释(即使它的时区不是UTC,也会将其视为UTC)
pytz
实例:when
将被解释为由时区实例指定的本地时间。“data feed” 实例:when
将被解释为数据源实例的tz
参数指定的本地时间。
注意 :如果 when
是 SESSION_START
或 SESSION_END
并且 tzdata
是 None
,则系统中的第一个 数据源 (即 self.data0
)将被用作查找会话时间的参考。
strats
(默认值:False
)同时调用策略的notify_timer
。cheat
(默认值:False
)如果为True
,则计时器将在经纪人有机会评估订单之前被调用。这为在会话开始之前基于开盘价发出订单提供了机会。*args
:任何额外的 args 将传递给notify_timer
。**kwargs
:任何额外的 kwargs 将传递给notify_timer
。
示例用法 scheduled.py
#
$ ./scheduled.py --help
用法:scheduled.py [-h] [--data0 DATA0] [--fromdate FROMDATE]
[--todate TODATE] [--cerebro kwargs] [--broker kwargs]
[--sizer kwargs] [--strat kwargs] [--plot [kwargs]]
样例框架
可选参数:
-h, --help 显示帮助信息并退出
--data0 DATA0 要读取的数据(默认值:../../datas/2005-2006-day-001.txt)
--fromdate FROMDATE 以YYYY-MM-DD[THH:MM:SS]格式的日期[时间](默认值:)
--todate TODATE 以YYYY-MM-DD[THH:MM:SS]格式的日期[时间](默认值:)
--cerebro kwargs 以 key=value 格式的 kwargs(默认值:)
--broker kwargs 以 key=value 格式的 kwargs(默认值:)
--sizer kwargs 以 key=value 格式的 kwargs(默认值:)
--strat kwargs 以 key=value 格式的 kwargs(默认值:)
--plot [kwargs] 以 key=value 格式的 kwargs(默认值:)
示例用法 scheduled-min.py
#
- :: $ ./scheduled-min.py –help
- 用法: scheduled-min.py [-h] [–data0 DATA0] [–fromdate FROMDATE]
[–todate TODATE] [–cerebro kwargs] [–broker kwargs] [–sizer kwargs] [–strat kwargs] [–plot [kwargs]]
定时器测试日内
- 可选参数:
- -h, --help
显示帮助信息并退出
- --data0 DATA0
要读取的数据 (默认: ../../datas/2006-min-005.txt)
- --fromdate FROMDATE
日期[时间],格式为YYYY-MM-DD[THH:MM:SS] (默认: )
- --todate TODATE
日期[时间],格式为YYYY-MM-DD[THH:MM:SS] (默认: )
- --cerebro kwargs
以key=value格式的kwargs (默认: )
- --broker kwargs
以key=value格式的kwargs (默认: )
- --sizer kwargs
以key=value格式的kwargs (默认: )
- --strat kwargs
以key=value格式的kwargs (默认: )
–plot [kwargs] 以key=value格式的kwargs (默认: )
样例源码 scheduled.py
#
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import datetime
import backtrader as bt
class St(bt.Strategy):
params = dict(
when=bt.timer.SESSION_START,
timer=True,
cheat=False,
offset=datetime.timedelta(),
repeat=datetime.timedelta(),
weekdays=[],
)
def __init__(self):
bt.ind.SMA()
if self.p.timer:
self.add_timer(
when=self.p.when,
offset=self.p.offset,
repeat=self.p.repeat,
weekdays=self.p.weekdays,
)
if self.p.cheat:
self.add_timer(
when=self.p.when,
offset=self.p.offset,
repeat=self.p.repeat,
cheat=True,
)
self.order = None
def prenext(self):
self.next()
def next(self):
_, isowk, isowkday = self.datetime.date().isocalendar()
txt = '{}, {}, Week {}, Day {}, O {}, H {}, L {}, C {}'.format(
len(self), self.datetime.datetime(),
isowk, isowkday,
self.data.open[0], self.data.high[0],
self.data.low[0], self.data.close[0])
print(txt)
def notify_timer(self, timer, when, *args, **kwargs):
print('strategy notify_timer with tid {}, when {} cheat {}'.
format(timer.p.tid, when, timer.p.cheat))
if self.order is None and timer.p.cheat:
print('-- {} Create buy order'.format(self.data.datetime.date()))
self.order = self.buy()
def notify_order(self, order):
if order.status == order.Completed:
print('-- {} Buy Exec @ {}'.format(
self.data.datetime.date(), order.executed.price))
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
# Data feed kwargs
kwargs = dict(
timeframe=bt.TimeFrame.Days,
compression=1,
sessionstart=datetime.time(9, 0),
sessionend=datetime.time(17, 30),
)
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
kwargs[d] = datetime.datetime.strptime(a, strpfmt)
# Data feed
data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
# Strategy
cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
if args.plot: # Plot if requested to
cerebro.plot(**eval('dict(' + args.plot + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'Sample Skeleton'
)
)
parser.add_argument('--data0', default='../../datas/2005-2006-day-001.txt',
required=False, help='Data to read in')
# Defaults for dates
parser.add_argument('--fromdate', required=False, default='',
help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
parser.add_argument('--todate', required=False, default='',
help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
parser.add_argument('--cerebro', required=False, default='',
metavar='kwargs', help='kwargs in key=value format')
parser.add_argument('--broker', required=False, default='',
metavar='kwargs', help='kwargs in key=value format')
parser.add_argument('--sizer', required=False, default='',
metavar='kwargs', help='kwargs in key=value format')
parser.add_argument('--strat', required=False, default='',
metavar='kwargs', help='kwargs in key=value format')
parser.add_argument('--plot', required=False, default='',
nargs='?', const='{}',
metavar='kwargs', help='kwargs in key=value format')
return parser.parse_args(pargs)
if __name__ == '__main__':
runstrat()
样例源码 scheduled-min.py
#
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import datetime
import backtrader as bt
class St(bt.Strategy):
params = dict(
when=bt.timer.SESSION_START,
timer=True,
cheat=False,
offset=datetime.timedelta(),
repeat=datetime.timedelta(),
weekdays=[],
weekcarry=False,
monthdays=[],
monthcarry=True,
)
def __init__(self):
bt.ind.SMA()
if self.p.timer:
self.add_timer(
when=self.p.when,
offset=self.p.offset,
repeat=self.p.repeat,
weekdays=self.p.weekdays,
weekcarry=self.p.weekcarry,
monthdays=self.p.monthdays,
monthcarry=self.p.monthcarry,
# tzdata=self.data0,
)
if self.p.cheat:
self.add_timer(
when=self.p.when,
offset=self.p.offset,
repeat=self.p.repeat,
weekdays=self.p.weekdays,
weekcarry=self.p.weekcarry,
monthdays=self.p.monthdays,
monthcarry=self.p.monthcarry,
# tzdata=self.data0,
cheat=True,
)
self.order = None
def prenext(self):
self.next()
def next(self):
_, isowk, isowkday = self.datetime.date().isocalendar()
txt = '{}, {}, Week {}, Day {}, O {}, H {}, L {}, C {}'.format(
len(self), self.datetime.datetime(),
isowk, isowkday,
self.data.open[0], self.data.high[0],
self.data.low[0], self.data.close[0])
print(txt)
def notify_timer(self, timer, when, *args, **kwargs):
print('strategy notify_timer with tid {}, when {} cheat {}'.
format(timer.p.tid, when, timer.p.cheat))
if self.order is None and timer.params.cheat:
print('-- {} Create buy order'.format(
self.data.datetime.datetime()))
self.order = self.buy()
def notify_order(self, order):
if order.status == order.Completed:
print('-- {} Buy Exec @ {}'.format(
self.data.datetime.datetime(), order.executed.price))
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
# Data feed kwargs
kwargs = dict(
timeframe=bt.TimeFrame.Minutes,
compression=5,
sessionstart=datetime.time(9, 0),
sessionend=datetime.time(17, 30),
)
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
kwargs[d] = datetime.datetime.strptime(a, strpfmt)
# Data feed
data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
# Strategy
cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
if args.plot: # Plot if requested to
cerebro.plot(**eval('dict(' + args.plot + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'Timer Test Intraday'
)
)
parser.add_argument('--data0', default='../../datas/2006-min-005.txt',
required=False, help='Data to read in')
# Defaults for dates
parser.add_argument('--fromdate', required=False, default='',
help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
parser.add_argument('--todate', required=False, default='',
help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
parser.add_argument('--cerebro', required=False, default='',
metavar='kwargs', help='kwargs in key=value format')
parser.add_argument('--broker', required=False, default='',
metavar='kwargs', help='kwargs in key=value format')
parser.add_argument('--sizer', required=False, default='',
metavar='kwargs', help='kwargs in key=value format')
parser.add_argument('--strat', required=False, default='',
metavar='kwargs', help='kwargs in key=value format')
parser.add_argument('--plot', required=False, default='',
nargs='?', const='{}',
metavar='kwargs', help='kwargs in key=value format')
return parser.parse_args(pargs)
if __name__ == '__main__':
runstrat()