Source code for pandas_ta.cycles.ebsw

# -*- coding: utf-8 -*-
from numpy import cos as npCos
from numpy import exp as npExp
from numpy import nan as npNaN
from numpy import pi as npPi
from numpy import sin as npSin
from numpy import sqrt as npSqrt
from pandas import Series
from pandas_ta.utils import get_offset, verify_series


[docs]def ebsw(close, length=None, bars=None, offset=None, **kwargs): """Indicator: Even Better SineWave (EBSW)""" # Validate arguments length = int(length) if length and length > 38 else 40 bars = int(bars) if bars and bars > 0 else 10 close = verify_series(close, length) offset = get_offset(offset) if close is None: return # variables alpha1 = HP = 0 # alpha and HighPass a1 = b1 = c1 = c2 = c3 = 0 Filt = Pwr = Wave = 0 lastClose = lastHP = 0 FilterHist = [0, 0] # Filter history # Calculate Result m = close.size result = [npNaN for _ in range(0, length - 1)] + [0] for i in range(length, m): # HighPass filter cyclic components whose periods are shorter than Duration input alpha1 = (1 - npSin(360 / length)) / npCos(360 / length) HP = 0.5 * (1 + alpha1) * (close[i] - lastClose) + alpha1 * lastHP # Smooth with a Super Smoother Filter from equation 3-3 a1 = npExp(-npSqrt(2) * npPi / bars) b1 = 2 * a1 * npCos(npSqrt(2) * 180 / bars) c2 = b1 c3 = -1 * a1 * a1 c1 = 1 - c2 - c3 Filt = c1 * (HP + lastHP) / 2 + c2 * FilterHist[1] + c3 * FilterHist[0] # Filt = float("{:.8f}".format(float(Filt))) # to fix for small scientific notations, the big ones fail # 3 Bar average of Wave amplitude and power Wave = (Filt + FilterHist[1] + FilterHist[0]) / 3 Pwr = (Filt * Filt + FilterHist[1] * FilterHist[1] + FilterHist[0] * FilterHist[0]) / 3 # Normalize the Average Wave to Square Root of the Average Power Wave = Wave / npSqrt(Pwr) # update storage, result FilterHist.append(Filt) # append new Filt value FilterHist.pop(0) # remove first element of list (left) -> updating/trim lastHP = HP lastClose = close[i] result.append(Wave) ebsw = Series(result, index=close.index) # Offset if offset != 0: ebsw = ebsw.shift(offset) # Handle fills if "fillna" in kwargs: ebsw.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: ebsw.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it ebsw.name = f"EBSW_{length}_{bars}" ebsw.category = "cycles" return ebsw
ebsw.__doc__ = \ """Even Better SineWave (EBSW) *beta* This indicator measures market cycles and uses a low pass filter to remove noise. Its output is bound signal between -1 and 1 and the maximum length of a detected trend is limited by its length input. Written by rengel8 for Pandas TA based on a publication at 'prorealcode.com' and a book by J.F.Ehlers. * This implementation seems to be logically limited. It would make sense to implement exactly the version from prorealcode and compare the behaviour. Sources: https://www.prorealcode.com/prorealtime-indicators/even-better-sinewave/ J.F.Ehlers 'Cycle Analytics for Traders', 2014 Calculation: refer to 'sources' or implementation Args: close (pd.Series): Series of 'close's length (int): It's max cycle/trend period. Values between 40-48 work like expected with minimum value: 39. Default: 40. bars (int): Period of low pass filtering. Default: 10 drift (int): The difference period. Default: 1 offset (int): How many periods to offset the result. Default: 0 Kwargs: fillna (value, optional): pd.DataFrame.fillna(value) fill_method (value, optional): Type of fill method Returns: pd.Series: New feature generated. """