Source code for pandas_ta.trend.psar

# -*- coding: utf-8 -*-
from numpy import nan as npNaN
from pandas import DataFrame, Series
from pandas_ta.utils import get_offset, verify_series, zero


[docs]def psar(high, low, close=None, af0=None, af=None, max_af=None, offset=None, **kwargs): """Indicator: Parabolic Stop and Reverse (PSAR)""" # Validate Arguments high = verify_series(high) low = verify_series(low) af = float(af) if af and af > 0 else 0.02 af0 = float(af0) if af0 and af0 > 0 else af max_af = float(max_af) if max_af and max_af > 0 else 0.2 offset = get_offset(offset) def _falling(high, low, drift:int=1): """Returns the last -DM value""" # Not to be confused with ta.falling() up = high - high.shift(drift) dn = low.shift(drift) - low _dmn = (((dn > up) & (dn > 0)) * dn).apply(zero).iloc[-1] return _dmn > 0 # Falling if the first NaN -DM is positive falling = _falling(high.iloc[:2], low.iloc[:2]) if falling: sar = high.iloc[0] ep = low.iloc[0] else: sar = low.iloc[0] ep = high.iloc[0] if close is not None: close = verify_series(close) sar = close.iloc[0] long = Series(npNaN, index=high.index) short = long.copy() reversal = Series(0, index=high.index) _af = long.copy() _af.iloc[0:2] = af0 # Calculate Result m = high.shape[0] for row in range(1, m): high_ = high.iloc[row] low_ = low.iloc[row] if falling: _sar = sar + af * (ep - sar) reverse = high_ > _sar if low_ < ep: ep = low_ af = min(af + af0, max_af) _sar = max(high.iloc[row - 1], high.iloc[row - 2], _sar) else: _sar = sar + af * (ep - sar) reverse = low_ < _sar if high_ > ep: ep = high_ af = min(af + af0, max_af) _sar = min(low.iloc[row - 1], low.iloc[row - 2], _sar) if reverse: _sar = ep af = af0 falling = not falling # Must come before next line ep = low_ if falling else high_ sar = _sar # Update SAR # Seperate long/short sar based on falling if falling: short.iloc[row] = sar else: long.iloc[row] = sar _af.iloc[row] = af reversal.iloc[row] = int(reverse) # Offset if offset != 0: _af = _af.shift(offset) long = long.shift(offset) short = short.shift(offset) reversal = reversal.shift(offset) # Handle fills if "fillna" in kwargs: _af.fillna(kwargs["fillna"], inplace=True) long.fillna(kwargs["fillna"], inplace=True) short.fillna(kwargs["fillna"], inplace=True) reversal.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: _af.fillna(method=kwargs["fill_method"], inplace=True) long.fillna(method=kwargs["fill_method"], inplace=True) short.fillna(method=kwargs["fill_method"], inplace=True) reversal.fillna(method=kwargs["fill_method"], inplace=True) # Prepare DataFrame to return _params = f"_{af0}_{max_af}" data = { f"PSARl{_params}": long, f"PSARs{_params}": short, f"PSARaf{_params}": _af, f"PSARr{_params}": reversal, } psardf = DataFrame(data) psardf.name = f"PSAR{_params}" psardf.category = long.category = short.category = "trend" return psardf
psar.__doc__ = \ """Parabolic Stop and Reverse (psar) Parabolic Stop and Reverse (PSAR) was developed by J. Wells Wilder, that is used to determine trend direction and it's potential reversals in price. PSAR uses a trailing stop and reverse method called "SAR," or stop and reverse, to identify possible entries and exits. It is also known as SAR. PSAR indicator typically appears on a chart as a series of dots, either above or below an asset's price, depending on the direction the price is moving. A dot is placed below the price when it is trending upward, and above the price when it is trending downward. Sources: https://www.tradingview.com/pine-script-reference/#fun_sar https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=66&Name=Parabolic Calculation: Default Inputs: af0=0.02, af=0.02, max_af=0.2 See Source links Args: high (pd.Series): Series of 'high's low (pd.Series): Series of 'low's close (pd.Series, optional): Series of 'close's. Optional af0 (float): Initial Acceleration Factor. Default: 0.02 af (float): Acceleration Factor. Default: 0.02 max_af (float): Maximum Acceleration Factor. Default: 0.2 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.DataFrame: long, short, af, and reversal columns. """