La Estrategia de Trading Criteria es un enfoque de seguimiento de tendencia multi-marco temporal convertido del asesor experto original MQL4 "Trading Criteria". El port se basa en medias móviles lineales ponderadas, filtros de desviación de momentum y confirmaciones MACD extraídas de marcos temporales de tendencia y mensual. Las características de gestión de riesgo incluyen trailing stops, protección de break-even y objetivos de stop-loss/take-profit configurables.
Lógica de entrada
Marco temporal primario: Usa una media móvil lineal ponderada (LWMA) rápida y lenta. Las señales largas requieren que la MA rápida se mantenga por encima de la lenta; las cortas requieren lo contrario.
Filtro de momentum: Calcula la desviación del momentum (|Momentum-100|) en el marco temporal de tendencia y verifica los tres valores más recientes contra umbrales alcistas o bajistas.
Filtro MACD de tendencia: Evalúa la línea principal del MACD relativa a su línea de señal en el mismo marco temporal de tendencia. Las señales solo se disparan cuando la relación actual se alinea con la barra anterior para evitar cambios rápidos.
Filtro MACD mensual: Confirma el sesgo direccional mayor usando MACD en un marco temporal mensual (o de usuario especificado lento).
Exposición de posición: Limita el tamaño máximo de posición neta a MaxPositions * Volume. Si aparece una nueva señal mientras se mantiene una posición opuesta, la estrategia primero neutralizará la exposición comprando o vendiendo suficiente volumen.
Salida y gestión de riesgo
Stop Loss / Take Profit: Definido via StopLossPoints y TakeProfitPoints, convertido en offsets de precio real usando el tamaño de pip normalizado del instrumento.
Trailing stop: Habilitado con EnableTrailing y TrailingStopPoints. Para largos, el stop rastrea el precio más alto menos la distancia de trailing una vez que el movimiento supera el umbral; los cortos hacen lo contrario usando el precio más bajo.
Movimiento de break-even: Cuando está habilitado (EnableBreakEven), el stop migra al precio de entrada más un offset opcional una vez que el precio de cierre alcanza la distancia BreakEvenTriggerPoints a favor de la posición abierta.
Salidas protectoras manuales: Si la vela toca los niveles calculados de stop o objetivo, la estrategia cierra toda la posición neta en esa barra.
Parámetros
Parámetro
Descripción
CandleType
Marco temporal base para la generación de señales y medias móviles.
TrendCandleType
Marco temporal usado para los filtros de momentum y MACD.
MonthlyCandleType
Marco temporal lento que proporciona confirmación MACD a largo plazo.
FastMaPeriod / SlowMaPeriod
Longitudes de las LWMA rápida y lenta en el marco temporal de entrada.
MomentumPeriod
Período de lookback de momentum en el marco temporal de tendencia.
MomentumBuyThreshold / MomentumSellThreshold
Desviación mínima de 100 requerida para entradas largas o cortas.
MaxPositions
Número máximo de lotes base que pueden permanecer abiertos simultáneamente.
StopLossPoints / TakeProfitPoints
Distancias, en puntos, para stops protectores y objetivos de beneficio.
EnableTrailing / TrailingStopPoints
Activa los trailing stops y define su distancia.
EnableBreakEven
Activa el comportamiento de break-even.
BreakEvenTriggerPoints / BreakEvenOffsetPoints
Controla cuánto debe moverse el precio antes de que el stop se mueva a break-even y qué offset aplicar.
Notas de uso
Adjuntar la estrategia a un instrumento con soporte adecuado de series de velas para los marcos temporales seleccionados.
Asegurarse de que el instrumento proporcione un PriceStep preciso; la implementación ajusta los instrumentos de pips fraccionarios (3 o 5 decimales) para coincidir con las convenciones MQL.
Las protecciones de trailing y break-even operan en velas completadas. En mercados rápidos, los niveles protectores pueden ejecutarse en la siguiente barra cuando ocurre un gap.
El conjunto de parámetros predeterminado refleja los inputs MQL publicados, pero pueden optimizarse via los metadatos de parámetros integrados.
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 TradingCriteriaStrategy : 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 TradingCriteriaStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).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 trading_criteria_strategy(Strategy):
def __init__(self):
super(trading_criteria_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA 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._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(trading_criteria_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(trading_criteria_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
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 = 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 > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.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.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
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 trading_criteria_strategy()