Source code for backtrader.indicators.contrib.fractal_amambk
#!/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 Indicator
__all__ = [
"FractalAMAMBK",
]
[docs]
class FractalAMAMBK(Indicator):
"""FRAMA-style indicator exposing smoothed trend and trigger lines."""
lines = ("frama", "trigger")
params = (
("r_period", 16),
("multiplier", 4.6),
("signal_multiplier", 2.5),
)
def __init__(self):
"""Set minimum period based on FRAMA computation window."""
self.addminperiod(max(int(self.p.r_period), 2) + 2)
def _range(self, high_line, low_line, start_shift, count):
highs = [
float(high_line[-shift]) if shift else float(high_line[0])
for shift in range(start_shift, start_shift + count)
]
lows = [
float(low_line[-shift]) if shift else float(low_line[0])
for shift in range(start_shift, start_shift + count)
]
return max(highs) - min(lows)
[docs]
def next(self):
"""Compute FRAMA and trigger values for the current bar."""
period = max(int(self.p.r_period), 2)
n = (period // 2) * 2
n2 = max(n // 2, 1)
price = float(self.data.close[0])
if len(self.data) <= n:
self.l.frama[0] = price
self.l.trigger[0] = price
return
r1 = self._range(self.data.high, self.data.low, 0, n2) / n2
r2 = self._range(self.data.high, self.data.low, n2, n2) / n2
r3 = self._range(self.data.high, self.data.low, 0, n) / n
if r3 <= 0 or (r1 + r2) <= 0:
dimension_estimate = 1.0
else:
dimension_estimate = (math.log(r1 + r2) - math.log(r3)) * 1.442695
alpha = math.exp(-float(self.p.multiplier) * (dimension_estimate - 1.0))
alpha = min(max(alpha, 0.01), 1.0)
alphas = math.exp(-float(self.p.signal_multiplier) * (dimension_estimate - 1.0))
prev_frama = (
float(self.l.frama[-1])
if len(self.data) > 1 and math.isfinite(float(self.l.frama[-1]))
else float(self.data.close[-1])
)
prev_trigger = (
float(self.l.trigger[-1])
if len(self.data) > 1 and math.isfinite(float(self.l.trigger[-1]))
else prev_frama
)
frama = alpha * price + (1.0 - alpha) * prev_frama
trigger = alphas * frama + (1.0 - alphas) * prev_trigger
self.l.frama[0] = frama
self.l.trigger[0] = trigger