Source code for backtrader.indicators.contrib.center_of_gravity_candle_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 (
ExponentialMovingAverage,
Indicator,
SimpleMovingAverage,
SmoothedMovingAverage,
WeightedMovingAverage,
)
__all__ = [
"CenterOfGravityCandleIndicator",
]
[docs]
class CenterOfGravityCandleIndicator(Indicator):
"""Center-of-Gravity Candle indicator exposing center, signal, and state lines."""
lines = ("center", "signal", "state")
params = (
("period", 10),
("smooth_period", 3),
("ma_method", "sma"),
("applied_price", "close"),
("point", 0.01),
)
def __init__(self):
"""Build the center, signal, and warmup period from the applied price.
Side effects:
Computes ``center`` as the point-scaled product of an SMA and a LWMA
of the applied price, derives ``signal`` by smoothing ``center``, and
sets the minimum warmup period.
"""
ma_cls = self._ma_class()
price = self._price_line()
sma = SimpleMovingAverage(price, period=self.p.period)
lwma = WeightedMovingAverage(price, period=self.p.period)
self.lines.center = (sma * lwma) / self.p.point
self.lines.signal = ma_cls(self.lines.center, period=self.p.smooth_period)
self.addminperiod(self.p.period + self.p.smooth_period + 5)
def _ma_class(self):
mode = str(self.p.ma_method).lower()
if mode in {"ema", "mode_ema"}:
return ExponentialMovingAverage
if mode in {"smma", "smoothed", "mode_smma"}:
return SmoothedMovingAverage
if mode in {"lwma", "wma", "mode_lwma"}:
return WeightedMovingAverage
return SimpleMovingAverage
def _price_line(self):
mode = str(self.p.applied_price).lower()
if mode == "open":
return self.data.open
if mode == "high":
return self.data.high
if mode == "low":
return self.data.low
if mode == "median":
return (self.data.high + self.data.low) / 2.0
if mode == "typical":
return (self.data.high + self.data.low + self.data.close) / 3.0
if mode == "weighted":
return (self.data.high + self.data.low + self.data.close + self.data.close) / 4.0
if mode == "simpl":
return (self.data.open + self.data.close) / 2.0
if mode == "quarter":
return (self.data.high + self.data.low + self.data.open + self.data.close) / 4.0
return self.data.close
[docs]
def next(self):
"""Set ``state`` to 2 when center is above signal, else 0, for the bar."""
self.lines.state[0] = (
2.0 if float(self.lines.center[0]) > float(self.lines.signal[0]) else 0.0
)