Esta estrategia replica el asesor experto "MA Cross" de MetaTrader 5 (archivo MA Cross.mq5) dentro del marco de trabajo StockSharp. El sistema observa dos medias móviles configurables y emite órdenes de mercado siempre que la media rápida cruce la media lenta. La implementación mantiene el nivel original de flexibilidad al exponer el método de media móvil, el precio aplicado y el desplazamiento del indicador para ambas curvas.
Lógica de la estrategia
Suscribirse a un flujo único de velas definido por el parámetro CandleType.
Calcular las medias móviles rápida y lenta en cada vela completada. Cada media móvil puede usar uno de cuatro métodos (simple, exponencial, suavizada o ponderada linealmente) y lee uno de los precios aplicados al estilo MetaTrader (cierre, apertura, máximo, mínimo, mediana, típico o ponderado).
Almacenar los valores más recientes del indicador teniendo en cuenta el desplazamiento configurado, de modo que las pruebas de cruce se realicen sobre valores de barras anteriores cuando sea necesario.
Detectar un cruce alcista cuando la media rápida se mueve de por debajo de la media lenta desplazada a por encima. Detectar un cruce bajista cuando ocurre el movimiento contrario.
Emitir órdenes de mercado solo después de que ambos indicadores estén completamente formados y la estrategia esté en línea. Las señales largas cierran cualquier posición corta existente y abren una posición larga de OrderVolume. Las señales cortas cierran cualquier posición larga existente y abren una posición corta del mismo tamaño.
La estrategia opera estrictamente sobre velas completadas y nunca inspecciona datos sin terminar. La lógica de protección se activa a través de StartProtection() para garantizar que StockSharp monitoree la posición abierta en busca de condiciones anormales.
Parámetros
Nombre
Predeterminado
Descripción
FastPeriod
3
Período de la media móvil rápida.
SlowPeriod
13
Período de la media móvil lenta.
FastMethod
Simple
Método de media móvil para la línea rápida (simple, exponencial, suavizada o ponderada linealmente).
SlowMethod
LinearWeighted
Método de media móvil para la línea lenta.
FastPriceType
Close
Precio aplicado usado por la línea rápida (cierre, apertura, máximo, mínimo, mediana, típico, ponderado).
SlowPriceType
Median
Precio aplicado usado por la línea lenta.
FastShift
0
Número de barras completadas usadas para desplazar la media rápida a la izquierda.
SlowShift
0
Número de barras completadas usadas para desplazar la media lenta a la izquierda.
OrderVolume
1
Volumen para cada orden de mercado.
CandleType
Marco temporal de 1 minuto
Serie de datos de velas procesada por la estrategia.
Todos los parámetros pueden optimizarse dentro de StockSharp porque el constructor los registra usando los helpers StrategyParam.
Reglas de trading
Entrada larga: Se activa cuando la media rápida cruza por encima de la media lenta según los valores ajustados por desplazamiento. Si la estrategia ya está corta, envía una única orden de compra a mercado para cerrar la exposición corta y abrir una nueva posición larga. Si no hay posición, compra exactamente OrderVolume.
Entrada corta: Se activa cuando la media rápida cruza por debajo de la media lenta. La exposición larga existente se invierte mediante una única orden de venta a mercado; de lo contrario, la estrategia abre una nueva operación corta de OrderVolume.
Sin escalado adicional: Una vez posicionado, las señales en la misma dirección se ignoran hasta que ocurra el cruce opuesto.
Estilo de ejecución: Las órdenes se envían con BuyMarket o SellMarket. La estrategia no configura niveles de stop-loss o take-profit; la gestión de riesgos puede añadirse a través de otros módulos de StockSharp si es necesario.
Notas de conversión
La creación del indicador refleja las llamadas iMA de MetaTrader. La enumeración personalizada MovingAverageMethods mapea MODE_SMA, MODE_EMA, MODE_SMMA y MODE_LWMA a SimpleMovingAverage, ExponentialMovingAverage, SmoothedMovingAverage y WeightedMovingAverage de StockSharp respectivamente.
El manejo del precio aplicado reproduce las opciones ENUM_APPLIED_PRICE de MetaTrader calculando los precios mediana, típico y ponderado directamente a partir de los datos de las velas.
Los parámetros de desplazamiento reutilizan la lógica original: la estrategia almacena en búfer los valores del indicador y recupera las comparaciones de entrada y salida de barras anteriores cuando FastShift o SlowShift son positivos.
La lógica de gestión de posiciones coincide con el enfoque original donde las señales opuestas primero cierran la posición existente y luego establecen una posición en la nueva dirección en la misma barra.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Moving average crossover strategy converted from MetaTrader 5 script.
/// Implements dual SMA crossover signals.
/// </summary>
public class MaCrossStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrevValues;
/// <summary>
/// Fast moving average period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow moving average period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public MaCrossStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Period for the fast moving average", "Moving Averages")
.SetOptimize(2, 20, 1);
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Period for the slow moving average", "Moving Averages")
.SetOptimize(5, 60, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for calculations", "Data");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_hasPrevValues = false;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrevValues = false;
var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, 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 fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_hasPrevValues)
{
var crossUp = _prevFast <= _prevSlow && fast > slow;
var crossDown = _prevFast >= _prevSlow && fast < slow;
if (crossUp && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
}
else if (crossDown && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
}
_prevFast = fast;
_prevSlow = slow;
_hasPrevValues = 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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ma_cross_strategy(Strategy):
def __init__(self):
super(ma_cross_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 5)
self._slow_period = self.Param("SlowPeriod", 21)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15)))
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev_values = False
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(ma_cross_strategy, self).OnStarted2(time)
self._has_prev_values = False
self._prev_fast = 0.0
self._prev_slow = 0.0
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self.ProcessCandle).Start()
def ProcessCandle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fast = float(fast_val)
slow = float(slow_val)
if self._has_prev_values:
cross_up = self._prev_fast <= self._prev_slow and fast > slow
cross_down = self._prev_fast >= self._prev_slow and fast < slow
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast
self._prev_slow = slow
self._has_prev_values = True
def OnReseted(self):
super(ma_cross_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev_values = False
def CreateClone(self):
return ma_cross_strategy()