Source code for backtrader.indicators.contrib.brake_parb_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.
"""

import math

from .. import Indicator

__all__ = [
    "BrakeParbIndicator",
]


[docs] class BrakeParbIndicator(Indicator): """Parabolic-style trailing-stop indicator with flip arrows. Maintains a power-curve stop that rises while long (and falls while short) from a begin price; when price breaks the stop the direction flips. Exposes the active stop on ``up``/``down`` lines and direction-flip cues on ``buy``/``sell`` lines. """ lines = ("buy", "sell", "up", "down") params = ( ("a", 1.5), ("b", 1.0), ("bigin_shift", 10.0), ) def __init__(self): """Set the minimum period and initialize the parabolic-stop state.""" self.addminperiod(5) self._is_long = True self._max_price = float("-inf") self._min_price = float("inf") self._begin_bar = 0 self._begin_price = None
[docs] def next(self): """Advance the parabolic stop and emit up/down stop and flip lines. Extends the stop along the power curve, flips direction (resetting the begin price and extremes) when price breaks the stop, and sets the ``up``/``down`` stop lines plus ``buy``/``sell`` flip cues for the bar. """ if self._begin_price is None: self._begin_price = float(self.data.low[0]) self._max_price = max(self._max_price, float(self.data.high[0])) self._min_price = min(self._min_price, float(self.data.low[0])) bars_since_begin = max(0, len(self.data) - 1 - self._begin_bar) b = float(self.p.b) * 0.00001 * 15.0 bigin_shift = float(self.p.bigin_shift) * 0.00001 parab = math.pow(max(0.0, float(bars_since_begin)), float(self.p.a)) * b value = self._begin_price + parab if self._is_long else self._begin_price - parab if self._is_long and value > float(self.data.low[0]): self._is_long = False self._begin_price = self._max_price + bigin_shift self._begin_bar = len(self.data) - 1 value = self._begin_price self._max_price = float("-inf") self._min_price = float("inf") elif (not self._is_long) and value < float(self.data.high[0]): self._is_long = True self._begin_price = self._min_price - bigin_shift self._begin_bar = len(self.data) - 1 value = self._begin_price self._max_price = float("-inf") self._min_price = float("inf") prev_up = float(self.lines.up[-1]) if len(self) > 0 else 0.0 prev_dn = float(self.lines.down[-1]) if len(self) > 0 else 0.0 if self._is_long: self.lines.up[0] = value self.lines.down[0] = 0.0 else: self.lines.up[0] = 0.0 self.lines.down[0] = value self.lines.buy[0] = ( self.lines.down[0] if prev_up > 0.0 and float(self.lines.down[0]) > 0.0 else 0.0 ) self.lines.sell[0] = ( self.lines.up[0] if prev_dn > 0.0 and float(self.lines.up[0]) > 0.0 else 0.0 )