Un puerto del histórico asesor experto "Gordago EA" de MetaTrader 5. La estrategia opera en el marco temporal base (predeterminado M3) mientras lee señales MACD de un gráfico intradía superior y un filtro estocástico de un gráfico horario. Preserva los parámetros originales de stop/take y la lógica de trailing, pero utiliza la API de alto nivel de StockSharp para las suscripciones de datos y la gestión de órdenes.
Lógica de la estrategia
Datos de mercado
Velas de ejecución principal: configurables, predeterminado velas de tres minutos.
Velas MACD: configurables, predeterminado velas de doce minutos.
Velas estocásticas: configurables, predeterminado velas de una hora.
Indicadores
MACD (rápido 12, lento 26, señal 9) calculado en el marco temporal MACD.
Oscilador estocástico (longitud 5, suavizado %K 3, %D 3) calculado en el marco temporal estocástico.
Condiciones de entrada
Compra: valor MACD actual superior al anterior, MACD anterior por debajo de cero, %K estocástico por debajo del umbral de compra (predeterminado 37) y en alza respecto al valor anterior.
Venta: valor MACD actual inferior al anterior, MACD anterior por encima de cero, %K estocástico por encima del umbral de venta (predeterminado 96) y en caída respecto al valor anterior.
Colocación de órdenes
El volumen de la orden es fijo; cambiar de dirección compensa automáticamente cualquier posición opuesta antes de abrir una nueva.
Existen distancias separadas de stop-loss/take-profit para operaciones largas y cortas (predeterminados: 40/70 pips para largo, 10/40 pips para corto).
Salidas
Los niveles protectores de stop-loss y take-profit se comprueban en cada vela base finalizada.
Un trailing stop se activa cuando el precio avanza más allá de la distancia de trailing configurada más el paso de trailing; una vez activado sigue avanzando hacia el mercado por la distancia de trailing.
El trailing puede introducir un stop de protección incluso cuando el stop original estaba desactivado, reflejando el EA fuente.
Parámetros
OrderVolume – volumen de operación en lotes.
StopLossBuyPips / TakeProfitBuyPips – distancias de stop-loss y take-profit para el lado largo (en pips).
StopLossSellPips / TakeProfitSellPips – distancias de stop-loss y take-profit para el lado corto (en pips).
TrailingStopPips – distancia de trailing en pips; establecer en cero para deshabilitar el trailing.
TrailingStepPips – beneficio adicional mínimo (en pips) antes de que el trailing stop pueda avanzar.
StochasticBuyLevel / StochasticSellLevel – umbrales del oscilador para entradas largas y cortas.
CandleType – marco temporal de trabajo para la lógica de ejecución.
MacdCandleType – marco temporal utilizado para alimentar el indicador MACD.
StochasticCandleType – marco temporal utilizado para alimentar el oscilador estocástico.
StochasticLength, StochasticSignalPeriod, StochasticSmoothing – períodos del oscilador estocástico.
Notas de implementación
Las distancias en pips se convierten a precios usando el PriceStep del instrumento. Si el paso tiene tres o cinco dígitos fraccionarios, la estrategia lo multiplica por diez, reproduciendo el ajuste de pip usado en la implementación MQL original para cotizaciones forex de 3/5 dígitos.
El trailing stop se ignora cuando TrailingStopPips es positivo pero TrailingStepPips no lo es; en ese caso se registra una advertencia.
Debido a que la versión de StockSharp trabaja con eventos de cierre de velas, la lógica de protección se ejecuta una vez por vela finalizada en lugar de en cada tick como en la versión MT5. El comportamiento de gestión de operaciones sigue las reglas originales.
Solo se proporciona la implementación en C#; no se incluye traducción ni carpeta de Python por petición.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Gordago EA strategy. Uses EMA crossover with RSI filter.
/// </summary>
public class GordagoEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevSlow;
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 GordagoEaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
if (_prevFast == null || _prevSlow == null)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fastVal > slowVal;
_prevFast = fastVal;
_prevSlow = slowVal;
if (!prevAbove && currAbove && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (prevAbove && !currAbove && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
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 gordago_ea_strategy(Strategy):
def __init__(self):
super(gordago_ea_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 12) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 26) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(gordago_ea_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(gordago_ea_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return gordago_ea_strategy()