Source code for backtrader.indicators.contrib.wprsi_signal_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 Indicator

__all__ = [
    "WPRSISignalIndicator",
]


[docs] class WPRSISignalIndicator(Indicator): """Reconstructs WPRSIsignal indicator from its MQ5 source. Uses WPR and RSI with same period. Buy: WPR crosses above -20 from below AND RSI > 50, with filterUP lookback confirmation. Sell: WPR crosses below -80 from above AND RSI < 50, with filterDN lookback confirmation. """ lines = ("sell_arrow", "buy_arrow") # buffer 0 = sell, buffer 1 = buy params = ( ("wprsi_period", 27), ("filter_up", 10), ("filter_dn", 10), ) def __init__(self): """Reserve warm-up bars covering the WPRSI period plus the filter window.""" self._period = int(self.p.wprsi_period) self._filter_up = int(self.p.filter_up) self._filter_dn = int(self.p.filter_dn) filter_max = max(self._filter_up, self._filter_dn) self.addminperiod(self._period + filter_max + 3) def _calc_wpr(self, ago=0): period = self._period highest = max(float(self.data.high[-(ago + i)]) for i in range(period)) lowest = min(float(self.data.low[-(ago + i)]) for i in range(period)) close = float(self.data.close[-ago]) if highest == lowest: return -50.0 return -100.0 * (highest - close) / (highest - lowest) def _calc_rsi(self, ago=0): period = self._period gains = 0.0 losses = 0.0 for i in range(period): idx = ago + i c = float(self.data.close[-idx]) cp = float(self.data.close[-(idx + 1)]) diff = c - cp if diff > 0: gains += diff else: losses -= diff avg_gain = gains / period avg_loss = losses / period if avg_loss == 0: return 100.0 rs = avg_gain / avg_loss return 100.0 - (100.0 / (1.0 + rs))
[docs] def next(self): """Emit buy/sell arrows on filtered Williams %R crosses confirmed by RSI.""" wpr_0 = self._calc_wpr(0) wpr_1 = self._calc_wpr(1) rsi_0 = self._calc_rsi(0) buy_val = 0.0 sell_val = 0.0 cur_high = float(self.data.high[0]) cur_low = float(self.data.low[0]) rng = cur_high - cur_low # Buy: WPR crosses above -20 from below, RSI > 50 if wpr_0 > -20.0 and wpr_1 < -20.0 and rsi_0 > 50.0: z = 0 for k in range(2, self._filter_up + 3): if k < len(self.data): wk = self._calc_wpr(k) if wk > -20.0: z = 1 break if z == 0: buy_val = cur_low - rng / 2.0 # Sell: WPR crosses below -80 from above, RSI < 50 if wpr_1 > -80.0 and wpr_0 < -80.0 and rsi_0 < 50.0: h = 0 for c in range(2, self._filter_dn + 3): if c < len(self.data): wk = self._calc_wpr(c) if wk < -80.0: h = 1 break if h == 0: sell_val = cur_high + rng / 2.0 self.lines.sell_arrow[0] = sell_val self.lines.buy_arrow[0] = buy_val