Ver en GitHub

Estrategia de Trading Criteria

Descripción general

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

  1. 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.
  2. 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.
  3. 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.
  4. Filtro MACD mensual: Confirma el sesgo direccional mayor usando MACD en un marco temporal mensual (o de usuario especificado lento).
  5. 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;
	}
}