Source code for backtrader.indicators.contrib.brain_trend2_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 collections import deque

from .. import Indicator

__all__ = [
    "BrainTrend2Indicator",
    "AbsolutelyNoLagLwmaIndicator",
]


[docs] class BrainTrend2Indicator(Indicator): """ATR-derived trend-state indicator producing a four-state color signal.""" lines = ("color_state",) params = ( ("atr_period", 7), ("point_size", 0.01), ) def __init__(self): """Initialize transition state and adaptive ATR window.""" self._period = max(1, int(self.p.atr_period)) self._cecf = 0.7 self._trs = deque(maxlen=self._period) self._river = None self._emaxtra = None self.addminperiod(self._period + 2) @staticmethod def _finite(value): return value is not None and math.isfinite(value)
[docs] def next(self): """Update trend river state and emit a color code.""" prev_close = float(self.data.close[-1]) if len(self.data) > 1 else float(self.data.close[0]) spread = ( float(getattr(self.data, "spread")[0]) * self.p.point_size if hasattr(self.data, "spread") else 0.0 ) high = float(self.data.high[0]) low = float(self.data.low[0]) open_ = float(self.data.open[0]) close = float(self.data.close[0]) tr = spread + high - low tr = max(tr, abs(spread + high - prev_close), abs(low - prev_close)) self._trs.append(tr) if len(self._trs) < self._period: self.lines.color_state[0] = float("nan") return weights = list(range(self._period, 0, -1)) atr = ( 2.0 * sum(w * v for w, v in zip(weights, reversed(self._trs))) / (self._period * (self._period + 1.0)) ) widcha = self._cecf * atr if self._river is None: prev2_close = float(self.data.close[-2]) if len(self.data) > 2 else prev_close self._river = prev2_close > prev_close self._emaxtra = prev_close if self._river and low < self._emaxtra - widcha: self._river = False self._emaxtra = spread + high if (not self._river) and spread + high > self._emaxtra + widcha: self._river = True self._emaxtra = low if self._river and low > self._emaxtra: self._emaxtra = low if (not self._river) and spread + high < self._emaxtra: self._emaxtra = spread + high if self._river: color = 0.0 if open_ <= close else 1.0 else: color = 4.0 if open_ >= close else 3.0 self.lines.color_state[0] = color
[docs] class AbsolutelyNoLagLwmaIndicator(Indicator): """No-lag LWMA indicator with color state transitions.""" lines = ("line_value", "color_state") params = (("length", 7),) def __init__(self): """Prepare rolling windows for dual-weighted moving average updates.""" self._length = max(1, int(self.p.length)) self._price_window = deque(maxlen=self._length) self._lwma_window = deque(maxlen=self._length) self.addminperiod(self._length * 2) def _weighted_ma(self, values): weights = list(range(len(values), 0, -1)) total = sum(weights) return sum(w * v for w, v in zip(weights, reversed(values))) / total
[docs] def next(self): """Compute smoothed LWMA and directional color for each bar.""" price = float(self.data.close[0]) self._price_window.append(price) if len(self._price_window) < self._length: self.lines.line_value[0] = float("nan") self.lines.color_state[0] = float("nan") return lwma1 = self._weighted_ma(self._price_window) self._lwma_window.append(lwma1) if len(self._lwma_window) < self._length: self.lines.line_value[0] = float("nan") self.lines.color_state[0] = float("nan") return lwma2 = self._weighted_ma(self._lwma_window) color = 1.0 prev = self.lines.line_value[-1] if len(self) > 0 else float("nan") if prev == prev: if prev < lwma2: color = 2.0 elif prev > lwma2: color = 0.0 self.lines.line_value[0] = lwma2 self.lines.color_state[0] = color