Source code for backtrader.indicators.contrib.xrsi_de_marker_histogram

#!/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 (
    RSI,
    DeMarker,
    Indicator,
)

__all__ = [
    "XrsiDeMarkerHistogram",
]


[docs] class XrsiDeMarkerHistogram(Indicator): """Blend RSI and DeMarker into a smoothed histogram line.""" lines = ("value",) params = ( ("ind_period", 14), ("rsi_price", "close"), ("high_level", 60.0), ("low_level", 40.0), ("xma_method", "SMA"), ("x_length", 5), ("x_phase", 15), ) def __init__(self): """Instantiate RSI and DeMarker and initialize smoothing buffers.""" self.rsi = RSI(self.data.close, period=self.p.ind_period) self.demarker = DeMarker(self.data, period=self.p.ind_period) self._raw_buf = [] self._smooth_prev = None self.addminperiod(self.p.ind_period + self.p.x_length + 5) def _smooth_value(self, raw_value): method = str(self.p.xma_method).upper() if method in ("MODE_SMA_", "SMA"): period = max(1, int(self.p.x_length)) if len(self._raw_buf) < period: return raw_value return sum(self._raw_buf[-period:]) / float(period) length = max(1, int(self.p.x_length)) phase = max(-100, min(100, int(self.p.x_phase))) alpha = 2.0 / (length + 1.0) alpha *= 1.0 + 0.35 * (phase / 100.0) alpha = max(0.01, min(0.99, alpha)) if self._smooth_prev is None or not math.isfinite(self._smooth_prev): smooth = raw_value else: smooth = self._smooth_prev + alpha * (raw_value - self._smooth_prev) self._smooth_prev = smooth return smooth
[docs] def next(self): """Compute and smooth the combined histogram value.""" raw_value = (float(self.rsi[0]) + 100.0 * float(self.demarker.demarker[0])) / 2.0 self._raw_buf.append(raw_value) self.lines.value[0] = self._smooth_value(raw_value)