question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

PSAR indicator - Incorrect value

See original GitHub issue

Which version are you running? The lastest version is on Github. Pip is for major releases.

import pandas_ta as ta
print(ta.version)

0.2.28b0

Upgrade.

$ pip install -U git+https://github.com/twopirllc/pandas-ta

Describe the bug A clear and concise description of what the bug is. The value of PSAR seems incorrect (as compared to TradingView).

– Pandas_ta for 2020-12-31 PSARs_0.02_0.2 = 377.265728 TradingView for 2020-12-31 PSAR = 363.67

To Reproduce Provide sample code.

from pandas_datareader import data
from IPython.display import display, HTML
import pandas as pd
import datetime
import pandas_ta as ta

start = datetime.datetime(2020, 1, 1)
end = datetime.datetime.now()
ticker = "SPY"
df = data.DataReader(ticker, 
                       start=start, 
                       end=end, 
                       data_source='yahoo')
df.ta.psar(append=True)
display(HTML(df.sort_index(ascending=False).to_html()))

Expected behavior A clear and concise description of what you expected to happen. The value of PSAR should be as close as possible to TradingView Screenshots If applicable, add screenshots to help explain your problem.

Additional context Add any other context about the problem here.

Thanks for using Pandas TA!

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:23 (11 by maintainers)

github_iconTop GitHub Comments

2reactions
AbyssAloracommented, Jun 11, 2021

Hi @twopirllc, I’ve made some changes as well as I’ve done some correlation tests, but I have no idea if it’s enough.

Code:

