backtrader.indicators.dma 源代码
#!/usr/bin/env python
"""DMA Indicator Module - Dickson Moving Average.
This module provides the Dickson Moving Average (DMA) developed
by Nathan Dickson, combining ZeroLag and Hull moving averages.
Classes:
DicksonMovingAverage: DMA indicator (aliases: DMA, DicksonMA).
Example:
class MyStrategy(bt.Strategy):
def __init__(self):
self.dma = bt.indicators.DMA(self.data.close, period=20, gainlimit=50, hperiod=7)
def next(self):
if self.data.close[0] > self.dma[0]:
self.buy()
elif self.data.close[0] < self.dma[0]:
self.sell()
"""
import math
from . import MovingAverageBase, ZeroLagIndicator
from .ema import EMA
from .hma import HMA
[文档]
class DicksonMovingAverage(MovingAverageBase):
"""By Nathan Dickson
The *Dickson Moving Average* combines the ``ZeroLagIndicator`` (aka
*ErrorCorrecting* or *EC*) by *Ehlers*, and the ``HullMovingAverage`` to
try to deliver a result close to that of the *Jurik* Moving Averages
Formula:
- ec = ZeroLagIndicator(period, gainlimit)
- hma = HullMovingAverage(hperiod)
- dma = (ec + hma) / 2
- The default moving average for the *ZeroLagIndicator* is EMA, but can
be changed with the parameter ``_movav``
::note:: the passed moving average must calculate alpha (and 1 - alpha)
and make them available as attributes ``alpha`` and ``alpha1``
- The second moving average can be changed from *Hull* to anything else with
the param *_hma*
See also:
- https://www.reddit.com/r/algotrading/comments/4xj3vh/dickson_moving_average
"""
alias = (
"DMA",
"DicksonMA",
)
lines = ("dma",)
params = (
("gainlimit", 50),
("hperiod", 7),
("_movav", EMA),
("_hma", HMA),
)
def _plotlabel(self):
plabels = [self.p.period, self.p.gainlimit, self.p.hperiod]
plabels += [self.p._movav] * self.p.notdefault("_movav")
plabels += [self.p._hma] * self.p.notdefault("_hma")
return plabels
def __init__(self):
"""Initialize the Dickson Moving Average.
Creates ZeroLag and Hull MA sub-indicators.
"""
super().__init__()
self.ec = ZeroLagIndicator(
period=self.p.period, gainlimit=self.p.gainlimit, _movav=self.p._movav
)
self.hull = self.p._hma(period=self.p.hperiod)
[文档]
def next(self):
"""Calculate DMA for the current bar.
Formula: DMA = (ZeroLag + HMA) / 2
"""
self.lines.dma[0] = (self.ec[0] + self.hull[0]) / 2.0
[文档]
def once(self, start, end):
"""Calculate DMA in runonce mode."""
ec_array = self.ec.lines[0].array
hull_array = self.hull.lines[0].array
larray = self.lines.dma.array
while len(larray) < end:
larray.append(0.0)
for i in range(start, min(end, len(ec_array), len(hull_array))):
ec_val = ec_array[i] if i < len(ec_array) else 0.0
hull_val = hull_array[i] if i < len(hull_array) else 0.0
if isinstance(ec_val, float) and math.isnan(ec_val):
larray[i] = float("nan")
elif isinstance(hull_val, float) and math.isnan(hull_val):
larray[i] = float("nan")
else:
larray[i] = (ec_val + hull_val) / 2.0