La estrategia MACD Power es un sistema de momentum multitemporal convertido del experto asesor MetaTrader original. La lógica combina un par de medias móviles linealmente ponderadas (LWMA) calculadas en el marco temporal principal, dos variantes de MACD, un filtro de momentum en un marco temporal superior y un sesgo MACD mensual. La estrategia intenta participar en movimientos impulsivos una vez que el momentum y las condiciones de tendencia del marco temporal superior se alinean.
Lógica principal
Medias móviles principales – Una LWMA rápida y una lenta del precio típico de la vela (((High + Low + Close) / 3)). La estrategia requiere que la media rápida esté por debajo de la lenta antes de considerar cualquier señal, imitando el código original que espera retrocesos dentro de una pendiente bajista dominante antes de entrar en la dirección del sesgo mensual.
Confirmación dual de MACD – Dos indicadores MACD con parámetros (12, 26, 1) y (6, 13, 1) deben estar ambos por encima de cero para operaciones largas o por debajo de cero para cortas. Estos valores reproducen las condiciones MacdMAIN1 y MacdMAIN2 del experto MQL que miden la aceleración a corto plazo.
Filtro de momentum – El Momentum (longitud 14) se calcula en un marco temporal superior derivado del tamaño de la vela principal (p.ej., base de 15 minutos → momentum de 1 hora). La distancia absoluta desde 100 se monitoriza en las tres últimas lecturas de momentum; al menos una debe superar el umbral configurado para confirmar que el precio se mueve decisivamente.
Sesgo MACD mensual – Un MACD mensual (12, 26, 9) (idéntico a MacdMAIN0/MacdSIGNAL0 en el EA) debe tener su línea principal por encima de la línea de señal para operaciones largas y por debajo para cortas. Esto protege contra operar en contra de la tendencia macro dominante.
Gestión de operaciones
Dimensionamiento de entrada – El parámetro OrderVolume define el tamaño base de la orden. Cuando se requiere una reversión de posición, el motor añade automáticamente la magnitud de la posición opuesta para que el volumen neto se invierta en una sola orden de mercado.
Take profit / stop loss – Las distancias absolutas se expresan en puntos del instrumento y se convierten a precio usando Security.PriceStep (con un respaldo seguro de 1).
Trailing stop – Una vez que el precio se mueve a favor en TrailingActivationPoints, el stop rastrea el precio más alto (largo) o más bajo (corto) con un offset definido por TrailingOffsetPoints.
Punto de equilibrio – Cuando el precio alcanza BreakEvenTriggerPoints, se activa un stop de punto de equilibrio sintético en Entrada ± BreakEvenOffsetPoints. Si el precio retrocede a ese nivel, la posición se cierra.
Límite de operaciones – MaxTrades limita el número de inicios de posición por ejecución; una vez alcanzado el umbral, no se emiten nuevas entradas.
Parámetros
Nombre
Descripción
Por defecto
CandleType
Marco temporal principal para la generación de señales.
Velas de 15 minutos
FastMaLength
Longitud de la LWMA rápida (precio típico).
6
SlowMaLength
Longitud de la LWMA lenta (precio típico).
85
MomentumLength
Período de retroceso del Momentum en el marco temporal superior.
14
MomentumBuyThreshold
Distancia mínima absoluta desde 100 requerida para momentum alcista.
0.3
MomentumSellThreshold
Distancia mínima absoluta desde 100 requerida para momentum bajista.
0.3
TakeProfitPoints
Distancia del take-profit en puntos del instrumento.
50
StopLossPoints
Distancia del stop-loss en puntos del instrumento.
20
TrailingActivationPoints
Beneficio (puntos) requerido antes de que active el trailing.
40
TrailingOffsetPoints
Brecha (puntos) entre el trailing stop y el precio extremo.
40
BreakEvenTriggerPoints
Beneficio (puntos) que activa la protección de punto de equilibrio.
30
BreakEvenOffsetPoints
Desplazamiento (puntos) aplicado al mover el stop al punto de equilibrio.
30
MaxTrades
Número máximo de operaciones permitidas por sesión.
10
OrderVolume
Volumen base de la orden.
1
Diferencias respecto al experto MQL
La estrategia usa la API de alto nivel de StockSharp (SubscribeCandles + Bind/BindEx) en lugar del sondeo directo de ticks. Los valores de los indicadores solo se procesan tras el cierre de las velas.
Los bloques de trailing basado en dinero y stop por capital del código original no están portados porque la gestión monetaria a nivel de cuenta se maneja normalmente por el framework de riesgo de StockSharp. En su lugar, se mantienen el trailing y el punto de equilibrio basados en puntos y pueden configurarse para emular el comportamiento del EA.
Las alertas, notificaciones y asistentes de modificación manual de órdenes de MQL se omiten; el motor de StockSharp gestiona las órdenes directamente mediante llamadas de mercado.
Notas de uso
Elija el marco temporal principal configurando CandleType. El momentum del marco temporal superior y el MACD mensual se derivan automáticamente según el mapeo implementado en GetMomentumCandleType().
Alinee TakeProfitPoints, StopLossPoints y los parámetros de trailing/punto de equilibrio con el tamaño de tick del instrumento. Los valores por defecto reflejan la configuración Forex de 5 dígitos del EA pero pueden adaptarse a otros mercados.
Monitorice el contador MaxTrades al ejecutar backtests automatizados; establézcalo en un número grande si se desea el comportamiento de apilamiento tipo martingala del EA original.
Para análisis visual, active los gráficos en la GUI – la implementación dibuja velas y las dos curvas LWMA por defecto.
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;
public class MacdPowerStrategy : 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 MacdPowerStrategy()
{
_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
class macd_power_strategy(Strategy):
"""
MACD Power: EMA crossover with manual SL/TP via price steps.
"""
def __init__(self):
super(macd_power_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12).SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50).SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200).SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400).SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_power_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(macd_power_strategy, self).OnStarted2(time)
self._fast_ind = ExponentialMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = ExponentialMovingAverage()
self._slow_ind.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
if not self._fast_ind.IsFormed or not self._slow_ind.IsFormed:
self._prev_fast = fast
self._prev_slow = slow
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast
self._prev_slow = slow
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close <= self._entry_price - self._stop_loss_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._take_profit_points.Value > 0 and close >= self._entry_price + self._take_profit_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
elif self.Position < 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close >= self._entry_price + self._stop_loss_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._take_profit_points.Value > 0 and close <= self._entry_price - self._take_profit_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._prev_fast <= self._prev_slow and fast > slow 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 < slow and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return macd_power_strategy()