La estrategia es un puerto StockSharp de alto nivel del Tipu MACD EA de MQL4. Opera con un solo símbolo utilizando señales basadas en MACD y refleja las características originales del asesor experto:
Filtro de horario de negociación opcional con dos ventanas horarias configurables.
MACD entradas de cruce de línea cero y línea de señal con longitudes y desplazamiento EMA ajustables.
Gestión automática de posiciones que incluye toma de ganancias, stop-loss, trailing stop y punto de equilibrio.
Limitación de volumen que emula la configuración de "lotes máximos" del código fuente.
Todas las operaciones utilizan órdenes de mercado. Los niveles de protección se rastrean internamente y las órdenes se cierran una vez que una vela atraviesa los niveles de stop-loss o take-profit.
Lógica comercial
Suscríbase al tipo de vela configurado y calcule un indicador MovingAverageConvergenceDivergenceSignal (MACD línea + línea de señal).
Evalúe los valores de MACD usando el cambio seleccionado (MacdShift 0 = vela actual, 1 = vela anterior) y cree señales cruzadas:
Cruce de línea cero (opcional): compre cuando MACD cruce por encima de cero, venda cuando cruce por debajo.
Cruce de línea de señal (opcional): compre cuando MACD cruce por encima de la línea de señal, venda cuando cruce por debajo.
Antes de abrir una posición, asegúrese de que la hora actual pertenezca al menos a una de las dos ventanas horarias cuando el filtro está habilitado.
Cuando aparece una señal larga:
Si la cobertura está deshabilitada y hay una posición corta abierta, ciérrela opcionalmente (CloseOnReverseSignal) u omita la nueva operación.
Realice una orden de compra de mercado por el menor de TradeVolume y el volumen restante hasta alcanzar MaxPositionVolume.
Actualice la instantánea de entrada larga y calcule los niveles de parada/toma de protección si está habilitado.
Cuando aparezca una señal corta, siga la lógica simétrica para las órdenes de venta.
Mientras una posición está activa:
Supervise las paradas y los objetivos en cada vela terminada y cierre la operación si se supera cualquiera de los niveles.
Cuando el seguimiento está habilitado y el precio avanza TrailingPips + TrailingCushionPips, mueva el stop para mantener una distancia de TrailingPips del precio.
Cuando el módulo de equilibrio esté activo y la ganancia supere RiskFreePips, mueva el stop al precio de entrada.
Parámetros
Nombre
Descripción
CandleType
Serie de velas utilizada para los cálculos de MACD.
TradeVolume
Volumen de cada entrada al mercado (lotes).
MaxPositionVolume
Máxima exposición acumulada larga o corta permitida.
UseTimeFilter
Habilita el filtro de horas de negociación de ventana dual.
Zone1StartHour, Zone1EndHour
Horas de inicio/finalización de la primera ventana de negociación (inclusive, hora de intercambio).
Zone2StartHour, Zone2EndHour
Horas de inicio/finalización de la segunda ventana de negociación.
FastPeriod, SlowPeriod, SignalPeriod
MACD EMA rápida, EMA lenta y señal de SMA longitudes.
MacdShift
0 = evaluar la barra actual, 1 = evaluar la barra anterior (que coincide con MQL iShift).
UseZeroCross
Habilita MACD entradas cruzadas de línea cero.
UseSignalCross
Habilita MACD frente a entradas cruzadas de líneas de señal.
AllowHedging
Permite construir exposiciones tanto largas como cortas sin cerrar primero el lado opuesto.
CloseOnReverseSignal
Cierra la posición opuesta cuando aparece una nueva señal (se utiliza cuando la cobertura está desactivada).
UseTakeProfit, TakeProfitPips
Habilita y configura la distancia de toma de ganancias (pips).
UseStopLoss, StopLossPips
Habilita y configura la distancia de stop-loss (pips).
Permite la gestión de seguimiento, establece la distancia de seguimiento y la amortiguación (pips).
UseRiskFree, RiskFreePips
Mueve el stop al punto de equilibrio una vez que la ganancia excede los pips especificados.
Notas de uso
Configure el tipo de vela para que coincida con el período de tiempo utilizado en MetaTrader (barras predeterminadas de 15 minutos).
El tamaño del pip se deriva de Security.PriceStep. Si el instrumento carece de estos metadatos, se utiliza un valor predeterminado de 0,0001.
La estrategia supone la ejecución inmediata de las órdenes de mercado. Cuando funcione en vivo, asegúrese de manejar adecuadamente el deslizamiento si es necesario.
Cuando se desactivan las entradas de línea cero y de línea de señal, la estrategia permanece inactiva.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Tipu MACD EA strategy: MACD signal line crossover.
/// Buys when MACD crosses above signal, sells when crosses below.
/// </summary>
public class TipuMacdEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _signalPeriod;
private readonly StrategyParam<int> _signalCooldownCandles;
private decimal _prevMacd;
private decimal _prevSignal;
private int _candlesSinceTrade;
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 int SignalPeriod { get => _signalPeriod.Value; set => _signalPeriod.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public TipuMacdEaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "MACD fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "MACD slow EMA period", "Indicators");
_signalPeriod = Param(nameof(SignalPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Signal Period", "MACD signal period", "Indicators");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacd = 0;
_prevSignal = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMacd = 0;
_prevSignal = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrev = false;
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd = { ShortMa = { Length = FastPeriod }, LongMa = { Length = SlowPeriod } },
SignalMa = { Length = SignalPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(macd, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished) return;
if (!macdValue.IsFinal) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (macdValue is not MovingAverageConvergenceDivergenceSignalValue typed) return;
if (typed.Macd is not decimal macdMain || typed.Signal is not decimal signal) return;
if (_hasPrev)
{
if (_prevMacd <= _prevSignal && macdMain > signal && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (_prevMacd >= _prevSignal && macdMain < signal && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
_prevMacd = macdMain;
_prevSignal = signal;
_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 MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class tipu_macd_ea_strategy(Strategy):
def __init__(self):
super(tipu_macd_ea_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._fast_period = self.Param("FastPeriod", 12)
self._slow_period = self.Param("SlowPeriod", 26)
self._signal_period = self.Param("SignalPeriod", 9)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 4)
self._prev_macd = 0.0
self._prev_signal = 0.0
self._candles_since_trade = 4
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@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 SignalPeriod(self):
return self._signal_period.Value
@SignalPeriod.setter
def SignalPeriod(self, value):
self._signal_period.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(tipu_macd_ea_strategy, self).OnReseted()
self._prev_macd = 0.0
self._prev_signal = 0.0
self._candles_since_trade = self.SignalCooldownCandles
self._has_prev = False
def OnStarted2(self, time):
super(tipu_macd_ea_strategy, self).OnStarted2(time)
self._prev_macd = 0.0
self._prev_signal = 0.0
self._candles_since_trade = self.SignalCooldownCandles
self._has_prev = False
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self.FastPeriod
macd.Macd.LongMa.Length = self.SlowPeriod
macd.SignalMa.Length = self.SignalPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, self._process_candle).Start()
def _process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
if macd_value.Macd is None or macd_value.Signal is None:
return
macd_main = float(macd_value.Macd)
signal = float(macd_value.Signal)
if self._has_prev:
if self._prev_macd <= self._prev_signal and macd_main > signal and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif self._prev_macd >= self._prev_signal and macd_main < signal and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
self._prev_macd = macd_main
self._prev_signal = signal
self._has_prev = True
def CreateClone(self):
return tipu_macd_ea_strategy()