Esta estrategia porta el asesor experto MetaTrader 5 Simple EA MA plus MACD a la API de alto nivel de StockSharp. Busca un rompimiento desde una "barra de señal" que satisface dos condiciones: una media móvil desplazada está por debajo/encima de los máximos de la barra, y el histograma MACD acaba de cruzar la línea cero. Cuando la siguiente vela cierra más allá del extremo de la barra de señal, la estrategia entra en la dirección del rompimiento.
La implementación mantiene el comportamiento original del EA:
Detección de señal – en cada vela terminada la estrategia inspecciona la barra anterior. Una media móvil configurable (LWMA por defecto) calculada en el precio aplicado elegido debe ser menor que los máximos de la vela anterior y actual para largos (mayor para cortos). Simultáneamente la línea principal MACD debe haber cruzado cero entre las dos barras precedentes.
Confirmación de señal – una vez almacenada una barra de señal, la estrategia espera la siguiente vela completada. Un cierre por encima del máximo almacenado activa un rompimiento largo; un cierre por debajo del mínimo almacenado activa un rompimiento corto. Si el precio invalida la señal cerrando de vuelta dentro de la barra de señal, la configuración se cancela.
Gestión de posición – los nuevos trades heredan distancias de stop-loss, take-profit y trailing-stop expresadas en pips. Los niveles de protección se convierten a precios absolutos usando el PriceStep del instrumento. Los instrumentos con tres o cinco decimales reciben el ajuste clásico de forex (step × 10) para imitar las definiciones de pip de MetaTrader.
Gestión de riesgo
Stop-loss / take-profit – las distancias opcionales definidas en pips se evalúan en cada cierre de vela. Cuando el mercado imprime más allá del nivel correspondiente, la estrategia sale con una orden de mercado.
Trailing stop – cuando el beneficio supera TrailingStopPips + TrailingStepPips, una referencia de trailing se mueve detrás del mejor precio alcanzado. Si el precio retrocede al nivel de trailing, la posición se cierra. Un paso de trailing de cero reactiva el stop en cada nuevo extremo.
Aplanar en reversión – si aparece un rompimiento opuesto mientras hay una posición opuesta abierta, la estrategia envía una única orden de mercado suficientemente grande para cerrar la exposición existente y abrir el nuevo trade en un solo movimiento.
Notas de implementación
La media móvil soporta los mismos métodos de suavizado y opciones de precio aplicado que MetaTrader (Simple, Exponential, Smoothed, LinearWeighted y precios Close/Open/High/Low/Median/Typical/Weighted).
MaShift reproduce el desplazamiento horizontal del indicador de MetaTrader leyendo valores de barras anteriores antes de evaluar las reglas de rompimiento.
MACD usa el indicador integrado MovingAverageConvergenceDivergence. Solo se requiere el histograma (diferencia entre EMAs rápida y lenta); el período de la línea de señal se retiene para mantenerse fiel a la configuración del EA.
Las suscripciones de velas y el procesamiento de indicadores dependen exclusivamente de la API de alto nivel de StockSharp. No se usa manejo manual de ticks ni buffers de indicadores.
Parámetros
Parámetro
Por defecto
Descripción
Volume
1
Tamaño de la orden para cada entrada de rompimiento.
TakeProfitPips
50
Distancia del objetivo de beneficio expresada en pips (convertida a precio absoluto usando el paso de precio del instrumento). Establecer en 0 para deshabilitar.
StopLossPips
50
Distancia del stop de protección en pips. Establecer en 0 para deshabilitar.
TrailingStopPips
5
Distancia del trailing stop en pips que se fija una vez que el precio avanza suficientemente.
TrailingStepPips
5
Progreso adicional mínimo (en pips) antes de que el trailing stop avance de nuevo.
MaPeriod
100
Longitud de la media móvil usada para validar la barra de señal.
MaShift
0
Desplazamiento horizontal aplicado a la media móvil, emulando el parámetro ma_shift de MetaTrader.
MaMethod
LinearWeighted
Método de suavizado de la media móvil (Simple, Exponential, Smoothed, LinearWeighted).
MaAppliedPrice
Weighted
Fuente de precio alimentada a la media móvil (Close, Open, High, Low, Median, Typical, Weighted).
MacdFastPeriod
12
Período EMA rápida usado en el cálculo MACD.
MacdSlowPeriod
26
Período EMA lenta usado en el cálculo MACD.
MacdSignalPeriod
9
Período de suavizado de la línea de señal retenido para paridad con el EA original.
MacdAppliedPrice
Weighted
Precio aplicado usado al alimentar valores al MACD.
CandleType
1 hour time frame
Serie de velas principal analizada para señales y gestión de trades.
Consejos de uso
Ajustar las protecciones basadas en pips para coincidir con el tamaño de tick del instrumento seleccionado; los valores PriceStep incorrectos en el lado del conector distorsionarán las conversiones de pip.
Para mercados altamente volátiles, considerar aumentar TrailingStepPips para reducir salidas prematuras, o disminuirlo para ajustar el comportamiento del trailing.
Dado que los trades se ejecutan en velas cerradas, el rompimiento debe persistir hasta que la barra se complete; habilitar marcos temporales más pequeños aumenta la frecuencia de trading pero puede introducir más ruido.
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>
/// Simple EA MA plus MACD strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class SimpleEaMaPlusMacdStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public SimpleEaMaPlusMacdStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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
from datatype_extensions import *
from indicator_extensions import *
class simple_ea_ma_plus_macd_strategy(Strategy):
def __init__(self):
super(simple_ea_ma_plus_macd_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._sl_points = self.Param("StopLossPoints", 200).SetNotNegative().SetDisplay("Stop Loss", "SL in price steps", "Risk")
self._tp_points = self.Param("TakeProfitPoints", 400).SetNotNegative().SetDisplay("Take Profit", "TP in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle type", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(simple_ea_ma_plus_macd_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
self._cooldown = 0
def OnStarted2(self, time):
super(simple_ea_ma_plus_macd_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
self._cooldown = 0
self._step = 1.0
if self.Security is not None and self.Security.PriceStep is not None and self.Security.PriceStep > 0:
self._step = float(self.Security.PriceStep)
fast = ExponentialMovingAverage()
fast.Length = self._fast_period.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = self._step
# Manage SL/TP
if self.Position > 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close <= self._entry_price - self._sl_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close >= self._entry_price + self._tp_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close >= self._entry_price + self._sl_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close <= self._entry_price - self._tp_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
# Crossover signals
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return simple_ea_ma_plus_macd_strategy()