backtrader.indicators.dema 源代码
#!/usr/bin/env python
"""DEMA/TEMA Indicator Module - Double/Triple Exponential Moving Average.
This module provides DEMA and TEMA indicators introduced by Patrick G. Mulloy
in 1994 to reduce the lag associated with traditional moving averages.
Classes:
DoubleExponentialMovingAverage: DEMA indicator (alias: DEMA).
TripleExponentialMovingAverage: TEMA indicator (alias: TEMA).
Example:
class MyStrategy(bt.Strategy):
def __init__(self):
self.dema = bt.indicators.DEMA(self.data.close, period=20)
def next(self):
if self.data.close[0] > self.dema[0]:
self.buy()
elif self.data.close[0] < self.dema[0]:
self.sell()
"""
import math
from . import MovingAverageBase
from .ema import EMA
[文档]
class DoubleExponentialMovingAverage(MovingAverageBase):
"""
DEMA was first time introduced in 1994, in the article "Smoothing Data with
Faster-Moving Averages" by Patrick G. Mulloy in "Technical Analysis of
Stocks & Commodities" magazine.
It attempts to reduce the inherent lag associated with Moving Averages
Formula:
- dema = (2.0 - ema(data, period) - ema(ema(data, period), period)
See:
(None)
"""
alias = (
"DEMA",
"MovingAverageDoubleExponential",
)
lines = ("dema",)
params = (("_movav", EMA),)
def __init__(self):
"""Initialize the DEMA indicator.
Creates two EMAs for the DEMA calculation.
"""
super().__init__()
self.ema1 = self.p._movav(self.data, period=self.p.period)
self.ema2 = self.p._movav(self.ema1, period=self.p.period)
# minperiod = 2 * period - 1 for DEMA
self._minperiod = max(self._minperiod, 2 * self.p.period - 1)
[文档]
def next(self):
"""Calculate DEMA for the current bar.
Formula: DEMA = 2 * EMA1 - EMA(EMA1)
"""
self.lines.dema[0] = 2.0 * self.ema1[0] - self.ema2[0]
[文档]
def once(self, start, end):
"""Calculate DEMA in runonce mode."""
ema1_array = self.ema1.lines[0].array
ema2_array = self.ema2.lines[0].array
larray = self.lines.dema.array
while len(larray) < end:
larray.append(0.0)
minperiod = 2 * self.p.period - 1
for i in range(min(minperiod - 1, len(ema1_array))):
if i < len(larray):
larray[i] = float("nan")
for i in range(minperiod - 1, min(end, len(ema1_array), len(ema2_array))):
ema1_val = ema1_array[i] if i < len(ema1_array) else 0.0
ema2_val = ema2_array[i] if i < len(ema2_array) else 0.0
if isinstance(ema1_val, float) and math.isnan(ema1_val):
larray[i] = float("nan")
elif isinstance(ema2_val, float) and math.isnan(ema2_val):
larray[i] = float("nan")
else:
larray[i] = 2.0 * ema1_val - ema2_val
# Triple Exponential Moving Average
[文档]
class TripleExponentialMovingAverage(MovingAverageBase):
"""
TEMA was first time introduced in 1994, in the article "Smoothing Data with
Faster-Moving Averages" by Patrick G. Mulloy in "Technical Analysis of
Stocks & Commodities" magazine.
It attempts to reduce the inherent lag associated with Moving Averages
Formula:
- ema1 = ema(data, period)
- ema2 = ema(ema1, period)
- ema3 = ema(ema2, period)
- tema = 3 * ema1 - 3 * ema2 + ema3
See:
(None)
"""
alias = (
"TEMA",
"MovingAverageTripleExponential",
)
lines = ("tema",)
params = (("_movav", EMA),)
def __init__(self):
"""Initialize the TEMA indicator.
Creates three EMAs for the TEMA calculation.
"""
super().__init__()
self.ema1 = self.p._movav(self.data, period=self.p.period)
self.ema2 = self.p._movav(self.ema1, period=self.p.period)
self.ema3 = self.p._movav(self.ema2, period=self.p.period)
# minperiod = 3 * period - 2 for TEMA
self._minperiod = max(self._minperiod, 3 * self.p.period - 2)
[文档]
def next(self):
"""Calculate TEMA for the current bar.
Formula: TEMA = 3 * EMA1 - 3 * EMA2 + EMA3
"""
self.lines.tema[0] = 3.0 * self.ema1[0] - 3.0 * self.ema2[0] + self.ema3[0]
[文档]
def once(self, start, end):
"""Calculate TEMA in runonce mode."""
ema1_array = self.ema1.lines[0].array
ema2_array = self.ema2.lines[0].array
ema3_array = self.ema3.lines[0].array
larray = self.lines.tema.array
while len(larray) < end:
larray.append(0.0)
minperiod = 3 * self.p.period - 2
for i in range(min(minperiod - 1, len(ema1_array))):
if i < len(larray):
larray[i] = float("nan")
for i in range(minperiod - 1, min(end, len(ema1_array), len(ema2_array), len(ema3_array))):
ema1_val = ema1_array[i] if i < len(ema1_array) else 0.0
ema2_val = ema2_array[i] if i < len(ema2_array) else 0.0
ema3_val = ema3_array[i] if i < len(ema3_array) else 0.0
if isinstance(ema1_val, float) and math.isnan(ema1_val):
larray[i] = float("nan")
elif isinstance(ema2_val, float) and math.isnan(ema2_val):
larray[i] = float("nan")
elif isinstance(ema3_val, float) and math.isnan(ema3_val):
larray[i] = float("nan")
else:
larray[i] = 3.0 * ema1_val - 3.0 * ema2_val + ema3_val