Source code for backtrader.indicators.contrib.fisher_org_v1_sign
#!/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 (
ATR,
Indicator,
)
__all__ = [
"FisherOrgV1Sign",
]
def _price(data, mode, ago=0):
"""Return a price value from OHLC data based on a mode selector.
Parameters
----------
data : DataFeed
Data feed with open/high/low/close lines.
mode : int
Price mode: 2=open, 3=high, 4=low, 5=(h+l)/2, 6=(h+l+c)/3,
7=(2c+h+l)/4, 8=(o+c)/2, 9=(o+h+l+c)/4; default returns close.
ago : int
Bar offset.
Returns
-------
float
Selected price value.
"""
o = float(data.open[-ago])
h = float(data.high[-ago])
low_price = float(data.low[-ago])
c = float(data.close[-ago])
if mode == 2:
return o
if mode == 3:
return h
if mode == 4:
return low_price
if mode == 5:
return (h + low_price) / 2.0
if mode == 6:
return (h + low_price + c) / 3.0
if mode == 7:
return (2.0 * c + h + low_price) / 4.0
if mode == 8:
return (o + c) / 2.0
if mode == 9:
return (o + h + low_price + c) / 4.0
return c
[docs]
class FisherOrgV1Sign(Indicator):
"""Fisher Transform Org V1 Sign indicator.
Normalises price within a highest-high/lowest-low window over `length`
bars, smooths the normalised position via recursive formula, then applies
the Fisher Transform (atanh) to produce a near-Gaussian signal. Buy/sell
trigger lines are set at ATR-scaled price levels on threshold crossovers.
Lines
-----
sell : float
Price level for sell signals (high + 3/8 ATR), set on up-cross.
buy : float
Price level for buy signals (low - 3/8 ATR), set on down-cross.
"""
lines = ("sell", "buy")
params = (
("atr_period", 14),
("length", 7),
("ipc", 1),
("up_level", 1.5),
("dn_level", -1.5),
)
def __init__(self):
"""Initialise indicator state: ATR sub-indicator and Fisher smoothing values."""
self.addminperiod(max(int(self.p.atr_period), int(self.p.length)) + 3)
self.atr = ATR(self.data, period=int(self.p.atr_period))
self._value1 = 0.0
self._fish1 = 0.0
[docs]
def next(self):
"""Compute Fisher Transform values and set buy/sell signal lines."""
length = int(self.p.length)
highs = [float(self.data.high[-i]) for i in range(length)]
lows = [float(self.data.low[-i]) for i in range(length)]
smax = max(highs)
smin = min(lows)
if smax == smin:
smax += 1e-12
price = _price(self.data, int(self.p.ipc), 0)
wpr = (price - smin) / (smax - smin)
value0 = (wpr - 0.5) + 0.67 * self._value1
value0 = min(max(value0, -0.999), 0.999)
res2 = (1.0 + value0) / (1.0 - value0)
if res2 < 1e-7:
res2 = 1.0
fish0 = 0.5 * math.log(res2) + 0.5 * self._fish1
self.lines.buy[0] = float("nan")
self.lines.sell[0] = float("nan")
atr = float(self.atr[0])
if fish0 > float(self.p.dn_level) and self._fish1 <= float(self.p.dn_level):
self.lines.buy[0] = float(self.data.low[0]) - atr * 3.0 / 8.0
if fish0 < float(self.p.up_level) and self._fish1 >= float(self.p.up_level):
self.lines.sell[0] = float(self.data.high[0]) + atr * 3.0 / 8.0
self._value1 = value0
self._fish1 = fish0