Source code for backtrader.indicators.contrib.renko_level
#!/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__ = [
"RenkoLevel",
]
[docs]
class RenkoLevel(Indicator):
"""Fixed-brick Renko level tracker emitting upper/lower levels and color."""
lines = ("upper", "lower", "color_idx")
params = (
("size_of_block", 30),
("point_size", 0.01),
)
def __init__(self):
"""Precompute the brick price step and epsilon, set minimum period."""
self.step_price = self.p.size_of_block * self.p.point_size
self.eps = self.p.point_size * 0.1
self.addminperiod(1)
def _levels(self, price):
"""Round a price to its enclosing Renko brick levels.
Args:
price: The price to snap to the brick grid.
Returns:
A tuple ``(price_ceil, price_round, price_floor)`` of brick levels.
"""
step = self.step_price
price_round = round(price / step) * step
price_ceil = math.ceil((price_round + step / 2.0) / step) * step
price_floor = math.floor((price_round - step / 2.0) / step) * step
return price_ceil, price_round, price_floor
[docs]
def next(self):
"""Advance the Renko brick levels for the current bar's close."""
close_price = float(self.data.close[0])
if (
len(self) == 1
or not math.isfinite(float(self.lines.upper[-1]))
or not math.isfinite(float(self.lines.lower[-1]))
):
price_ceil, price_round, price_floor = self._levels(close_price)
self.lines.upper[0] = price_round
self.lines.lower[0] = price_floor
self.lines.color_idx[0] = 0.0
return
prev_up = float(self.lines.upper[-1])
prev_down = float(self.lines.lower[-1])
prev_color = (
float(self.lines.color_idx[-1])
if math.isfinite(float(self.lines.color_idx[-1]))
else 0.0
)
price_ceil, price_round, price_floor = self._levels(close_price)
upper = prev_up
lower = prev_down
color = prev_color
if prev_down <= close_price <= prev_up:
pass
elif close_price < prev_down:
if abs(price_round - prev_down) > self.eps:
upper = price_ceil
lower = price_round
color = 1.0
elif close_price > prev_up:
if abs(price_round - prev_up) > self.eps:
lower = price_floor
upper = price_round
color = 0.0
self.lines.upper[0] = upper
self.lines.lower[0] = lower
self.lines.color_idx[0] = color