Source code for backtrader.indicators.zlind

#!/usr/bin/env python
"""Zero Lag Indicator Module - Zero-lag error correction.

This module provides the ZeroLagIndicator developed by John Ehlers
and Ric Way to reduce lag in moving averages.

Classes:
    ZeroLagIndicator: Zero-lag indicator with error correction.

Example:
    class MyStrategy(bt.Strategy):
        def __init__(self):
            self.zlind = bt.indicators.ZeroLagIndicator(self.data.close, period=20, gainlimit=50)

        def next(self):
            # Price above ZeroLagIndicator indicates uptrend
            if self.data.close[0] > self.zlind[0]:
                self.buy()
            # Price below ZeroLagIndicator indicates downtrend
            elif self.data.close[0] < self.zlind[0]:
                self.sell()
"""

from backtrader.utils.py3 import MAXINT

from . import MovingAverageBase
from .ema import EMA


[docs] class ZeroLagIndicator(MovingAverageBase): """By John Ehlers and Ric Way The zero-lag indicator (ZLIndicator) is a variation of the EMA which modifies the EMA by trying to minimize the error (distance price - error correction) and thus reduce the lag Formula: - EMA(data, period) - For each iteration calculate a best-error-correction of the ema (see the paper and/or the code) iterating over ``-bestgain`` -> ``+bestgain`` for the error correction factor (both incl.) - The default moving average 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`` in the instance See also: - http://www.mesasoftware.com/papers/ZeroLag.pdf """ alias = ( "ZLIndicator", "ZLInd", "EC", "ErrorCorrecting", ) lines = ("ec",) params = ( ("gainlimit", 50), ("_movav", EMA), ) def _plotlabel(self): plabels = [self.p.period, self.p.gainlimit] plabels += [self.p._movav] * self.p.notdefault("_movav") return plabels def __init__(self): """Initialize the Zero Lag Indicator. Creates EMA and sets up gain limits for error correction. """ self.ema = self.p._movav(period=self.p.period) self.limits = [-self.p.gainlimit, self.p.gainlimit + 1] # To make mixins work - super at the end for cooperative inheritance super().__init__()
[docs] def next(self): """Calculate zero lag indicator for the current bar. Iterates over gain values to find the error correction that minimizes the difference between price and corrected EMA. """ leasterror = MAXINT # 1000000 in original code bestec = ema = self.ema[0] # seed value 1st time for ec price = self.data[0] ec1 = self.lines.ec[-1] alpha, alpha1 = self.ema.alpha, self.ema.alpha1 for value1 in range(*self.limits): gain = value1 / 10 ec = alpha * (ema + gain * (price - ec1)) + alpha1 * ec1 error = abs(price - ec) if error < leasterror: leasterror = error bestec = ec self.lines.ec[0] = bestec