Source code for backtrader.indicators.contrib.vwma_digit_system
#!/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__ = [
"VWMADigitSystem",
]
[docs]
class VWMADigitSystem(Indicator):
"""Digit-rounded volume-weighted band color indicator.
Builds digit-rounded volume-weighted high and low levels over ``length``
bars and emits a ``color`` line encoding whether the close breaks above the
upper level or below the lower level, combined with candle direction.
"""
lines = ("color",)
params = (
("length", 12),
("digit", 2),
("shift", 2),
("use_tick_volume", True),
("point", 0.01),
)
def __init__(self):
"""Reserve the warm-up window for the shifted weighted levels."""
self.addminperiod(int(self.p.length) + int(self.p.shift) + 3)
def _weighted_level(self, series_name, ago=0):
length = int(self.p.length)
weights = []
total = 0.0
for i in range(length):
idx = ago + i
vol = (
float(self.data.volume[-idx])
if self.p.use_tick_volume
else float(self.data.openinterest[-idx])
)
weights.append(max(vol, 0.0))
total += max(vol, 0.0)
if total == 0.0:
return float(getattr(self.data, series_name)[-ago])
value = 0.0
for i in range(length):
idx = ago + i
value += float(getattr(self.data, series_name)[-idx]) * (weights[i] / total)
step = float(self.p.point) * (10 ** int(self.p.digit))
return round(value / step) * step if step else value
[docs]
def next(self):
"""Set the band color from close breaks of the weighted levels."""
shift = int(self.p.shift)
up = self._weighted_level("high", shift)
dn = self._weighted_level("low", shift)
close = float(self.data.close[0])
open_ = float(self.data.open[0])
color = 2.0
if close > up:
color = 4.0 if open_ < close else 3.0
if close < dn:
color = 0.0 if open_ > close else 1.0
self.lines.color[0] = color