Source code for backtrader.indicators.contrib.raw_close_close_stochastic
#!/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 (
ExponentialMovingAverage,
Indicator,
)
__all__ = [
"RawCloseCloseStochastic",
"CloseCloseEmaStochastic",
]
[docs]
class RawCloseCloseStochastic(Indicator):
"""Raw close-based Stochastic (%K numerator) over a close-only window."""
lines = ("raw",)
params = (("period", 5),)
def __init__(self):
"""Set the minimum period required before emitting values."""
self.addminperiod(int(self.p.period))
[docs]
def next(self):
"""Compute the raw close-based Stochastic value for the current bar."""
period = int(self.p.period)
closes = [float(self.data.close[-i]) for i in range(period)]
highest = max(closes)
lowest = min(closes)
denom = highest - lowest
if denom == 0:
self.lines.raw[0] = 0.0
return
self.lines.raw[0] = 100.0 * (float(self.data.close[0]) - lowest) / denom
[docs]
def once(self, start, end):
"""Vectorized raw close-based Stochastic over the array index range.
Args:
start: Start index (inclusive) of the range to compute.
end: End index (exclusive) of the range to compute.
"""
period = int(self.p.period)
closes = self.data.close.array
raw = self.lines.raw.array
for i in range(start, end):
window_start = max(0, i - period + 1)
window = closes[window_start : i + 1]
highest = max(window)
lowest = min(window)
denom = highest - lowest
raw[i] = 0.0 if denom == 0 else 100.0 * (closes[i] - lowest) / denom
[docs]
class CloseCloseEmaStochastic(Indicator):
"""EMA-smoothed close-based Stochastic exposing ``percK`` and ``percD``."""
lines = ("percK", "percD")
params = (
("period", 5),
("slowing", 3),
("dperiod", 3),
)
def __init__(self):
"""Build the EMA-smoothed %K and %D lines from the raw Stochastic."""
raw = RawCloseCloseStochastic(self.data, period=int(self.p.period))
self.lines.percK = ExponentialMovingAverage(raw, period=int(self.p.slowing))
self.lines.percD = ExponentialMovingAverage(self.lines.percK, period=int(self.p.dperiod))