Source code for backtrader.indicators.contrib.hlr_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 (
Highest,
Indicator,
Lowest,
)
__all__ = [
"HLRIndicator",
"ZeroLagHLRIndicator",
]
[docs]
class HLRIndicator(Indicator):
"""Base HLR indicator returning a normalized high-low range position."""
lines = ("value",)
params = (("period", 40),)
def __init__(self):
"""Initialize highest/lowest trackers and line averaging setup."""
period = int(self.p.period)
self.highest = Highest(self.data.high, period=period)
self.lowest = Lowest(self.data.low, period=period)
self.mid = (self.data.high + self.data.low) / 2.0
self.addminperiod(period + 1)
[docs]
def next(self):
"""Compute the HLR oscillator value for current bar."""
hh = float(self.highest[0])
ll = float(self.lowest[0])
span = hh - ll
self.l.value[0] = 0.0 if span == 0.0 else 100.0 * ((float(self.mid[0]) - ll) / span)
[docs]
class ZeroLagHLRIndicator(Indicator):
"""Zero-lag variant of HLR computed from a blended set of HLR periods."""
lines = ("fast", "slow")
params = (
("smoothing", 15),
("factor1", 0.05),
("hlr_period1", 8),
("factor2", 0.1),
("hlr_period2", 21),
("factor3", 0.16),
("hlr_period3", 34),
("factor4", 0.26),
("hlr_period4", 55),
("factor5", 0.43),
("hlr_period5", 89),
("preserve_source_hlr3_weight", True),
)
def __init__(self):
"""Instantiate source HLR components and initialize smoothing state."""
self.hlr1 = HLRIndicator(self.data, period=int(self.p.hlr_period1))
self.hlr2 = HLRIndicator(self.data, period=int(self.p.hlr_period2))
self.hlr3 = HLRIndicator(self.data, period=int(self.p.hlr_period3))
self.hlr4 = HLRIndicator(self.data, period=int(self.p.hlr_period4))
self.hlr5 = HLRIndicator(self.data, period=int(self.p.hlr_period5))
self.smooth_const = (float(self.p.smoothing) - 1.0) / float(self.p.smoothing)
self.hlr3_weight = float(
self.p.factor2 if self.p.preserve_source_hlr3_weight else self.p.factor3
)
max_period = max(
int(self.p.hlr_period1),
int(self.p.hlr_period2),
int(self.p.hlr_period3),
int(self.p.hlr_period4),
int(self.p.hlr_period5),
)
self.addminperiod((3 * max_period) + 3)
[docs]
def next(self):
"""Update fast and smoothed slow HLR outputs."""
fast = (
float(self.p.factor1) * float(self.hlr1.value[0])
+ float(self.p.factor2) * float(self.hlr2.value[0])
+ self.hlr3_weight * float(self.hlr3.value[0])
+ float(self.p.factor4) * float(self.hlr4.value[0])
+ float(self.p.factor5) * float(self.hlr5.value[0])
)
if len(self) <= 1:
slow = fast / float(self.p.smoothing)
else:
slow = (fast / float(self.p.smoothing)) + (float(self.l.slow[-1]) * self.smooth_const)
self.l.fast[0] = fast
self.l.slow[0] = slow