This strategy monitors the Parabolic SAR (Stop and Reverse) indicator to detect potential trend reversals. When the SAR value flips from above the price to below, the algorithm interprets it as a bullish signal and opens a long position. When the SAR moves from below the price to above, a short position is opened.
The default acceleration factor (0.02) and maximum acceleration (0.2) follow the classic Parabolic SAR configuration. These parameters control how quickly the indicator approaches price: higher values make the SAR react faster but can lead to whipsaws. The strategy processes only finished candles and stores previous SAR and price values to identify crossovers without querying historical data.
Risk management is not defined explicitly; the example relies on opposite signals to exit. Additional protection can be enabled through the framework's built-in mechanisms.
Details
Entry Criteria: Parabolic SAR crosses the closing price.
Long/Short: Both.
Exit Criteria: Opposite signal.
Stops: Not defined.
Default Values:
InitialAcceleration = 0.02
MaxAcceleration = 0.2
CandleType = 5 minute
Filters:
Category: Trend following
Direction: Both
Indicators: Parabolic SAR
Stops: Optional
Complexity: Basic
Timeframe: Intraday
Seasonality: No
Neural networks: No
Divergence: No
Risk level: Medium
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Parabolic SAR Alert Strategy.
/// Opens long or short positions when Parabolic SAR flips relative to price.
/// </summary>
public class ParabolicSarAlertStrategy : Strategy
{
private readonly StrategyParam<decimal> _initialAcceleration;
private readonly StrategyParam<decimal> _maxAcceleration;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevSar;
private decimal _prevClose;
private bool _initialized;
public decimal InitialAcceleration { get => _initialAcceleration.Value; set => _initialAcceleration.Value = value; }
public decimal MaxAcceleration { get => _maxAcceleration.Value; set => _maxAcceleration.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ParabolicSarAlertStrategy()
{
_initialAcceleration = Param(nameof(InitialAcceleration), 0.02m)
.SetDisplay("Initial Acceleration", "Initial acceleration factor for Parabolic SAR", "SAR Settings");
_maxAcceleration = Param(nameof(MaxAcceleration), 0.2m)
.SetDisplay("Max Acceleration", "Maximum acceleration factor for Parabolic SAR", "SAR Settings");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevSar = 0;
_prevClose = 0;
_initialized = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var parabolicSar = new ParabolicSar
{
Acceleration = InitialAcceleration,
AccelerationMax = MaxAcceleration
};
SubscribeCandles(CandleType)
.Bind(parabolicSar, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal sarValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_initialized)
{
_prevSar = sarValue;
_prevClose = candle.ClosePrice;
_initialized = true;
return;
}
var crossUp = _prevSar > _prevClose && sarValue < candle.ClosePrice;
var crossDown = _prevSar < _prevClose && sarValue > candle.ClosePrice;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevSar = sarValue;
_prevClose = candle.ClosePrice;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ParabolicSar
from StockSharp.Algo.Strategies import Strategy
class parabolic_sar_alert_strategy(Strategy):
def __init__(self):
super(parabolic_sar_alert_strategy, self).__init__()
self._initial_acceleration = self.Param("InitialAcceleration", 0.02) \
.SetDisplay("Initial Acceleration", "Initial acceleration factor for Parabolic SAR", "SAR Settings")
self._max_acceleration = self.Param("MaxAcceleration", 0.2) \
.SetDisplay("Max Acceleration", "Maximum acceleration factor for Parabolic SAR", "SAR Settings")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_sar = 0.0
self._prev_close = 0.0
self._initialized = False
@property
def initial_acceleration(self):
return self._initial_acceleration.Value
@property
def max_acceleration(self):
return self._max_acceleration.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(parabolic_sar_alert_strategy, self).OnReseted()
self._prev_sar = 0.0
self._prev_close = 0.0
self._initialized = False
def OnStarted2(self, time):
super(parabolic_sar_alert_strategy, self).OnStarted2(time)
parabolic_sar = ParabolicSar()
parabolic_sar.Acceleration = self.initial_acceleration
parabolic_sar.AccelerationMax = self.max_acceleration
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(parabolic_sar, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, sar_value):
if candle.State != CandleStates.Finished:
return
if not self._initialized:
self._prev_sar = sar_value
self._prev_close = candle.ClosePrice
self._initialized = True
return
cross_up = self._prev_sar > self._prev_close and sar_value < candle.ClosePrice
cross_down = self._prev_sar < self._prev_close and sar_value > candle.ClosePrice
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_sar = sar_value
self._prev_close = candle.ClosePrice
def CreateClone(self):
return parabolic_sar_alert_strategy()