Source code for backtrader.indicators.contrib.bykov_trend_indicator

#!/usr/bin/env python
"""Functional-test indicators migrated to contrib.

Generated from a single functional strategy module to preserve file-local
helper functions and constants without cross-test name collisions.
"""

from .. import Indicator

__all__ = [
    "BykovTrendIndicator",
]


[docs] class BykovTrendIndicator(Indicator): """Reconstructs BykovTrend from its MQ5 source. Uses WPR(SSP) + ATR(15) to detect trend flips. Outputs buy_arrow / sell_arrow (non-zero price level when arrow fires). """ lines = ("buy_arrow", "sell_arrow") params = ( ("risk", 3), ("ssp", 9), ) def __init__(self): """Cache WPR/ATR periods, the risk threshold, and set indicator warmup.""" self._k = 33 - int(self.p.risk) self._atr_period = 15 self._wpr_period = int(self.p.ssp) self._uptrend = True self._old = True self.addminperiod(max(self._wpr_period, self._atr_period) + 2) def _calc_wpr(self): period = self._wpr_period if len(self.data) < period: return 0.0 hh = max(float(self.data.high[-i]) for i in range(period)) ll = min(float(self.data.low[-i]) for i in range(period)) close_val = float(self.data.close[0]) if hh == ll: return 0.0 return -100.0 * (hh - close_val) / (hh - ll) def _calc_atr(self): period = self._atr_period if len(self.data) < period + 1: return 0.0 total = 0.0 for i in range(period): hi = float(self.data.high[-i]) lo = float(self.data.low[-i]) prev_close = float(self.data.close[-(i + 1)]) tr = max(hi - lo, abs(hi - prev_close), abs(prev_close - lo)) total += tr return total / period
[docs] def next(self): """Update the trend state and emit buy/sell arrow offsets on flips.""" k = self._k wpr = self._calc_wpr() atr = self._calc_atr() rng = atr * 3.0 / 8.0 uptrend = self._uptrend if wpr < -100 + k: uptrend = False if wpr > -k: uptrend = True buy_val = 0.0 sell_val = 0.0 if not self._old and uptrend: buy_val = float(self.data.low[0]) - rng if self._old and not uptrend: sell_val = float(self.data.high[0]) + rng self.lines.buy_arrow[0] = buy_val self.lines.sell_arrow[0] = sell_val self._old = uptrend self._uptrend = uptrend