Esta estrategia es un port del experto MQL5 Exp_ColorX2MA_Digit.
El algoritmo original pinta una media móvil doblemente suavizada en diferentes colores según su pendiente y usa esos colores para generar señales de trading.
En esta versión en C# el comportamiento se aproxima mediante dos medias móviles simples y se opera en sus cruces.
Lógica de trading
Una media móvil rápida suaviza la serie de precios.
Una media móvil lenta suaviza el resultado de la rápida.
Cuando la media rápida cruza hacia arriba a la media lenta, la estrategia abre una posición larga y cierra cualquier posición corta existente.
Cuando la media rápida cruza hacia abajo a la media lenta, la estrategia abre una posición corta y cierra cualquier posición larga existente.
Las señales se procesan solo después de que la vela haya cerrado.
Parámetros
FastLength – longitud del primer suavizado (predeterminado 12).
SlowLength – longitud del segundo suavizado (predeterminado 5).
CandleType – marco temporal de las velas usadas para los cálculos.
La estrategia usa únicamente la API de alto nivel: SubscribeCandles con Bind para alimentar indicadores y BuyMarket/SellMarket para gestionar posiciones. Los comentarios en el código están en inglés para facilitar el mantenimiento.
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>
/// Trend following strategy based on two sequential moving averages.
/// Trades on crossovers of fast and slow SMAs.
/// </summary>
public class ColorX2MaDigitStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorX2MaDigitStrategy()
{
_fastLength = Param(nameof(FastLength), 8)
.SetGreaterThanZero()
.SetDisplay("Fast MA Length", "Length of the first smoothing", "Parameters");
_slowLength = Param(nameof(SlowLength), 21)
.SetGreaterThanZero()
.SetDisplay("Slow MA Length", "Length of the second smoothing", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fastMa = new ExponentialMovingAverage { Length = FastLength };
var slowMa = new ExponentialMovingAverage { Length = SlowLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastMa, slowMa, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastMa);
DrawIndicator(area, slowMa);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastMa, decimal slowMa)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevFast is null || _prevSlow is null)
{
_prevFast = fastMa;
_prevSlow = slowMa;
return;
}
var wasAbove = _prevFast > _prevSlow;
var isAbove = fastMa > slowMa;
// Fast MA crossed above slow MA -> buy
if (!wasAbove && isAbove && Position <= 0)
BuyMarket();
// Fast MA crossed below slow MA -> sell
else if (wasAbove && !isAbove && Position >= 0)
SellMarket();
_prevFast = fastMa;
_prevSlow = slowMa;
}
}
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 color_x2_ma_digit_strategy(Strategy):
def __init__(self):
super(color_x2_ma_digit_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 8) \
.SetDisplay("Fast MA Length", "Length of the first smoothing", "Parameters")
self._slow_length = self.Param("SlowLength", 21) \
.SetDisplay("Slow MA Length", "Length of the second smoothing", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for strategy", "General")
self._prev_fast = None
self._prev_slow = None
@property
def fast_length(self):
return self._fast_length.Value
@property
def slow_length(self):
return self._slow_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_x2_ma_digit_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(color_x2_ma_digit_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.fast_length
slow_ma = ExponentialMovingAverage()
slow_ma.Length = self.slow_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ma, slow_ma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ma)
self.DrawIndicator(area, slow_ma)
self.DrawOwnTrades(area)
def process_candle(self, candle, fast_ma, slow_ma):
if candle.State != CandleStates.Finished:
return
fast_ma = float(fast_ma)
slow_ma = float(slow_ma)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fast_ma
self._prev_slow = slow_ma
return
was_above = self._prev_fast > self._prev_slow
is_above = fast_ma > slow_ma
if not was_above and is_above and self.Position <= 0:
self.BuyMarket()
elif was_above and not is_above and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_ma
self._prev_slow = slow_ma
def CreateClone(self):
return color_x2_ma_digit_strategy()