Parabolic SAR Estrategia de alerta
Descripción general
Esta estrategia es el puerto StockSharp del MetaTrader 4 asesor experto pSAR_alert.mq4. El script original solo reproducía un sonido de alerta cada vez que el indicador Parabolic SAR cambiaba de un lado del precio al otro. La conversión mantiene la misma lógica de decisión pero convierte las alertas en órdenes de mercado reales, lo que permite que la señal se negocie automáticamente dentro de StockSharp.
Lógica de trading
- La estrategia se suscribe al tipo de vela configurado y ejecuta un indicador Parabolic SAR con el factor de aceleración clásico (0,02) y la aceleración máxima (0,2) de forma predeterminada.
- Para cada vela terminada, la estrategia compara el valor Parabolic SAR con el cierre de la vela y también rastrea el contexto de la vela anterior.
- Cuando la vela anterior cerró por debajo del SAR pero el cierre actual está por encima, el indicador ha volteado hacia abajo y se abre una posición larga (o se revierte una posición corta existente).
- Cuando la vela anterior cerró por encima del SAR pero el cierre actual está por debajo, el indicador se ha volteado hacia arriba y se abre una posición corta (o se revierte una posición larga existente).
- El volumen de operaciones se calcula como el volumen de la estrategia base más la posición actual absoluta, lo que garantiza que las reversiones salgan por completo de la operación anterior antes de entrar en la nueva dirección.
StartProtection() se ejecuta al inicio, por lo que StockSharp gestiona automáticamente las desconexiones inesperadas mientras las posiciones están abiertas.
Parámetros
| Parámetro |
Predeterminado |
Descripción |
AccelerationFactor |
0,02 |
Paso de aceleración inicial que controla la rapidez con la que el Parabolic SAR sigue los movimientos de precios. |
MaxAccelerationFactor |
0,2 |
Límite superior para el paso de aceleración, que limita la agresividad con la que SAR acelera durante tendencias fuertes. |
CandleType |
marco de tiempo de 5 minutos |
Tipo de datos de mercado utilizado para actualizaciones de indicadores; cámbielo para cambiar entre marcos de tiempo u otras representaciones de velas. |
Todos los parámetros están expuestos a través de StrategyParam<T> para que puedan optimizarse directamente en el diseñador StockSharp.
Flujo de trabajo del indicador
- Suscríbase al flujo de velas configurado a través de
SubscribeCandles.
- Vincula la transmisión a un indicador
ParabolicSar para que StockSharp la actualice automáticamente.
- Dentro de la devolución de llamada vinculante, compare el valor SAR actual con el precio de cierre y conserve el par SAR/cierre anterior.
- Detecte cruces evaluando si el SAR se movió de arriba hacia abajo en el cierre (giro alcista) o de abajo hacia arriba (giro bajista).
- Ejecute
BuyMarket o SellMarket en consecuencia y registre mensajes descriptivos para cada operación.
Notas prácticas
- Debido a que la estrategia sólo reacciona a los cierres de velas confirmados, evita señales prematuras que pueden desaparecer antes de que termine la barra.
- Los parámetros predeterminados reproducen el comportamiento del script MQL, pero puedes ajustarlos para adaptar la sensibilidad del Parabolic SAR.
- Adjunte la estrategia a instrumentos que tengan una tendencia limpia; la lógica de inversión SAR funciona mejor cuando las inversiones son decisivas en lugar de ruidosas.
- La visualización del gráfico se habilita automáticamente cuando un área del gráfico está disponible: las velas, el indicador Parabolic SAR y las operaciones propias se dibujan para una inspección rápida.
Archivos
CS/ParabolicSarCrossoverAlertStrategy.cs – Implementación C# de la estrategia.
README.md – Esta documentación en inglés.
README_zh.md – Traducción al chino de la documentación.
README_ru.md – Traducción al ruso de la documentación.
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()