The PSAR Trader strategy acts on shifts in the Parabolic SAR indicator. When the SAR flips below price a long position is opened, and when the SAR flips above price a short position is opened. An optional "Close On Opposite" setting reverses the position when an opposite signal appears. Trading occurs only during the configured session hours. Stop loss and take profit are managed by the protection module.
Details
Entry Criteria: Price crossing the Parabolic SAR.
Long/Short: Both directions.
Exit Criteria: Opposite SAR crossing or position reversal.
Stops: Yes, fixed via parameters.
Default Values:
SarStep = 0.001m
SarMaxStep = 0.2m
StartHour = 0
EndHour = 23
CloseOnOpposite = true
TakeValue = 50 (absolute)
StopValue = 50 (absolute)
CandleType = TimeSpan.FromMinutes(5)
Filters:
Category: Trend
Direction: Both
Indicators: Parabolic SAR
Stops: Fixed
Complexity: Basic
Timeframe: Intraday (5m)
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 cross strategy.
/// Opens long when price moves above SAR and short when price moves below SAR.
/// </summary>
public class PsarTraderStrategy : Strategy
{
private readonly StrategyParam<decimal> _sarStep;
private readonly StrategyParam<decimal> _sarMaxStep;
private readonly StrategyParam<DataType> _candleType;
private bool _prevPriceAboveSar;
private bool _hasPrev;
public decimal SarStep { get => _sarStep.Value; set => _sarStep.Value = value; }
public decimal SarMaxStep { get => _sarMaxStep.Value; set => _sarMaxStep.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public PsarTraderStrategy()
{
_sarStep = Param(nameof(SarStep), 0.001m)
.SetGreaterThanZero()
.SetDisplay("SAR Step", "Acceleration factor for Parabolic SAR", "Parabolic SAR");
_sarMaxStep = Param(nameof(SarMaxStep), 0.2m)
.SetGreaterThanZero()
.SetDisplay("SAR Max Step", "Maximum acceleration factor", "Parabolic SAR");
_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();
_prevPriceAboveSar = false;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var parabolicSar = new ParabolicSar
{
AccelerationStep = SarStep,
AccelerationMax = SarMaxStep
};
SubscribeCandles(CandleType).Bind(parabolicSar, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal sarValue)
{
if (candle.State != CandleStates.Finished) return;
var isPriceAboveSar = candle.ClosePrice > sarValue;
if (!_hasPrev)
{
_prevPriceAboveSar = isPriceAboveSar;
_hasPrev = true;
return;
}
if (_prevPriceAboveSar != isPriceAboveSar)
{
if (isPriceAboveSar && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (!isPriceAboveSar && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
}
_prevPriceAboveSar = isPriceAboveSar;
}
}
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 psar_trader_strategy(Strategy):
def __init__(self):
super(psar_trader_strategy, self).__init__()
self._sar_step = self.Param("SarStep", 0.001) \
.SetDisplay("SAR Step", "Acceleration factor for Parabolic SAR", "Parabolic SAR")
self._sar_max_step = self.Param("SarMaxStep", 0.2) \
.SetDisplay("SAR Max Step", "Maximum acceleration factor", "Parabolic SAR")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_price_above_sar = False
self._has_prev = False
@property
def sar_step(self):
return self._sar_step.Value
@property
def sar_max_step(self):
return self._sar_max_step.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(psar_trader_strategy, self).OnReseted()
self._prev_price_above_sar = False
self._has_prev = False
def OnStarted2(self, time):
super(psar_trader_strategy, self).OnStarted2(time)
psar = ParabolicSar()
psar.AccelerationStep = self.sar_step
psar.AccelerationMax = self.sar_max_step
self.SubscribeCandles(self.candle_type).Bind(psar, self.process_candle).Start()
def process_candle(self, candle, sar_value):
if candle.State != CandleStates.Finished:
return
is_price_above_sar = float(candle.ClosePrice) > float(sar_value)
if not self._has_prev:
self._prev_price_above_sar = is_price_above_sar
self._has_prev = True
return
if self._prev_price_above_sar != is_price_above_sar:
if is_price_above_sar and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif not is_price_above_sar and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_price_above_sar = is_price_above_sar
def CreateClone(self):
return psar_trader_strategy()