Source code for backtrader.indicators.contrib.blau_tvi

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

__all__ = [
    "BlauTVI",
]


[docs] class BlauTVI(Indicator): """Blau Tick Volume Indicator: a triple-EMA-smoothed up/down tick oscillator.""" lines = ("value", "color_idx") params = ( ("xlength1", 12), ("xlength2", 12), ("xlength3", 12), ) def __init__(self): """Build the up/down tick EMAs and the smoothed oscillator value line.""" up_ticks = (self.data.volume + (self.data.close - self.data.open) / 0.01) / 2.0 dn_ticks = (self.data.volume - (self.data.close - self.data.open) / 0.01) / 2.0 up_1 = ExponentialMovingAverage(up_ticks, period=self.p.xlength1) dn_1 = ExponentialMovingAverage(dn_ticks, period=self.p.xlength1) up_2 = ExponentialMovingAverage(up_1, period=self.p.xlength2) dn_2 = ExponentialMovingAverage(dn_1, period=self.p.xlength2) raw = 100.0 * (up_2 - dn_2) / (up_2 + dn_2 + 1e-12) self.lines.value = ExponentialMovingAverage(raw, period=self.p.xlength3) self.addminperiod(self.p.xlength1 + self.p.xlength2 + self.p.xlength3 + 2)
[docs] def next(self): """Assign a color index based on the value's sign and direction of change.""" current = float(self.lines.value[0]) prev = ( float(self.lines.value[-1]) if len(self) > 1 and math.isfinite(float(self.lines.value[-1])) else current ) color = 2.0 if current > 0: color = 4.0 if current > prev else 3.0 elif current < 0: color = 0.0 if current < prev else 1.0 self.lines.color_idx[0] = color