TickAtlas
Tutorial 10 min read · March 28, 2026

Parabolic SAR: Trailing Stop-Loss Automation

How to implement automated trailing stop losses using Parabolic SAR data from the TickAtlas API, with Python code and backtesting considerations.

CG
By the TickAtlas team

What Is Parabolic SAR?

Parabolic SAR (Stop and Reverse), developed by J. Welles Wilder, is a trend-following indicator that provides potential entry and exit points. On a chart, it appears as dots above or below price: dots below price indicate an uptrend, dots above indicate a downtrend.

What makes it especially useful for automation is that it gives you a specific price level at each bar -- not a vague "overbought" signal, but an exact stop-loss value that tightens over time as the trend progresses.

Dots Below Price

Uptrend active. The SAR value is your trailing stop for a long position. It only moves up, never down.

Dots Above Price

Downtrend active. The SAR value is your trailing stop for a short position. It only moves down, never up.

How SAR Is Calculated

The SAR uses an acceleration factor (AF) that starts at 0.02 and increases by 0.02 each time a new extreme point is reached, up to a maximum of 0.20. This creates the "parabolic" curve that accelerates toward price as the trend matures.

SAR(next) = SAR(current) + AF * (EP - SAR(current))

Where:
  AF = Acceleration Factor (starts 0.02, max 0.20)
  EP = Extreme Point (highest high in uptrend, lowest low in downtrend)

When price crosses SAR, the trend reverses:
  - New SAR = most extreme EP from the previous trend
  - AF resets to 0.02

Fetching Parabolic SAR from the API

curl -H "X-API-Key: YOUR_API_KEY" \
  "https://tickatlas.com/v1/indicator?symbol=GBPUSD&indicator=SAR&timeframe=H1"

Response:

json
{
  "success": true,
  "data": {
    "symbol": "GBPUSD",
    "timeframe": "H1",
    "indicator": "SAR",
    "values": {
      "sar": 1.2934
    },
    "signal": "bullish",
    "ohlcv": {
      "open": 1.2948,
      "high": 1.2962,
      "low": 1.2941,
      "close": 1.2957,
      "volume": 8932
    },
    "timestamp": "2026-03-28T15:00:00Z"
  }
}

The SAR is at 1.2934, below the close of 1.2957. Signal is "bullish" -- dots are below price. This SAR value is your trailing stop if you are long GBPUSD.

Python: Automated SAR Trailing Stop

python
import requests
import time
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("sar_trailing")

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://tickatlas.com/v1"

class SARTrailingStop:
    """Manage a trailing stop using Parabolic SAR."""

    def __init__(self, symbol: str, timeframe: str, direction: str):
        self.symbol = symbol
        self.timeframe = timeframe
        self.direction = direction
        self.current_stop = None
        self.is_active = True

    def fetch_sar(self) -> dict:
        resp = requests.get(
            f"{BASE_URL}/indicator",
            headers={"X-API-Key": API_KEY},
            params={
                "symbol": self.symbol,
                "indicator": "SAR",
                "timeframe": self.timeframe,
            },
        )
        resp.raise_for_status()
        return resp.json()["data"]

    def update(self) -> dict:
        """Check SAR and update trailing stop."""
        data = self.fetch_sar()
        sar = data["values"]["sar"]
        close = data["ohlcv"]["close"]
        signal = data["signal"]

        result = {
            "sar": sar,
            "close": close,
            "signal": signal,
            "stop_hit": False,
            "stop_level": self.current_stop,
        }

        if self.direction == "long":
            # SAR flipped above price = exit signal
            if signal == "bearish":
                result["stop_hit"] = True
                self.is_active = False
                logger.info(f"SAR flipped bearish. Exit long at {close}")
                return result

            # Update trailing stop (only moves up)
            if self.current_stop is None or sar > self.current_stop:
                self.current_stop = sar
                result["stop_level"] = sar
                logger.info(f"Trailing stop updated to {sar}")

        elif self.direction == "short":
            if signal == "bullish":
                result["stop_hit"] = True
                self.is_active = False
                logger.info(f"SAR flipped bullish. Exit short at {close}")
                return result

            if self.current_stop is None or sar < self.current_stop:
                self.current_stop = sar
                result["stop_level"] = sar
                logger.info(f"Trailing stop updated to {sar}")

        return result

# Usage
trailing = SARTrailingStop("GBPUSD", "H1", "long")

# In a real bot, this runs on a timer matching the timeframe
while trailing.is_active:
    status = trailing.update()
    print(f"Close: {status['close']}, Stop: {status['stop_level']}")
    if status["stop_hit"]:
        print("Position closed by SAR reversal.")
        break
    time.sleep(3600)  # Check every hour for H1

SAR + ATR Hybrid Approach

A common improvement is to use SAR for the trailing mechanism but set the initial stop with ATR. This prevents the early SAR values (which start very close to price) from triggering a premature exit:

python
def hybrid_stop(symbol: str, timeframe: str, direction: str) -> dict:
    """Use ATR for initial stop, SAR for trailing."""
    # Fetch both indicators
    sar_data = requests.get(
        f"{BASE_URL}/indicator",
        headers={"X-API-Key": API_KEY},
        params={"symbol": symbol, "indicator": "SAR", "timeframe": timeframe},
    ).json()["data"]

    atr_data = requests.get(
        f"{BASE_URL}/indicator",
        headers={"X-API-Key": API_KEY},
        params={"symbol": symbol, "indicator": "ATR_14", "timeframe": timeframe},
    ).json()["data"]

    close = sar_data["ohlcv"]["close"]
    sar = sar_data["values"]["sar"]
    atr = atr_data["values"]["atr"]

    if direction == "long":
        atr_stop = close - (atr * 2.0)
        # Use whichever is further from price (more conservative)
        initial_stop = min(sar, atr_stop)
    else:
        atr_stop = close + (atr * 2.0)
        initial_stop = max(sar, atr_stop)

    return {
        "sar_stop": sar,
        "atr_stop": round(atr_stop, 5),
        "selected_stop": round(initial_stop, 5),
        "method": "ATR" if initial_stop != sar else "SAR",
    }

When SAR Works Best (and Worst)

Best: strong trending markets

SAR excels in sustained trends where the parabolic curve locks in profits as the trend accelerates. XAUUSD trend days are ideal.

Worst: ranging/choppy markets

In sideways markets, SAR flips frequently, generating costly whipsaw entries and exits. Always filter with a trend indicator like ADX.

Tip: Use ADX > 25 as a trend filter

Only use SAR for trailing stops when ADX confirms a strong trend. In low-ADX environments, switch to a fixed ATR stop instead.

Related Reading

Try this with live data

Every account gets $2.50 in free PAYG credits. No card required — paste your API key and run the code above against live broker data.