Parabolic SAR Limit é uma porta direta do consultor especialista MT4 ytg_Parabolic_exp.mq4. O sistema mantém continuamente as ordens com limite de compra e venda coladas ao valor Parabolic SAR e permite que o mercado coloque a ordem em uma negociação. Uma vez preenchida, a estratégia supervisiona a posição aberta e realiza saídas de stop-loss ou take-profit usando extremos de velas, refletindo o comportamento original MQL.
Lógica da estratégia
A estratégia assina uma série de velas configuráveis (período de 4 horas por padrão) e calcula o indicador Parabolic SAR com o mesmo passo e valores máximos do script MT4.
Em cada vela acabada:
Se o ponto SAR estiver abaixo do mínimo da barra e o melhor lance estiver pelo menos MinOrderDistancePoints acima do preço SAR, um pedido com limite de compra será colocado (ou realinhado) exatamente no valor SAR.
Se o ponto SAR estiver acima da máxima da barra e a melhor venda estiver pelo menos MinOrderDistancePoints abaixo do preço SAR, uma ordem de venda com limite é colocada (ou realinhada) a esse preço SAR.
Apenas uma ordem pendente por lado é mantida. Quando o SAR se move, a ordem pendente ativa é cancelada e uma nova é enviada no nível atualizado.
Quando uma ordem pendente é preenchida, as distâncias de stop-loss e take-profit (expressas em pontos) são convertidas em preços absolutos usando a etapa de preço do título. Esses níveis são armazenados como limites de proteção virtuais.
Cada nova vela verifica os limites registrados. Se o intervalo da vela tocar o nível de stop ou take, a estratégia fecha a posição correspondente imediatamente e redefine o estado de proteção.
Parâmetros
CandleType – prazo para velas de sinal. O padrão é velas de 4 horas para corresponder ao parâmetro de entrada MT4 timeframe.
SarStep – Parabolic SAR fator de aceleração (step em MT4). Controla a rapidez com que o SAR alcança o preço.
SarMaximum – aceleração máxima (maximum em MT4). Limita a velocidade SAR.
StopLossPoints – distância em pontos entre o preço de entrada e o nível de stop. Defina como 0 para desativar.
TakeProfitPoints – distância em pontos entre o preço de entrada e o nível de take-profit. Defina como 0 para desativar.
MinOrderDistancePoints – imita MODE_STOPLEVEL no MT4. As ordens pendentes são enviadas apenas se o preço de mercado estiver mais distante do que esta distância do valor SAR.
OrderVolume – lotes (volume) para cada ordem pendente. Alinhe-o com o VolumeStep do instrumento.
Todas as distâncias baseadas em pontos são convertidas em preços usando o instrumento PriceStep, para que o comportamento permaneça consistente em todos os mercados.
Comportamento de Negociação
Funciona em ambas as direções simultaneamente: uma ordem com limite de compra e uma ordem de venda podem coexistir se o preço SAR mudar.
Os pedidos pendentes são sempre alinhados à leitura mais recente de SAR; pedidos obsoletos são cancelados antes que um novo seja registrado.
As saídas de stop-loss e take-profit são tratadas virtualmente por meio de altos e baixos de velas, porque estratégias StockSharp de alto nível não vinculam SL/TP diretamente a pedidos pendentes.
A estratégia depende dos melhores dados de compra/venda, quando disponíveis; caso contrário, o preço de fechamento da vela será usado como alternativa para avaliar as condições de distância.
Portando Notas
O padrão de MinOrderDistancePoints é 0, mas você pode configurá-lo para o nível de stop da corretora se a plataforma de negociação impor uma distância mínima.
Os níveis de proteção são zerados automaticamente quando a posição é fechada ou quando a ordem pendente é cancelada, mantendo a lógica idêntica à do especialista MT4.
Os comentários dentro do código C# explicam o uso de API de alto nível, a vinculação do indicador e o ciclo de vida do pedido para facilitar a manutenção.
Dicas de uso
Fornece cotações de nível 1 para verificação precisa de distância; caso contrário, certifique-se de que o preço de fechamento da vela seja um bom indicador do preço de mercado atual.
Revise PriceStep e VolumeStep do seu símbolo para que as distâncias dos pontos e o volume do pedido sejam convertidos em preços e quantidades válidos.
Como as saídas são avaliadas em velas concluídas, considere usar prazos mais curtos se precisar de granularidade mais refinada para monitoramento de stop-loss.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Parabolic SAR strategy: enters on SAR flip (price crosses SAR level).
/// Buys when price moves above SAR, sells when price drops below SAR.
/// </summary>
public class ParabolicSarLimitStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevEma;
private decimal _prevClose;
private decimal _entryPrice;
private bool _wasBullish;
private bool _hasPrev;
public ParabolicSarLimitStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_emaLength = Param(nameof(EmaLength), 14)
.SetDisplay("EMA Length", "EMA period acting as dynamic SAR proxy.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR for volatility.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevEma = 0;
_prevClose = 0;
_entryPrice = 0;
_wasBullish = false;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevEma = 0;
_prevClose = 0;
_entryPrice = 0;
_wasBullish = false;
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevEma = emaVal;
_prevClose = close;
_wasBullish = close > emaVal;
_hasPrev = true;
return;
}
var isBullish = close > emaVal;
var flip = isBullish != _wasBullish;
// Exit on SAR flip
if (Position > 0 && flip && !isBullish)
{
SellMarket();
_entryPrice = 0;
}
else if (Position < 0 && flip && isBullish)
{
BuyMarket();
_entryPrice = 0;
}
// Entry on flip
if (Position == 0 && flip)
{
if (isBullish)
{
_entryPrice = close;
BuyMarket();
}
else
{
_entryPrice = close;
SellMarket();
}
}
_prevEma = emaVal;
_prevClose = close;
_wasBullish = isBullish;
}
}
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_limit_strategy(Strategy):
def __init__(self):
super(parabolic_sar_limit_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
self._ema_length = self.Param("EmaLength", 14).SetDisplay("EMA Length", "EMA period acting as dynamic SAR proxy", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR for volatility", "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_limit_strategy, self).OnReseted()
self._prev_ema = 0
self._prev_close = 0
self._entry_price = 0
self._was_bullish = False
self._has_prev = False
def OnStarted2(self, time):
super(parabolic_sar_limit_strategy, self).OnStarted2(time)
self._prev_ema = 0
self._prev_close = 0
self._entry_price = 0
self._was_bullish = False
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(ema, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
if not self._has_prev:
self._prev_ema = ema_val
self._prev_close = close
self._was_bullish = close > ema_val
self._has_prev = True
return
is_bullish = close > ema_val
flip = is_bullish != self._was_bullish
if self.Position > 0 and flip and not is_bullish:
self.SellMarket()
self._entry_price = 0
elif self.Position < 0 and flip and is_bullish:
self.BuyMarket()
self._entry_price = 0
if self.Position == 0 and flip:
if is_bullish:
self._entry_price = close
self.BuyMarket()
else:
self._entry_price = close
self.SellMarket()
self._prev_ema = ema_val
self._prev_close = close
self._was_bullish = is_bullish
def CreateClone(self):
return parabolic_sar_limit_strategy()