O indicador Parabolic SAR coloca pontos acima ou abaixo do preço para sinalizar a direção da tendência. Quando os pontos mudam de lado, pode marcar o fim do movimento anterior. Esta estratégia entra em operações nessa mudança, esperando uma reversão de curto prazo.
Os testes indicam um retorno anual médio de aproximadamente 148%. Funciona melhor no mercado de câmbio.
Um valor de Parabolic SAR é mantido em execução para cada candle. Se o indicador passa de acima do preço para abaixo, uma posição comprada é aberta. Se passa de abaixo para acima, uma operação vendida é executada. O método não usa um alvo de lucro explícito e tipicamente depende de saída discricional ou stops de trailing fora do código de amostra.
Como o SAR reage rapidamente, sinais falsos podem ocorrer em mercados lateralizados, portanto é melhor usado quando o preço faz oscilações decisivas.
Detalhes
Critérios de entrada: O Parabolic SAR muda de lado em relação ao preço.
Comprado/Vendido: Ambos.
Critérios de saída: Stop manual ou externo.
Stops: Não definido.
Valores padrão:
InitialAcceleration = 0.02
MaxAcceleration = 0.2
CandleType = 15 minute
Filtros:
Categoria: Seguidor de tendência
Direção: Ambos
Indicadores: Parabolic SAR
Stops: Opcional
Complexidade: Básico
Período: Intradiário
Sazonalidade: Não
Redes neurais: Não
Divergência: Não
Nível de risco: Médio
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 Reversal strategy.
/// Enters long when SAR switches from above to below price.
/// Enters short when SAR switches from below to above price.
/// Uses cooldown to control trade frequency.
/// </summary>
public class ParabolicSarReversalStrategy : Strategy
{
private readonly StrategyParam<decimal> _acceleration;
private readonly StrategyParam<decimal> _accelerationMax;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private bool? _prevSarAbove;
private int _cooldown;
/// <summary>
/// Initial acceleration.
/// </summary>
public decimal Acceleration
{
get => _acceleration.Value;
set => _acceleration.Value = value;
}
/// <summary>
/// Max acceleration.
/// </summary>
public decimal AccelerationMax
{
get => _accelerationMax.Value;
set => _accelerationMax.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public ParabolicSarReversalStrategy()
{
_acceleration = Param(nameof(Acceleration), 0.02m)
.SetRange(0.01m, 0.05m)
.SetDisplay("Acceleration", "Initial acceleration factor", "SAR");
_accelerationMax = Param(nameof(AccelerationMax), 0.2m)
.SetRange(0.1m, 0.3m)
.SetDisplay("Max Acceleration", "Maximum acceleration factor", "SAR");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSarAbove = null;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevSarAbove = null;
_cooldown = 0;
var sar = new ParabolicSar
{
Acceleration = Acceleration,
AccelerationMax = AccelerationMax
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sar, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sar);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal sarValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var isSarAbove = sarValue > candle.ClosePrice;
if (_prevSarAbove == null)
{
_prevSarAbove = isSarAbove;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevSarAbove = isSarAbove;
return;
}
// SAR switched from above to below = bullish signal
var sarSwitchedBelow = _prevSarAbove == true && !isSarAbove;
// SAR switched from below to above = bearish signal
var sarSwitchedAbove = _prevSarAbove == false && isSarAbove;
if (Position == 0 && sarSwitchedBelow)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && sarSwitchedAbove)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && sarSwitchedAbove)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && sarSwitchedBelow)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevSarAbove = isSarAbove;
}
}
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_reversal_strategy(Strategy):
"""
Parabolic SAR Reversal strategy.
Enters long when SAR switches from above to below price.
Enters short when SAR switches from below to above price.
Uses cooldown to control trade frequency.
"""
def __init__(self):
super(parabolic_sar_reversal_strategy, self).__init__()
self._acceleration = self.Param("Acceleration", 0.02).SetDisplay("Acceleration", "Initial acceleration factor", "SAR")
self._acceleration_max = self.Param("AccelerationMax", 0.2).SetDisplay("Max Acceleration", "Maximum acceleration factor", "SAR")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._prev_sar_above = None
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(parabolic_sar_reversal_strategy, self).OnReseted()
self._prev_sar_above = None
self._cooldown = 0
def OnStarted2(self, time):
super(parabolic_sar_reversal_strategy, self).OnStarted2(time)
self._prev_sar_above = None
self._cooldown = 0
sar = ParabolicSar()
sar.Acceleration = self._acceleration.Value
sar.AccelerationMax = self._acceleration_max.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sar, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sar)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sar_val):
if candle.State != CandleStates.Finished:
return
sv = float(sar_val)
close = float(candle.ClosePrice)
is_sar_above = sv > close
if self._prev_sar_above is None:
self._prev_sar_above = is_sar_above
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_sar_above = is_sar_above
return
cd = self._cooldown_bars.Value
# SAR switched from above to below = bullish signal
sar_switched_below = self._prev_sar_above == True and not is_sar_above
# SAR switched from below to above = bearish signal
sar_switched_above = self._prev_sar_above == False and is_sar_above
if self.Position == 0 and sar_switched_below:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and sar_switched_above:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and sar_switched_above:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and sar_switched_below:
self.BuyMarket()
self._cooldown = cd
self._prev_sar_above = is_sar_above
def CreateClone(self):
return parabolic_sar_reversal_strategy()