Source code for backtrader.indicators.contrib.any_range_cld_tail_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 backtrader.utils.dateintern import num2date
from .. import Indicator
__all__ = [
"AnyRangeCldTailIndicator",
]
[docs]
class AnyRangeCldTailIndicator(Indicator):
"""Compute a session-based daily channel and color-state trend signal."""
lines = ("color_state", "upper", "lower")
params = (
("time1", "02:00"),
("time2", "07:00"),
)
def __init__(self):
"""Initialize session boundaries and window tracking state."""
self._time1 = self._parse_hhmm(self.p.time1)
self._time2 = self._parse_hhmm(self.p.time2)
self._window_start = min(self._time1, self._time2)
self._window_end = max(self._time1, self._time2)
self._current_day = None
self._range_high = None
self._range_low = None
self._channel_high = None
self._channel_low = None
self._window_finalized = False
self.addminperiod(2)
@staticmethod
def _parse_hhmm(value):
hour, minute = value.split(":")
return int(hour) * 60 + int(minute)
[docs]
def next(self):
"""Update channel bounds and emit color state for the current bar."""
dt = num2date(self.data.datetime[0])
day = dt.date()
minute = dt.hour * 60 + dt.minute
if self._current_day != day:
self._current_day = day
self._range_high = None
self._range_low = None
self._channel_high = None
self._channel_low = None
self._window_finalized = False
in_window = self._window_start < minute <= self._window_end
if in_window:
high = float(self.data.high[0])
low = float(self.data.low[0])
self._range_high = high if self._range_high is None else max(self._range_high, high)
self._range_low = low if self._range_low is None else min(self._range_low, low)
elif (
minute > self._window_end
and not self._window_finalized
and self._range_high is not None
and self._range_low is not None
):
self._channel_high = self._range_high
self._channel_low = self._range_low
self._window_finalized = True
color = 4.0
if self._channel_high is not None and self._channel_low is not None and not in_window:
close = float(self.data.close[0])
open_ = float(self.data.open[0])
if close > self._channel_high:
color = 3.0 if close >= open_ else 2.0
elif close < self._channel_low:
color = 0.0 if close <= open_ else 1.0
self.lines.color_state[0] = color
self.lines.upper[0] = self._channel_high if self._channel_high is not None else float("nan")
self.lines.lower[0] = self._channel_low if self._channel_low is not None else float("nan")