Parabolic SAR Estratégia de alerta
Visão geral
Esta estratégia é a porta StockSharp do MetaTrader 4 consultor especialista pSAR_alert.mq4. O script original apenas reproduzia um som de alerta sempre que o indicador Parabolic SAR mudava de um lado para o outro do preço. A conversão mantém a mesma lógica de decisão, mas transforma os alertas em ordens de mercado reais, permitindo que o sinal seja negociado automaticamente dentro de StockSharp.
Lógica de negociação
- A estratégia assina o tipo de vela configurado e executa um indicador Parabolic SAR com o fator de aceleração clássico (0,02) e aceleração máxima (0,2) por padrão.
- Para cada vela finalizada, a estratégia compara o valor Parabolic SAR com o fechamento da vela e também rastreia o contexto da vela anterior.
- Quando a vela anterior fechou abaixo de SAR, mas o fechamento atual está acima, o indicador caiu para baixo e uma posição longa foi aberta (ou uma posição curta existente foi revertida).
- Quando a vela anterior fechou acima de SAR, mas o fechamento atual está abaixo, o indicador subiu e uma posição curta foi aberta (ou uma posição longa existente foi revertida).
- O volume de negociação é calculado como o volume da estratégia base mais a posição atual absoluta, garantindo que as reversões saiam totalmente da negociação anterior antes de entrar na nova direção.
StartProtection() é executado no início, então StockSharp gerencia automaticamente desconexões inesperadas enquanto as posições estão abertas.
Parâmetros
| Parâmetro |
Padrão |
Descrição |
AccelerationFactor |
0,02 |
Etapa de aceleração inicial que controla a rapidez com que Parabolic SAR segue os movimentos de preços. |
MaxAccelerationFactor |
0,2 |
Limite superior para a etapa de aceleração, limitando a agressividade com que o SAR acelera durante tendências fortes. |
CandleType |
Período de 5 minutos |
Tipo de dados de mercado utilizado para atualizações de indicadores; altere-o para alternar entre intervalos de tempo ou outras representações de velas. |
Todos os parâmetros são expostos por meio de StrategyParam<T> para que possam ser otimizados diretamente no StockSharp Designer.
Fluxo de trabalho do indicador
- Assine o fluxo de vela configurado via
SubscribeCandles.
- Vincule o fluxo a um indicador
ParabolicSar para que StockSharp o atualize automaticamente.
- Dentro do retorno de chamada de ligação, compare o valor SAR atual com o preço de fechamento e retenha o par SAR/close anterior.
- Detecte cruzamentos avaliando se o SAR se moveu de cima para baixo no fechamento (mudança de alta) ou de baixo para cima (mudança de baixa).
- Execute
BuyMarket ou SellMarket adequadamente e registre mensagens descritivas para cada negociação.
Notas práticas
- Como a estratégia reage apenas ao fechamento confirmado da vela, ela evita sinais prematuros que podem desaparecer antes do término da barra.
- Os parâmetros padrão reproduzem o comportamento do script MQL, mas você pode ajustá-los para adaptar a sensibilidade do Parabolic SAR.
- Vincular a estratégia a instrumentos que apresentem tendências limpas; a lógica de inversão SAR tem melhor desempenho quando as reversões são decisivas em vez de barulhentas.
- A visualização do gráfico é ativada automaticamente quando uma área do gráfico está disponível: velas, o indicador Parabolic SAR e negociações próprias são desenhadas para inspeção rápida.
Arquivos
CS/ParabolicSarCrossoverAlertStrategy.cs – Implementação da estratégia em C#.
README.md – Esta documentação em inglês.
README_zh.md – Tradução chinesa da documentação.
README_ru.md – Tradução russa da documentação.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Parabolic SAR Crossover: EMA crossover with ATR stops.
/// </summary>
public class ParabolicSarCrossoverAlertStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public ParabolicSarCrossoverAlertStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 10)
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 30)
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
public int SlowEmaLength
{
get => _slowEmaLength.Value;
set => _slowEmaLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var close = candle.ClosePrice;
if (Position > 0)
{
if (fastVal < slowVal && _prevFast >= _prevSlow)
{
SellMarket();
_entryPrice = 0;
}
else if (close <= _entryPrice - atrVal * 2m)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow)
{
BuyMarket();
_entryPrice = 0;
}
else if (close >= _entryPrice + atrVal * 2m)
{
BuyMarket();
_entryPrice = 0;
}
}
if (Position == 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow)
{
_entryPrice = close;
BuyMarket();
}
else if (fastVal < slowVal && _prevFast >= _prevSlow)
{
_entryPrice = close;
SellMarket();
}
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}
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 ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class parabolic_sar_crossover_alert_strategy(Strategy):
def __init__(self):
super(parabolic_sar_crossover_alert_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
self._fast_ema_length = self.Param("FastEmaLength", 10).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_ema_length = self.Param("SlowEmaLength", 30).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR period", "Indicators")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(parabolic_sar_crossover_alert_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
def OnStarted2(self, time):
super(parabolic_sar_crossover_alert_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self._fast_ema_length.Value
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self._slow_ema_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast_ema, slow_ema, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val, atr_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0 or atr_val <= 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = candle.ClosePrice
if self.Position > 0:
if (fast_val < slow_val and self._prev_fast >= self._prev_slow) or close <= self._entry_price - atr_val * 2:
self.SellMarket()
self._entry_price = 0
elif self.Position < 0:
if (fast_val > slow_val and self._prev_fast <= self._prev_slow) or close >= self._entry_price + atr_val * 2:
self.BuyMarket()
self._entry_price = 0
if self.Position == 0:
if fast_val > slow_val and self._prev_fast <= self._prev_slow:
self._entry_price = close
self.BuyMarket()
elif fast_val < slow_val and self._prev_fast >= self._prev_slow:
self._entry_price = close
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return parabolic_sar_crossover_alert_strategy()