def psar(high, low, close=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
    max_af = float(max_af) if max_af and max_af > 0 else 0.2
    offset = get_offset(offset)

    falling = True
    sar = high.iloc[0]
    ep = low.iloc[0]
    af0 = af

    if close is not None:
        close = verify_series(close)
        sar = close.iloc[0]

    long = Series(npNaN, index=high.index)
    short = long.copy()
    reversal = Series(False, index=high.index)
    _af = long.copy()
    _af.iloc[0:2] = af0

    m = high.shape[0]

    # Calculate Result
    for row in range(2, m):
        HIGH = high.iloc[row]
        LOW = low.iloc[row]

        if falling:
            new_sar = sar + af * (ep - sar)
            reverse = HIGH > new_sar

            if LOW < ep:
                ep = LOW
                af = min(af + af0, max_af)

            new_sar = max(high.iloc[row - 1], high.iloc[row - 2], new_sar)
        else:
            new_sar = sar + af * (ep - sar)
            reverse = LOW < new_sar

            if HIGH > ep:
                ep = HIGH
                af = min(af + af0, max_af)

            new_sar = min(low.iloc[row - 1], low.iloc[row - 2], new_sar)

        if reverse:
            new_sar = ep
            af = af0
            falling = not falling

            if falling:
                ep = LOW
            else:
                ep = HIGH

        sar = new_sar

        if not falling:
            long.iloc[row] = sar
        else:
            short.iloc[row] = sar

        _af.iloc[row] = af
        reversal.iloc[row] = 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

Should be reviewd.

Tests:

import pandas as pd
import pandas_ta as ta

data = pd.read_csv("1.csv")  # Read exported 1m data from TV with ParabolicSAR
tv_psar = data['ParabolicSAR'].values

psar = data.ta.psar(fillna=0)
ta_psar = psar['PSARl_0.02_0.2'].values + psar['PSARs_0.02_0.2'].values

psarDf = pd.DataFrame({
    'psar_tv': tv_psar[10:],  # Ignore first first few values because of self correction
    'psar_ta': ta_psar[10:],  # Ignore first first few values because of self correction
})

print(psarDf.tail(20))
print(psarDf.corr())

Results 1m data:

        psar_tv   psar_ta
5816  1.543524  1.543524
5817  1.543254  1.543254
5818  1.542988  1.542988
5819  1.542729  1.542729
5820  1.542120  1.542120
5821  1.541212  1.541212
5822  1.540360  1.540360
5823  1.539558  1.539558
5824  1.538805  1.538805
5825  1.538096  1.538096
5826  1.537161  1.537161
5827  1.536300  1.536300
5828  1.535040  1.535040
5829  1.533906  1.533906
5830  1.532609  1.532609
5831  1.531468  1.531468
5832  1.530464  1.530464
5833  1.529580  1.529580
5834  1.528803  1.528803
5835  1.528118  1.528118
         psar_tv  psar_ta
psar_tv      1.0      1.0
psar_ta      1.0      1.0

Results 4h data:

       psar_tv   psar_ta
5081  1.608000  1.608000
5082  1.610592  1.610592
5083  1.737600  1.737600
5084  1.733848  1.733848
5085  1.723342  1.723342
5086  1.713256  1.713256
5087  1.703574  1.703574
5088  1.685360  1.685360
5089  1.668238  1.668238
5090  1.652144  1.652144
5091  1.637015  1.637015
5092  1.622794  1.622794
5093  1.400000  1.400000
5094  1.404566  1.404566
5095  1.413783  1.413783
5096  1.422632  1.422632
5097  1.435542  1.435542
5098  1.447678  1.447678
5099  1.459085  1.459085
5100  1.469808  1.469808
         psar_tv  psar_ta
psar_tv      1.0      1.0
psar_ta      1.0      1.0

Hope that’s ok and helpful as well.

Kind regards, AA

1reaction
AbyssAloracommented, Jun 10, 2021

Hello, I’ve tried reproduce TV psar from chart today, but i put there no more than half of hour. I wrote code in different language but here is python version (hope that it’s ok). This code produced similar results to TV on some live tests, but I have no time to test it properly. Maybe it’ll help, but I think that definition of psar is slightly different.

def psar(high, low, af=0.02, af_max=0.2):
    falling = True
    sar = high[0]
    ep = low[0]
    af0 = af

    psar_l = [0] * len(high)
    psar_s = [0] * len(high)

    for row in range(1, len(high)):
        HIGH = high[row]
        LOW = low[row]

        if falling:
            if LOW < ep:
                ep = LOW
                af = min(af + af0, af_max)
    
            new_sar = sar + af * (ep - sar)
            new_sar = max(HIGH, new_sar)
    
            reverse = HIGH > sar
        else: 
            if HIGH > ep:
                ep = HIGH
                af = min(af + af0, af_max)
    
            new_sar = sar + af * (ep - sar)
            new_sar = min(LOW, new_sar)
    
            reverse = LOW < sar

        if reverse:
            new_sar = ep
            af = af0
            falling = not falling
    
            if falling:
                ep = LOW
            else:
                ep = HIGH

        sar = new_sar

        if not falling:
            psar_l[row] = sar
        else:
            psar_s[row] = sar

    return psar_l, psar_s

Let me know if there are some incorrections and I’ll take a look.

Best regards, AA

Read more comments on GitHub >

github_iconTop Results From Across the Web

What Is the PSAR Indicator? - Bullish Bears
What's the PSAR indicator and how do you read it? It stands for stop and reverse and shows whether the price will continue...
Read more >
Parabolic SAR - Overview, How It Works, and How to Calculate
The Parabolic SAR is a technical indicator developed by J. Welles Wilder to determine the direction that an asset is moving.
Read more >
PSAR - Parabolic Stop And Reverse: Identifying Trend ...
When the Parabolic SAR touches the price, the trend changes its direction. This risk-following indicator can be used to estimate optimal entry/ ...
Read more >
How to Use the Parabolic SAR Indicator to Spot a Crypto Buy ...
Parabolic SAR (PSAR) is a technical indicator for traders to spot an uptrend of the downtrend price signal. Learn how PSAR works in...
Read more >
Parabolic Sar Indicator - Settings, Strategies and Tips - YouTube
The parabolic SAR is a time and price indicator in technical trading. It's used to identify the direction of the asset's price and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found