Parabolic SAR in Python — Coding It from Scratch

The full recursive SAR/EP/AF algorithm, step by step

Parabolic SAR computed in Python
Parabolic SAR computed in Python

The Parabolic SAR is the most procedural indicator in this series — it’s a genuine state machine, not a vectorized formula. The explainer covers the logic; here it is faithfully in Python, including the constraint most implementations get wrong.

What you’ll need

  • Python 3.9+, numpy
  • high, low arrays.

From scratch

import numpy as np


def parabolic_sar(high, low, af_start=0.02, af_step=0.02, af_max=0.20):
    high = np.asarray(high, float)
    low = np.asarray(low, float)
    n = len(high)
    sar = np.full(n, np.nan)

    up = True                 # start assuming an uptrend
    af = af_start
    ep = high[0]              # extreme point
    sar[0] = low[0]

    for i in range(1, n):
        prev = sar[i - 1]
        s = prev + af * (ep - prev)

        if up:
            # SAR may not enter the prior two bars' range.
            s = min(s, low[i - 1], low[i - 2] if i >= 2 else low[i - 1])
            if low[i] < s:                 # price hit the stop -> flip down
                up = False
                s = ep                     # new SAR starts at the old extreme
                ep = low[i]
                af = af_start
            elif high[i] > ep:             # new high -> extend and accelerate
                ep = high[i]
                af = min(af + af_step, af_max)
        else:
            s = max(s, high[i - 1], high[i - 2] if i >= 2 else high[i - 1])
            if high[i] > s:                # flip up
                up = True
                s = ep
                ep = high[i]
                af = af_start
            elif low[i] < ep:
                ep = low[i]
                af = min(af + af_step, af_max)

        sar[i] = s

    return sar

Read it as a state machine: track the trend direction, the extreme point, and the acceleration factor; step the SAR toward the EP each bar; flip when price crosses it. That produces the trailing dots from the output chart.

Turning it into signals

sar = parabolic_sar(df["high"].values, df["low"].values)
below = df["close"].values > sar          # dots below price = uptrend
flip_up = np.r_[False, below[1:] & ~below[:-1]]   # flipped to uptrend this bar
flip_dn = np.r_[False, ~below[1:] & below[:-1]]

flip_up/flip_dn mark the bars where the SAR crosses to the other side — the stop-and-reverse points to backtest in AlgoGen.

Gotchas

  • The prior-two-bars constraint. s = min(s, low[i-1], low[i-2]) (and the max for downtrends) stops the SAR from jumping inside recent range. Omitting it is the single most common Parabolic SAR bug.
  • Flip mechanics. On a flip, the new SAR starts at the old extreme point, and AF resets to the start value. Forgetting the reset makes the next leg trail wrong.
  • It’s inherently sequential. Unlike most indicators, you can’t fully vectorize this — the loop is the honest implementation.

The lazy one-liner

import pandas_ta as ta
df["psar"] = ta.psar(df["high"], df["low"], df["close"])["PSARl_0.02_0.2"]

Same indicator elsewhere: MQL5, Pine Script, EasyLanguage, NinjaScript.


This post is educational, not financial advice. Indicators describe the past; they don’t predict the future. Backtest anything before you risk real money on it.

Sources and further reading

  1. Windowing operations (pandas documentation)

Historical research from the Algogen archive. Not investment advice.

Blog

Have a strategy idea?

Describe it in plain English, preview where your rules fire, then decide whether the evidence is worth a backtest.

Keep me postedHow it works