La Estrategia Russian20 Momentum MA es una conversión directa del asesor experto MetaTrader 5 Russian20-hp1.mq5. El script original fue publicado por Gordago Software Corp. y se basa en un gráfico de dos horas, una media móvil simple (SMA) de 20 períodos y un indicador Momentum de 5 períodos para identificar continuaciones de tendencias a corto plazo. La implementación en StockSharp mantiene el mismo núcleo analítico mientras adapta el manejo de órdenes y la gestión del dinero a la API de estrategia de alto nivel.
Lógica de trading
Frecuencia de datos: Trabaja con el tipo de vela definido por el usuario (el predeterminado son velas de 2 horas, coincidiendo con el marco temporal MQL5 PERIOD_H2). La lógica se ejecuta solo cuando se cierra una vela.
Indicadores:
Media móvil simple con período configurable (predeterminado 20).
Indicador Momentum con período configurable (predeterminado 5). El nivel neutro de Momentum es 100, reflejando la salida predeterminada de MQL5.
Entrada larga: Se activa cuando se satisfacen todas las siguientes condiciones en la última vela cerrada:
El precio de cierre está por encima de la SMA.
El valor de Momentum es mayor que 100 (aceleración positiva).
El precio de cierre es más alto que el cierre de la vela anterior, asegurando momentum ascendente en la acción del precio.
Entrada corta: Se activa cuando se satisfacen todas las siguientes condiciones:
El precio de cierre está por debajo de la SMA.
El valor de Momentum es menor que 100 (aceleración negativa).
El precio de cierre es más bajo que el cierre de la vela anterior.
Salida larga: La estrategia liquida posiciones largas cuando Momentum cae por debajo de 100 o cuando se cruza un umbral de stop-loss o take-profit de protección.
Salida corta: La estrategia liquida posiciones cortas cuando Momentum sube por encima de 100 o cuando se alcanzan los umbrales de protección configurados.
Gestión de riesgos
El asesor experto MQL5 original coloca órdenes fijas de stop loss y take profit en "pips" ajustados para precios Forex de 4 y 5 dígitos. La conversión en C# reproduce este comportamiento:
Calculando un tamaño de pip ajustado a partir del PriceStep del instrumento. Para símbolos con tres o cinco decimales, el tamaño del pip equivale a PriceStep * 10, de lo contrario equivale a PriceStep.
Traduciendo las entradas del usuario para stop loss y take profit en distancias de precio absolutas.
Monitoreando la acción del precio en cada vela cerrada y cerrando la posición cuando el precio cruza los umbrales calculados.
Parámetros
Parámetro
Valor predeterminado
Descripción
CandleType
Velas de 2 horas
Tipo de datos utilizado para la generación de señales.
MovingAverageLength
20
Retrospectiva para el filtro SMA.
MomentumPeriod
5
Retrospectiva para el indicador Momentum.
StopLossBuyPips
50
Distancia de stop-loss largo expresada en pips. Poner 0 para deshabilitar.
TakeProfitBuyPips
50
Distancia de take-profit largo en pips. Poner 0 para deshabilitar.
StopLossSellPips
50
Distancia de stop-loss corto en pips. Poner 0 para deshabilitar.
TakeProfitSellPips
50
Distancia de take-profit corto en pips. Poner 0 para deshabilitar.
Todos los parámetros numéricos están expuestos a través de StrategyParam<T> y marcados como optimizables cuando corresponde, permitiendo backtesting y optimización con herramientas de StockSharp.
Notas de implementación
La estrategia utiliza la API de alto nivel SubscribeCandles().Bind(...) para transmitir datos de velas y obtener simultáneamente valores de SMA y Momentum sin gestión manual de indicadores.
Los niveles de Momentum se evalúan exactamente como en el script MQL5 (100 como nivel neutro). Cualquier brecha más allá de los offsets de stop-loss/take-profit activa una salida de mercado, imitando fielmente la lógica original de colocación de órdenes.
El cierre anterior se almacena en caché para verificar el momentum del precio sin recurrir a búsquedas en colecciones históricas, en línea con las directrices de rendimiento del proyecto.
Los ganchos de visualización (DrawCandles, DrawIndicator, DrawOwnTrades) están conectados por conveniencia cuando el entorno host admite gráficos.
Consejos de uso
El marco temporal y los parámetros predeterminados corresponden a la configuración original del autor. Ajuste el tipo de vela cuando trabaje con instrumentos que no producen barras de 2 horas.
Al operar activos cotizados con tamaños de tick no convencionales, revise el tamaño de pip calculado para asegurarse de que las distancias de stop-loss y take-profit sean realistas.
La estrategia está diseñada para una única posición abierta a la vez. Las operaciones manuales externas o las posiciones simultáneas en el mismo instrumento pueden interferir con la lógica de salida integrada.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Russian20 Momentum MA strategy. Combines SMA filter with momentum confirmation.
/// </summary>
public class Russian20MomentumMaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _momPeriod;
private decimal? _prevMom;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public int MomPeriod
{
get => _momPeriod.Value;
set => _momPeriod.Value = value;
}
public Russian20MomentumMaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "SMA period for trend filter", "Indicators");
_momPeriod = Param(nameof(MomPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Momentum Period", "Momentum lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMom = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMom = null;
var sma = new SimpleMovingAverage { Length = MaPeriod };
var mom = new Momentum { Length = MomPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, mom, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal maVal, decimal momVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevMom = momVal;
return;
}
if (_prevMom == null)
{
_prevMom = momVal;
return;
}
var close = candle.ClosePrice;
// Price above MA + momentum crosses above zero → buy
if (close > maVal && _prevMom.Value <= 100m && momVal > 100m && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Price below MA + momentum crosses below zero → sell
else if (close < maVal && _prevMom.Value >= 100m && momVal < 100m && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevMom = momVal;
}
}
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 SimpleMovingAverage, Momentum
from StockSharp.Algo.Strategies import Strategy
class russian20_momentum_ma_strategy(Strategy):
def __init__(self):
super(russian20_momentum_ma_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._ma_period = self.Param("MaPeriod", 20) \
.SetDisplay("MA Period", "SMA period for trend filter", "Indicators")
self._mom_period = self.Param("MomPeriod", 10) \
.SetDisplay("Momentum Period", "Momentum lookback", "Indicators")
self._prev_mom = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def MaPeriod(self):
return self._ma_period.Value
@property
def MomPeriod(self):
return self._mom_period.Value
def OnReseted(self):
super(russian20_momentum_ma_strategy, self).OnReseted()
self._prev_mom = None
def OnStarted2(self, time):
super(russian20_momentum_ma_strategy, self).OnStarted2(time)
self._prev_mom = None
sma = SimpleMovingAverage()
sma.Length = self.MaPeriod
mom = Momentum()
mom.Length = self.MomPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, mom, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _on_process(self, candle, ma_value, mom_value):
if candle.State != CandleStates.Finished:
return
mv = float(ma_value)
momv = float(mom_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_mom = momv
return
if self._prev_mom is None:
self._prev_mom = momv
return
close = float(candle.ClosePrice)
# Price above MA + momentum crosses above 100
if close > mv and self._prev_mom <= 100.0 and momv > 100.0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Price below MA + momentum crosses below 100
elif close < mv and self._prev_mom >= 100.0 and momv < 100.0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_mom = momv
def CreateClone(self):
return russian20_momentum_ma_strategy()