La estrategia replica el comportamiento del asesor experto MQL/34176/MACross.mq4 original utilizando la API de alto nivel de StockSharp. Negocia un único instrumento en un cruce de media móvil y mantiene todos los controles de riesgo expresados en pips y capital de la cuenta.
Lógica comercial
Se construyen dos promedios móviles simples (SMA) sobre el tipo de vela configurado:
FastPeriod reacciona rápidamente a los cambios de precios.
SlowPeriod suaviza la tendencia a largo plazo.
Al cierre de cada vela terminada se comparan los promedios rápido y lento:
Un cruce alcista (cruce rápido por encima del lento) abre una posición larga. Cualquier corto activo se aplana primero.
Un cruce bajista (cruce rápido por debajo del lento) abre una posición corta después de cerrar una posición larga existente.
Cada entrada utiliza un volumen de mercado fijo derivado de LotSize y alineado con los límites del instrumento (VolumeStep, MinVolume, MaxVolume).
Una vez abierta la posición, la estrategia rastrea dos objetivos de riesgo medidos en pips. El tamaño del pip se infiere automáticamente de Security.Decimals (o PriceStep como alternativa):
TakeProfitPips define la distancia al objetivo de ganancias. Golpearlo implica una salida del mercado en la dirección actual.
StopLossPips define la distancia de parada de protección. Su incumplimiento cierra la posición inmediatamente.
El guardia MinEquity puede pausar las operaciones. Cuando el valor actual de la cartera está por debajo del umbral, la estrategia sigue gestionando la posición activa pero no permite nuevas entradas.
Todos los cálculos funcionan únicamente con velas terminadas, coincidiendo completamente con el asesor experto original que esperó una nueva barra antes de evaluar las medias móviles.
Visualización
Cuando hay un panel de gráfico disponible, la estrategia se traza:
Ingrese velas de la serie suscrita.
Las SMA rápidas y lentas.
Operaciones propias para resaltar las entradas y salidas activadas por las reglas de cruce.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
FastPeriod
int
8
Longitud del rápido SMA que genera señales cruzadas.
SlowPeriod
int
20
Longitud del SMA lento utilizado como línea de tendencia de referencia.
TakeProfitPips
decimal
20
Distancia objetivo de ganancias expresada en pips. El tamaño del pip se deduce de los decimales del instrumento.
StopLossPips
decimal
20
Distancia de parada de protección en pips. Utiliza el mismo cálculo del tamaño del pip que el objetivo de ganancias.
LotSize
decimal
1
Volumen base de pedidos. La estrategia lo redondea al tamaño permitido más cercano antes de enviar órdenes de mercado.
MinEquity
decimal
100
Patrimonio mínimo de la cuenta. Las nuevas operaciones se bloquean mientras el valor de la cartera esté por debajo de este nivel.
CandleType
DataType
TimeSpan.FromMinutes(1).TimeFrame()
Serie de velas utilizada para cálculos SMA y evaluación de señales.
Diferencias vs. versión MQL
El experto original de MQL pasó los precios de límite de pérdidas y obtención de ganancias a OrderSend como cero. El puerto StockSharp emula el mismo comportamiento con salidas manuales que monitorean el precio de cierre de cada vela terminada.
La validación de equidad (cekMinEquity) ahora lee Portfolio.CurrentValue y Portfolio.BeginValue en lugar de AccountEquity() pero conserva la lógica del umbral.
La detección del tamaño del pip refleja el ayudante GetPipPoint: las cotizaciones de 2 o 3 dígitos usan 0,01, las cotizaciones de 4 o 5 dígitos usan 0,0001; de lo contrario, se toma PriceStep.
La estrategia resultante se puede optimizar a través de todos los parámetros expuestos y se combina perfectamente con la infraestructura de gestión de riesgos y gráficos de StockSharp.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// MA Cross strategy: SMA crossover.
/// Buys when fast SMA crosses above slow SMA, sells on cross below.
/// </summary>
public class MacrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public MacrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
BuyMarket();
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
SellMarket();
}
else
{
if (fastValue > slowValue && Position <= 0)
BuyMarket();
else if (fastValue < slowValue && Position >= 0)
SellMarket();
}
_prevFast = fastValue;
_prevSlow = slowValue;
_hasPrev = true;
}
}
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 ma_cross_strategy(Strategy):
"""
MA Cross strategy: EMA crossover.
Buys when fast crosses above slow, sells on cross below.
"""
def __init__(self):
super(ma_cross_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60))).SetDisplay("Candle Type", "Timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_cross_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(ma_cross_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self._fast_period.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
f = float(fast_val)
s = float(slow_val)
if self._has_prev:
if self._prev_fast <= self._prev_slow and f > s and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and f < s and self.Position >= 0:
self.SellMarket()
else:
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_fast = f
self._prev_slow = s
self._has_prev = True
return
if f > s and self.Position <= 0:
self.BuyMarket()
elif f < s and self.Position >= 0:
self.SellMarket()
self._prev_fast = f
self._prev_slow = s
self._has_prev = True
def CreateClone(self):
return ma_cross_strategy()