Source code for backtrader.indicators.contrib.breakout_bars_trend_v2

#!/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__ = [
    "BreakoutBarsTrendV2",
]


[docs] class BreakoutBarsTrendV2(Indicator): """Custom trend-breakout indicator calculating dynamic trend boundaries and reversals. Lines: value: Trend state value (1.0 or positive series count for uptrend, -1.0 or negative series count for downtrend). """ lines = ("value",) params = ( ("reversal_mode", "PERCENT"), ("delta", 1.0), ("point", 0.01), ) def __init__(self): """Initialize the indicator parameters, trend tracking states, and seed prices.""" self._mode = str(self.p.reversal_mode).upper() self._delta = float(self.p.delta) if self._mode == "PIPS": if self._delta < 30.0: self._delta = 1000.0 else: if self._delta < 0.03 or self._delta > 30.0: self._delta = 1.0 self._seed_close = None self._seed_high = None self._seed_low = None self._initialized = False self._uptrend = None self._min_price = None self._max_price = None self.addminperiod(1) def _reversal_distance(self, price): """Calculate the absolute price pullback distance threshold required for a trend reversal. Args: price (float): Extreme reference price. Returns: float: Symmetrical price pullback distance. """ if self._mode == "PIPS": return float(self._delta) * float(self.p.point) return (float(price) / 100.0) * float(self._delta)
[docs] def next(self): """Determine if a trend reversal has occurred, and update trend extremes.""" close = float(self.data.close[0]) high = float(self.data.high[0]) low = float(self.data.low[0]) if self._seed_close is None: self._seed_close = close self._seed_high = high self._seed_low = low self.lines.value[0] = 0.0 return if not self._initialized: reversal = self._reversal_distance(self._seed_close) if abs(close - self._seed_close) - reversal <= 0.00001: self.lines.value[0] = 0.0 return if close > self._seed_close: self._initialized = True self._uptrend = True self._min_price = self._seed_low self._max_price = high self.lines.value[0] = 1.0 else: self._initialized = True self._uptrend = False self._min_price = low self._max_price = self._seed_high self.lines.value[0] = -1.0 return prev_value = float(self.lines.value[-1]) prev_high = float(self.data.high[-1]) prev_low = float(self.data.low[-1]) self._min_price = min(float(self._min_price), prev_low) self._max_price = max(float(self._max_price), prev_high) if self._uptrend: reversal = self._reversal_distance(self._max_price) if close > float(self._max_price): self.lines.value[0] = prev_value + 1.0 elif close < max(float(self._max_price), high) - reversal and close < prev_low: self._uptrend = False self.lines.value[0] = -1.0 self._max_price = high self._min_price = low else: self.lines.value[0] = prev_value else: reversal = self._reversal_distance(self._min_price) if close < float(self._min_price): self.lines.value[0] = prev_value - 1.0 elif close > min(float(self._min_price), low) + reversal and close > prev_high: self._uptrend = True self.lines.value[0] = 1.0 self._min_price = low self._max_price = high else: self.lines.value[0] = prev_value