Parabolic SAR in Python....PSAR keep growing instead of reversing
Asked Answered
C

4

6

I have a pandas dataframe of Open/high/low/close stock prices and I am writing to write a function that will add Parabolic SAR to my dataframe. Right now the PSAR number just grows insanely huge and i never seem to get much in terms of flipping between bull and bear directions. Any help in understanding why my PSAR grows so crazy would be great. I've tried several variations on this code to no avail.

For those who are not familiar with PSAR:

  • Prior SAR: The SAR value for the previous period.

Rising SAR

  • Extreme Point (EP): The highest high of the current uptrend.
  • Acceleration Factor (AF): Starting at .02, AF increases by .02 each time the extreme point makes a new high. AF can reach a maximum of .20, no matter how long the uptrend extends.
  • The Acceleration Factor is multiplied by the difference between the Extreme Point and the prior period's SAR. This is then added to the prior period's SAR. Note however that SAR can never be above the prior two periods' lows. Should SAR be above one of those lows, use the lowest of the two for SAR.

    Current SAR = Prior SAR + Prior AF(Prior EP - Prior SAR)

Eg: 13-Apr-10: SAR = 48.28 = 48.13 + .14(49.20 - 48.13)

Falling SAR

  • Extreme Point (EP): The lowest low of the current downtrend.
  • Acceleration Factor (AF): Starting at .02, AF increases by .02 each time the extreme point makes a new low. AF can reach a maximum of .20, no matter how long the downtrend extends.
  • The Acceleration Factor is multiplied by the difference between the Prior period's SAR and the Extreme Point. This is then subtracted from the prior period's SAR. Note however that SAR can never be below the prior two periods' highs. Should SAR be below one of those highs, use the highest of the two for SAR.

    Current SAR = Prior SAR - Prior AF(Prior EP - Prior SAR)

Eg: 9-Feb-10: SAR = 43.56 = 43.84 - .16(43.84 - 42.07)

During Reversal, the PSAR becomes the prior extreme point EP, and the new EP is the previous high or low depending on the direction of the flip. The AF resets to 0.02.

My function:

def addSAR(df):
    df.loc[0, 'AF'] =0.02
    df.loc[0, 'PSAR'] = df.loc[0, 'low']
    df.loc[0, 'EP'] = df.loc[0, 'high']
    df.loc[0, 'PSARdir'] = "bull"

    for a in range(1, len(df)):

        if df.loc[a-1, 'PSARdir'] == 'bull':

            df.loc[a, 'PSAR'] = df.loc[a-1, 'PSAR'] + (df.loc[a-1, 'AF']*(df.loc[a-1, 'EP']-df.loc[a-1, 'PSAR']))            

            df.loc[a, 'PSARdir'] = "bull"

            if df.loc[a, 'low'] < df.loc[a-1, 'PSAR']:
                df.loc[a, 'PSARdir'] = "bear"
                df.loc[a, 'PSAR'] = df.loc[a-1, 'EP']
                df.loc[a, 'EP'] = df.loc[a-1, 'low']
                df.loc[a, 'AF'] = .02

            else:
                if df.loc[a, 'high'] > df.loc[a-1, 'EP']:
                    df.loc[a, 'EP'] = df.loc[a, 'high']
                    if df.loc[a-1, 'AF'] <= 0.18:
                        df.loc[a, 'AF'] =df.loc[a-1, 'AF'] + 0.02
                    else:
                        df.loc[a, 'AF'] = df.loc[a-1, 'AF']
                elif df.loc[a, 'high'] <= df.loc[a-1, 'EP']:
                    df.loc[a, 'AF'] = df.loc[a-1, 'AF']
                    df.loc[a, 'EP'] = df.loc[a-1, 'EP']               



        elif df.loc[a-1, 'PSARdir'] == 'bear':

            df.loc[a, 'PSAR'] = df.loc[a-1, 'PSAR'] - (df.loc[a-1, 'AF']*(df.loc[a-1, 'EP']-df.loc[a-1, 'PSAR']))

            df.loc[a, 'PSARdir'] = "bear"

            if df.loc[a, 'high'] > df.loc[a-1, 'PSAR']:
                df.loc[a, 'PSARdir'] = "bull"
                df.loc[a, 'PSAR'] = df.loc[a-1, 'EP']
                df.loc[a, 'EP'] = df.loc[a-1, 'high']
                df.loc[a, 'AF'] = .02

            else:
                if df.loc[a, 'low'] < df.loc[a-1, 'EP']:
                    df.loc[a, 'EP'] = df.loc[a, 'low']
                    if df.loc[a-1, 'AF'] <= 0.18:
                        df.loc[a, 'AF'] = df.loc[a-1, 'AF'] + 0.02
                    else:
                        df.loc[a, 'AF'] = df.loc[a-1, 'AF']

                elif df.loc[a, 'low'] >= df.loc[a-1, 'EP']:
                    df.loc[a, 'AF'] = df.loc[a-1, 'AF']
                    df.loc[a, 'EP'] = df.loc[a-1, 'EP']           

    return df
