Python的隐藏力量(1) – backtrader中文教程
只有在遇到backtrader的真实用户时,才能意识到平台中使用的抽象和 Python 功能是否有意义。
在不抛开 Pythonic 座右铭的情况下,反向交易者试图为用户提供尽可能多的控制权,同时通过将Python 提供的隐藏功能付诸行动来简化使用。
本系列的第一篇文章中的第一个示例。
它是一个数组还是它是什么?
一个非常简单的例子:
import backtrader as bt class MyStrategy(bt.Strategy): def __init__(self): self.hi_lo_avg = (self.data.high + self.data.low) / 2.0 def next(self): if self.hi_lo_avg[0] > another_value: print('we have a winner!') ... ... cerebro.addstrategy(MyStrategy) cerebro.run()
很快弹出的问题之一是:
- 不能也使用
[]
during__init__
吗?
之所以提出这个问题,是因为用户已经尝试过并且 Python 已停止运行并出现异常。
答案:
[]
不,在初始化期间不意味着使用。
接下来的问题是:
- 那么如果不是数组,实际存储
self.hi_lo_avg
的是什么?__init__
对于程序员来说,答案并不令人费解,但对于选择 Python 的算法交易员来说,这可能是一个谜
- 它是一个惰性求值的对象,它会
[]
在阶段通过算子计算并传递值cerebro.run
,即:在next
策略的方法中。
底线:在该next
方法中,数组索引运算符[]
将使您能够访问过去和当前时刻的计算值。
秘诀就在这里
运算符重载是真正的调味汁。让我们分解high-low-average的计算:
self.hi_lo_avg = (self.data.high + self.data.low) / 2.0
组件:
self.data.high
并且self.data.low
它们本身就是对象(反向交易者命名方案 中的行)
在许多情况下,它们被错误地视为纯数组,但事实并非如此。它们成为对象的原因:
- 在反向交易者中实施
0
和-1
索引计划 - 控制缓冲区大小和链接到其他对象
在这种情况下最重要的方面:
- 重写运算符以返回对象
这就是为什么下面的操作会返回一个lines对象。开始吧:
temp = self.data.high - self.data.low
然后将临时对象除以2.0
并分配给成员变量:
self.hi_lo_avg = temp / 2.0
这又返回另一个行对象。因为运算符覆盖不仅适用于直接在行对象之间执行的操作,还适用于例如这种除法之类的算术运算。
这意味着它self.hi_lo_avg
引用了lines对象。next
该对象在策略方法中或作为 指标或其他计算的输入很有用。
逻辑运算符示例
__init__
上面的示例在和 的组合期间和之后使用了算术运算符[0]
,>
在next
.
因为运算符重载不限于算术,让我们再举一个例子,在组合中添加一个指标。第一次尝试是:
import backtrader as bt class MyStrategy(bt.Strategy): def __init__(self): self.hi_lo_avg = (self.data.high + self.data.low) / 2.0 self.sma = bt.indicators.SMA(period=30) def next(self): if self.hi_lo_avg[0] > self.sma[0]: print('we have a winner!') ... ... cerebro.addstrategy(MyStrategy) cerebro.run()
但在这种情况下,只是从another_value
变为 self.sma[0]
。让我们改进它:
import backtrader as bt class MyStrategy(bt.Strategy): def __init__(self): self.hi_lo_avg = (self.data.high + self.data.low) / 2.0 self.sma = bt.indicators.SMA(period=30) def next(self): if self.hi_lo_avg > self.sma: print('we have a winner!') ... ... cerebro.addstrategy(MyStrategy) cerebro.run()
一个给好人的。运算符覆盖也可以使用next
,用户实际上可以删除[0]
并直接比较对象。
如果这一切都是可能的,那实际上似乎有点矫枉过正。但好在还有更多。看这个例子:
import backtrader as bt class MyStrategy(bt.Strategy): def __init__(self): hi_lo_avg = (self.data.high + self.data.low) / 2.0 sma = bt.indicators.SMA(period=30) self.signal = hi_lo_avg > sma def next(self): if self.signal: print('we have a winner!') ... ... cerebro.addstrategy(MyStrategy) cerebro.run()
我们做了两件事:
- 创建一个名为lines的对象
self.signal
,将 高低平均值与简单移动平均线的值进行比较如上所述,该对象在
next
计算时很有用 - 检查信号是否为 True 时,删除 next 中 [0] 的使用。 这是可能的,因为运算符也已被布尔运算覆盖
结论
希望这可以为执行操作时实际发生的__init__
情况以及操作员覆盖实际发生的情况提供一些启示。
评论被关闭。