backtrader的最初目标之一是:
- 能够快速制作指针原型以测试新想法
它不一定是一个完美的指针,但能够快速轻松地开发它们确实会有所帮助。为了确认设计是正确的,反向交易者标准库中的第一个指针是指数移动平均线(又名 EMA),其定义为:递归。
笔记
琐事:正如您想像的那样,第一个指针是 SimpleMovingAverage
由于如何开发递归指针的问题已发布在反向交易者社区中,让我们开发一个快速的ExponentialMovingAverage指针。
递归指针,如
- 它使用先前的值来计算当前值
例如,您可以在Wikipedia - Exponential Moving Average中查看数学
如果您有足够的勇气阅读所有内容,您就会发现该周期是用来计算指数平滑的。我们会使用它。
为了解决计算第一个值的难题,行业决定使用前一period值的简单平均值。
作为杠杆,我们将使用bt.indicators.PeriodN :
已经定义了一个
period参数通知框架最终用户使用的实际
period
参见其定义: Docs - Indicator Reference
然后让我们开发我们的EMA
import backtrader as bt
class EMA(bt.indicators.PeriodN):
params = {'period': 30} # even if defined, we can redefine the default value
lines = ('ema',) # our output line
def __init__(self):
self.alpha = 2.0 / (1.0 + self.p.period) # period -> exp smoothing factor
def nextstart(self): # calculate here the seed value
self.lines.ema[0] = sum(self.data.get(size=self.p.period)) / self.p.period
def next(self):
ema1 = self.lines.ema[-1] # previous EMA value
self.lines.ema[0] = ema1 * (1.0 - self.alpha) + self.data[0] * self.alpha
做起来几乎比说的容易。关键是在nextstart中提供种子值,其中
当达到指针的最短预热期时,将调用一次。
与
next不同,它将为传递到系统中的每个新数据值调用
nextstart的默认实现只是将任务委托给next ,对于大多数指针(例如简单移动平均线)来说,这是正确的做法。但在这种情况下,覆盖和提供种子值是关键。
沿着数据绘制
作为移动平均线,如果指针绘制在与其计算平均值的数据相同的轴上,那就太好了。因为我们继承自PeriodN ,所以绘图的默认值是(参见文档):
subplot=True
这当然意味着将为我们的指针创建一个subplot (图表上的另一个轴)。这很容易被覆盖。
import backtrader as bt
class EMA(bt.indicators.PeriodN):
plot = dict(subplot=False)
并做了。如果您想控制更多绘图选项,请查看Docs - Plotting
祝你好运!