Cohl answered 28/2, 2019 at 4:37 Comment(2)
PSAR was well explained. If you could elaborate on what is the problem you are facing & what help you need with the code, we can help you. I am a trader and I wanted to write software to help fellow traders. I am glad to help.Epanorthosis
when i run this my PSAR value grows and grows and grows.....into the millions and billions...which is clearly not correct. I've starred at my code and cant seem to figure out what i did wrong.Cohl
C
4

figured it out

df.loc[a, 'PSAR'] = df.loc[a-1, 'PSAR'] + (df.loc[a-1, 'AF']*(df.loc[a-1, 'EP']-df.loc[a-1, 'PSAR'])) 

Should be df.loc[a, 'PSAR'] = df.loc[a-1, 'PSAR'] + (df.loc[a-1, 'AF']*(df.loc[a-1, 'PSAR']-df.loc[a-1, 'EP']))

last two variables transposed!

now I can clean up the function and make it better.

Cohl answered 1/3, 2019 at 4:10 Comment(4)
Great, BTW from where do you get the OHLC values..? Do you enter the values manually or is there a way to get the values into our program from the web..?Epanorthosis
There are various API's available. mine is through my brokerage.Cohl
Did you get the final version of this working? I'm still falling of the cliff... Could you share your working code?Allergist
In my case the function does not work... of course, I changed the line above. Do you have a working version?Healthful
P
0

For my case my dataframe's index is datetime so i converted all a to df.index[a] and a-1 to df.index[a-1]. Also i changed AF,PSAR,EP,PSARdir columns as all row values will be initialized as same e.g. df['AF'] =0.02

