Emplea una media móvil exponencial de doble suavizado conocida como XMA de 3ª Generación para detectar máximos y mínimos locales. Se abre una posición larga cuando el XMA gira al alza desde un mínimo local. Los cortos se inician cuando el XMA se revierte desde un máximo local. Las posiciones se invierten ante señales opuestas y no se utiliza stop ni take profit explícito.
Detalles
Criterios de entrada: El XMA forma un mínimo o máximo local y se revierte.
Largo/Corto: Ambos lados.
Criterios de salida: Señal opuesta.
Stops: Ninguno.
Valores predeterminados:
MaLength = 50
CandleType = TimeSpan.FromHours(4)
Filtros:
Categoría: Tendencia
Dirección: Ambos
Indicadores: EMA
Stops: No
Complejidad: Básico
Marco temporal: Intradía (4H)
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Medio
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>
/// 3rd Generation XMA reversal strategy using double-smoothed EMA turning points.
/// </summary>
public class ThirdGenerationXmaReversalStrategy : Strategy
{
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<DataType> _candleType;
private decimal _prev1;
private decimal _prev2;
private int _barCount;
public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ThirdGenerationXmaReversalStrategy()
{
_maLength = Param(nameof(MaLength), 50)
.SetDisplay("MA Length", "Base length for the moving average", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prev1 = 0;
_prev2 = 0;
_barCount = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema1 = new ExponentialMovingAverage { Length = MaLength };
var ema2 = new ExponentialMovingAverage { Length = MaLength / 2 > 0 ? MaLength / 2 : 10 };
SubscribeCandles(CandleType).Bind(ema1, ema2, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema1Value, decimal ema2Value)
{
if (candle.State != CandleStates.Finished) return;
// XMA = 2*ema1 - ema2 (third generation concept)
var xma = 2m * ema1Value - ema2Value;
_barCount++;
if (_barCount >= 3)
{
// Local minimum => buy
if (_prev1 < _prev2 && xma > _prev1 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
// Local maximum => sell
else if (_prev1 > _prev2 && xma < _prev1 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
}
_prev2 = _prev1;
_prev1 = xma;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class third_generation_xma_reversal_strategy(Strategy):
def __init__(self):
super(third_generation_xma_reversal_strategy, self).__init__()
self._ma_length = self.Param("MaLength", 50) \
.SetDisplay("MA Length", "Base length for the moving average", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev1 = 0.0
self._prev2 = 0.0
self._bar_count = 0
@property
def ma_length(self):
return self._ma_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(third_generation_xma_reversal_strategy, self).OnReseted()
self._prev1 = 0.0
self._prev2 = 0.0
self._bar_count = 0
def OnStarted2(self, time):
super(third_generation_xma_reversal_strategy, self).OnStarted2(time)
ema1 = ExponentialMovingAverage()
ema1.Length = self.ma_length
ema2 = ExponentialMovingAverage()
half = int(self.ma_length / 2)
ema2.Length = half if half > 0 else 10
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema1, ema2, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, ema1_value, ema2_value):
if candle.State != CandleStates.Finished:
return
# XMA = 2*ema1 - ema2 (third generation concept)
xma = 2 * ema1_value - ema2_value
self._bar_count += 1
if self._bar_count >= 3:
# Local minimum => buy
if self._prev1 < self._prev2 and xma > self._prev1 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Local maximum => sell
elif self._prev1 > self._prev2 and xma < self._prev1 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev2 = self._prev1
self._prev1 = xma
def CreateClone(self):
return third_generation_xma_reversal_strategy()