Source code for backtrader.indicators.contrib.xrsi_histogram_vol_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__ = [
"XRSIHistogramVolIndicator",
]
[docs]
class XRSIHistogramVolIndicator(Indicator):
"""Volume-scaled RSI histogram indicator producing directional color states."""
lines = ("color_state", "value", "max_level", "up_level", "dn_level", "min_level")
params = (
("rsi_period", 14),
("high_level2", 17),
("high_level1", 5),
("low_level1", -5),
("low_level2", -17),
("ma_length", 12),
)
def __init__(self):
"""Prepare rolling RSI and volume histories."""
self._scaled_history = []
self._volume_history = []
self.addminperiod(max(self.p.rsi_period, self.p.ma_length) + 3)
[docs]
def next(self):
"""Calculate scaled histogram level and classify it into a color state."""
vol = float(self.data.volume[0]) if len(self.data.volume) else 0.0
gains = []
losses = []
for idx in range(self.p.rsi_period):
delta = float(self.data.close[-idx]) - float(self.data.close[-idx - 1])
gains.append(max(delta, 0.0))
losses.append(max(-delta, 0.0))
avg_gain = sum(gains) / float(len(gains))
avg_loss = sum(losses) / float(len(losses))
if avg_loss <= 1e-12:
rsi_value = 100.0 if avg_gain > 0 else 50.0
else:
rs = avg_gain / avg_loss
rsi_value = 100.0 - (100.0 / (1.0 + rs))
raw = (rsi_value - 50.0) * vol
self._scaled_history.append(raw)
self._volume_history.append(vol)
if len(self._scaled_history) > self.p.ma_length:
self._scaled_history.pop(0)
if len(self._volume_history) > self.p.ma_length:
self._volume_history.pop(0)
scaled = sum(self._scaled_history) / float(len(self._scaled_history))
avg_vol = (
sum(self._volume_history) / float(len(self._volume_history))
if self._volume_history
else max(vol, 1.0)
)
max_level = self.p.high_level2 * avg_vol
up_level = self.p.high_level1 * avg_vol
dn_level = self.p.low_level1 * avg_vol
min_level = self.p.low_level2 * avg_vol
clr = 2.0
if scaled > max_level:
clr = 0.0
elif scaled > up_level:
clr = 1.0
elif scaled < min_level:
clr = 4.0
elif scaled < dn_level:
clr = 3.0
self.lines.value[0] = scaled
self.lines.max_level[0] = max_level
self.lines.up_level[0] = up_level
self.lines.dn_level[0] = dn_level
self.lines.min_level[0] = min_level
self.lines.color_state[0] = clr