def addSAR(df):
    df['AF'] =0.02
    df['PSAR'] = df['Low']
    df['EP'] = df['High']
    df['PSARdir'] = "bull"

    for a in range(1, len(df)):

        if df.loc[df.index[a-1], 'PSARdir'] == 'bull':

            df.loc[df.index[a], 'PSAR'] = df.loc[df.index[a-1], 'PSAR'] + (df.loc[df.index[a-1], 'AF']*(df.loc[df.index[a-1], 'PSAR']-df.loc[df.index[a-1], 'EP']))          

            df.loc[df.index[a], 'PSARdir'] = "bull"

            if df.loc[df.index[a], 'Low'] < df.loc[df.index[a-1], 'PSAR']:
                df.loc[df.index[a], 'PSARdir'] = "bear"
                df.loc[df.index[a], 'PSAR'] = df.loc[df.index[a-1], 'EP']
                df.loc[df.index[a], 'EP'] = df.loc[df.index[a-1], 'Low']
                df.loc[df.index[a], 'AF'] = .02

            else:
                if df.loc[df.index[a], 'High'] > df.loc[df.index[a-1], 'EP']:
                    df.loc[df.index[a], 'EP'] = df.loc[df.index[a], 'High']
                    if df.loc[df.index[a-1], 'AF'] <= 0.18:
                        df.loc[df.index[a], 'AF'] =df.loc[df.index[a-1], 'AF'] + 0.02
                    else:
                        df.loc[df.index[a], 'AF'] = df.loc[df.index[a-1], 'AF']
                elif df.loc[df.index[a], 'High'] <= df.loc[df.index[a-1], 'EP']:
                    df.loc[df.index[a], 'AF'] = df.loc[df.index[a-1], 'AF']
                    df.loc[df.index[a], 'EP'] = df.loc[df.index[a-1], 'EP']               



        elif df.loc[df.index[a-1], 'PSARdir'] == 'bear':

            df.loc[df.index[a], 'PSAR'] = df.loc[df.index[a-1], 'PSAR'] - (df.loc[df.index[a-1], 'AF']*(df.loc[df.index[a-1], 'EP']-df.loc[df.index[a-1], 'PSAR']))

            df.loc[df.index[a], 'PSARdir'] = "bear"

            if df.loc[df.index[a], 'High'] > df.loc[df.index[a-1], 'PSAR']:
                df.loc[df.index[a], 'PSARdir'] = "bull"
                df.loc[df.index[a], 'PSAR'] = df.loc[df.index[a-1], 'EP']
                df.loc[df.index[a], 'EP'] = df.loc[df.index[a-1], 'High']
                df.loc[df.index[a], 'AF'] = .02

            else:
                if df.loc[df.index[a], 'Low'] < df.loc[df.index[a-1], 'EP']:
                    df.loc[df.index[a], 'EP'] = df.loc[df.index[a], 'Low']
                    if df.loc[df.index[a-1], 'AF'] <= 0.18:
                        df.loc[df.index[a], 'AF'] = df.loc[df.index[a-1], 'AF'] + 0.02
                    else:
                        df.loc[df.index[a], 'AF'] = df.loc[df.index[a-1], 'AF']

                elif df.loc[df.index[a], 'Low'] >= df.loc[df.index[a-1], 'EP']:
                    df.loc[df.index[a], 'AF'] = df.loc[df.index[a-1], 'AF']
                    df.loc[df.index[a], 'EP'] = df.loc[df.index[a-1], 'EP']           

    return df
Palgrave answered 13/10, 2020 at 3:4 Comment(0)
T
0

I updated the script, fixed the bug with the increasing PSAR value and also overlapping PSAR with high/low price. Now this function gives the exact same PSAR like TradingView. enter image description here

def PSAR(df, af=0.02, max=0.2):
df.loc[0, 'AF'] = 0.02
df.loc[0, 'PSAR'] = df.loc[0, 'low']
df.loc[0, 'EP'] = df.loc[0, 'high']
df.loc[0, 'PSARdir'] = "bull"

for a in range(1, len(df)):
    if df.loc[a-1, 'PSARdir'] == 'bull':
        df.loc[a, 'PSAR'] = df.loc[a-1, 'PSAR'] + (df.loc[a-1, 'AF']*(df.loc[a-1, 'EP']-df.loc[a-1, 'PSAR']))
        df.loc[a, 'PSARdir'] = "bull"

        if df.loc[a, 'low'] < df.loc[a-1, 'PSAR'] or df.loc[a, 'low'] < df.loc[a, 'PSAR']:
            df.loc[a, 'PSARdir'] = "bear"
            df.loc[a, 'PSAR'] = df.loc[a-1, 'EP']
            df.loc[a, 'EP'] = df.loc[a-1, 'low']
            df.loc[a, 'AF'] = af
        else:
            if df.loc[a, 'high'] > df.loc[a-1, 'EP']:
                df.loc[a, 'EP'] = df.loc[a, 'high']
                if df.loc[a-1, 'AF'] <= 0.18:
                    df.loc[a, 'AF'] =df.loc[a-1, 'AF'] + af
                else:
                    df.loc[a, 'AF'] = df.loc[a-1, 'AF']
            elif df.loc[a, 'high'] <= df.loc[a-1, 'EP']:
                df.loc[a, 'AF'] = df.loc[a-1, 'AF']
                df.loc[a, 'EP'] = df.loc[a-1, 'EP']

    elif df.loc[a-1, 'PSARdir'] == 'bear':
        df.loc[a, 'PSAR'] = df.loc[a-1, 'PSAR'] - (df.loc[a-1, 'AF']*(df.loc[a-1, 'PSAR']-df.loc[a-1, 'EP']))
        df.loc[a, 'PSARdir'] = "bear"

        if df.loc[a, 'high'] > df.loc[a-1, 'PSAR'] or df.loc[a, 'high'] > df.loc[a, 'PSAR']:
            df.loc[a, 'PSARdir'] = "bull"
            df.loc[a, 'PSAR'] = df.loc[a-1, 'EP']
            df.loc[a, 'EP'] = df.loc[a-1, 'high']
            df.loc[a, 'AF'] = af
        else:
            if df.loc[a, 'low'] < df.loc[a-1, 'EP']:
                df.loc[a, 'EP'] = df.loc[a, 'low']
                if df.loc[a-1, 'AF'] < max:
                    df.loc[a, 'AF'] = df.loc[a-1, 'AF'] + af
                else:
                    df.loc[a, 'AF'] = df.loc[a-1, 'AF']

            elif df.loc[a, 'low'] >= df.loc[a-1, 'EP']:
                df.loc[a, 'AF'] = df.loc[a-1, 'AF']
                df.loc[a, 'EP'] = df.loc[a-1, 'EP']
