Parabolic SAR El límite es un puerto directo del asesor experto MT4 ytg_Parabolic_exp.mq4. El sistema mantiene continuamente las órdenes limitadas de compra y venta pegadas al valor Parabolic SAR y permite que el mercado introduzca la orden en una operación. Una vez completada, la estrategia supervisa la posición abierta y realiza salidas de stop-loss o take-profit utilizando velas extremas, reflejando el comportamiento original de MQL.
Lógica de la estrategia
La estrategia se suscribe a una serie de velas configurables (período de tiempo de 4 horas de forma predeterminada) y calcula el indicador Parabolic SAR con el mismo paso y valores máximos que el script MT4.
En cada vela terminada:
Si el punto SAR está debajo del mínimo de la barra y la mejor oferta está al menos MinOrderDistancePoints por encima del precio SAR, se coloca (o realinea) una orden de límite de compra exactamente al valor SAR.
Si el punto SAR está arriba del máximo de la barra y la mejor demanda está al menos MinOrderDistancePoints por debajo del precio SAR, se coloca (o realinea) una orden de límite de venta a ese precio SAR.
Sólo se mantiene una orden pendiente por lado. Cuando el SAR se mueve, la orden pendiente activa se cancela y se envía una nueva en el nivel actualizado.
Cuando se ejecuta una orden pendiente, las distancias de stop-loss y take-profit (expresadas en puntos) se convierten a precios absolutos utilizando el paso del precio del valor. Esos niveles se almacenan como límites protectores virtuales.
Cada nueva vela comprueba los límites registrados. Si el rango de velas toca el nivel de stop o take, la estrategia cierra inmediatamente la posición correspondiente y restablece el estado de protección.
Parámetros
CandleType – período de tiempo para velas de señal. El valor predeterminado es velas de 4 horas para coincidir con el parámetro de entrada MT4 timeframe.
SarStep – Parabolic SAR factor de aceleración (step en MT4). Controla la rapidez con la que SAR alcanza el precio.
SarMaximum – aceleración máxima (maximum en MT4). Limita la velocidad SAR.
StopLossPoints – distancia en puntos entre el precio de entrada y el nivel de stop. Establezca en 0 para desactivar.
TakeProfitPoints – distancia en puntos entre el precio de entrada y el nivel de obtención de beneficios. Establezca en 0 para desactivar.
MinOrderDistancePoints: imita MODE_STOPLEVEL en MT4. Las órdenes pendientes se envían solo si el precio de mercado está más lejos que esta distancia del valor SAR.
OrderVolume – lotes (volumen) para cada orden pendiente. Alinéelo con el VolumeStep del instrumento.
Todas las distancias basadas en puntos se convierten a precios utilizando el instrumento PriceStep, por lo que el comportamiento se mantiene constante en todos los mercados.
Comportamiento comercial
Funciona en ambas direcciones simultáneamente: una orden límite de compra y venta puede coexistir si el SAR cambia el precio.
Las órdenes pendientes siempre están alineadas con la última lectura de SAR; Los pedidos obsoletos se cancelan antes de que se registre uno nuevo.
Las salidas de stop-loss y take-profit se manejan virtualmente a través de máximos y mínimos de velas, porque las estrategias StockSharp de alto nivel no vinculan SL/TP directamente a las órdenes pendientes.
La estrategia se basa en los mejores datos de oferta/demanda cuando están disponibles; de lo contrario, el precio de cierre de la vela se utiliza como alternativa para evaluar las condiciones de distancia.
Notas de portabilidad
MinOrderDistancePoints tiene como valor predeterminado 0, pero puede establecerlo en el nivel de parada del corredor si el centro de negociación exige una distancia mínima.
Los niveles de protección se restablecen automáticamente cuando se cierra la posición o cuando se cancela la orden pendiente, manteniendo la lógica idéntica a la del experto MT4.
Los comentarios dentro del código C# explican el uso de alto nivel de API, el enlace del indicador y el ciclo de vida del pedido para facilitar el mantenimiento.
Consejos de uso
Proporcionar cotizaciones de Nivel 1 para una verificación precisa de la distancia; de lo contrario, asegúrese de que el precio de cierre de la vela sea un buen indicador del precio de mercado actual.
Revise los PriceStep y VolumeStep de su símbolo para que las distancias de los puntos y el volumen del pedido se conviertan en precios y cantidades válidos.
Debido a que las salidas se evalúan en velas completadas, considere usar períodos de tiempo más cortos si necesita una granularidad más fina para el monitoreo 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()