return df
Tourney answered 12/3, 2022 at 7:56 Comment(0)
B
0

it's about 100x faster if you turn if from a df to a dict of dict before:

    psar = df.to_dict('index')

    print("Calculating PSAR for {}".format(symbol))

    psar[0]['AF'] = af
    psar[0]['PSAR'] = psar[0]['Low']
    psar[0]['EP'] = psar[0]['High']
    psar[0]['PSARdir'] = 'bull'

    i = list(psar.keys())[1:]

    for i in list(psar.keys())[1:]: # start on second data row
        prev_i = i - 1
        if psar[prev_i]['PSARdir'] == 'bull':
            psar[i]['PSAR'] = psar[prev_i]['PSAR'] + (psar[prev_i]['AF'] * (psar[prev_i]['EP'] - psar[prev_i]['PSAR']))
            psar[i]['PSARdir'] = 'bull'

            if psar[i]['Low'] < psar[prev_i]['PSAR'] or psar[i]['Low'] < psar[i]['PSAR']:
                psar[i]['PSARdir'] = 'bear'
                psar[i]['PSAR'] = psar[prev_i]['EP']
                psar[i]['EP'] = psar[prev_i]['Low']
                psar[i]['AF'] = af

            else:
                if psar[i]['High'] > psar[prev_i]['EP']:
                    psar[i]['EP'] = psar[i]['High']
                    psar[i]['AF'] = min(max, psar[prev_i]['AF'] + af)
                else:
                    psar[i]['AF'] = psar[prev_i]['AF']
                    psar[i]['EP'] = psar[prev_i]['EP']

        else:
            psar[i]['PSAR'] = psar[prev_i]['PSAR'] - (psar[prev_i]['AF'] * (psar[prev_i]['PSAR'] - psar[prev_i]['EP']))
            psar[i]['PSARdir'] = 'bear'

            if psar[i]['High'] > psar[prev_i]['PSAR'] or psar[i]['High'] > psar[i]['PSAR']:
                psar[i]['PSARdir'] = 'bull'
                psar[i]['PSAR'] = psar[prev_i]['EP']
                psar[i]['EP'] = psar[prev_i]['High']
                psar[i]['AF'] = af
            else:
                if psar[i]['Low'] < psar[prev_i]['EP']:
                    psar[i]['EP'] = psar[i]['Low']
                    psar[i]['AF'] = min(max, psar[prev_i]['AF'] + af)
                else:
                    psar[i]['AF'] = psar[prev_i]['AF']
                    psar[i]['EP'] = psar[prev_i]['EP']

    df = pd.DataFrame.from_dict(psar, orient='index')
Bashkir answered 8/6, 2022 at 14:29 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Discommend

© 2022 - 2024 — McMap. All rights reserved.