Ver en GitHub

Estrategia del corredor de retroceso matutino

Descripción general

La Estrategia del corredor de retroceso matutino replica el comportamiento del asesor experto "3_Otkat_Sys_v1_2" MetaTrader 4. El sistema opera una vez al día durante la sesión de la mañana, evaluando la interacción entre el precio actual y el corredor de precios formado por velas separadas por 29 barras. Reacciona a los retrocesos matutinos después de un fuerte movimiento nocturno e inmediatamente fija niveles asimétricos de toma de ganancias para posiciones largas y cortas.

Lógica de trading

  1. Filtro de sesión: las órdenes se consideran solo dentro de la hora comercial configurada (hora predeterminada de la plataforma 05:00) y durante los primeros minutos de esa hora. Los lunes y viernes están excluidos de acuerdo con el EA original.
  2. Cálculos del corredor de precios: para cada vela completada, la estrategia mantiene una ventana móvil de las barras más recientes. Se compara:
    • el precio de apertura 29 barras atrás con el cierre de la vela anterior (Open[29] - Close[1]),
    • la vela anterior cerró con el precio de apertura 29 barras atrás (Close[1] - Open[29]),
    • la distancia desde el cierre anterior hasta el mínimo más bajo dentro del rango de 29 barras,
    • la distancia desde el máximo más alto en el mismo rango hasta el cierre anterior.
  3. Reglas de entrada: si el movimiento nocturno excede el umbral CorridorOpenClosePoints y el último retroceso cabe dentro del sobre configurado PullbackPoints ± CorridorPullbackPoints, se abre una posición de mercado al comienzo de la sesión de la mañana:
    • Las entradas largas requieren un fuerte movimiento hacia abajo con un retroceso superficial o un movimiento hacia arriba con una continuación extendida por encima del corredor.
    • Las entradas cortas reflejan la lógica de las configuraciones bajistas.
  4. Gestión de posiciones – cada operación recibe:
    • un stop-loss a StopLossPoints * PriceStep del precio de entrada,
    • una toma de ganancias en TakeProfitPoints * PriceStep para posiciones cortas y en (TakeProfitPoints + LongTakeProfitExtraPoints) * PriceStep para posiciones largas.
  5. Salida diaria: cualquier posición que aún esté abierta después del umbral de cierre configurado (predeterminado después de las 22:45) se cierra a la fuerza para evitar que se mantenga durante la noche.

Parámetros

Parámetro Descripción
TakeProfitPoints Distancia base de obtención de beneficios en puntos del instrumento, aplicada a operaciones cortas. Las operaciones largas añaden LongTakeProfitExtraPoints.
StopLossPoints Distancia de parada de protección en los puntos del instrumento.
PullbackPoints Tamaño de retroceso deseado alrededor del cual la estrategia evalúa los retrocesos.
CorridorOpenClosePoints Distancia mínima entre precios separados por 29 barras para confirmar un impulso nocturno.
CorridorPullbackPoints Tolerancia aplicada al umbral de retroceso para crear el corredor de entrada.
LongTakeProfitExtraPoints Se agregaron puntos adicionales al objetivo de obtención de ganancias a largo plazo.
TradeHour Hora (0–23) durante la cual se permiten nuevas entradas.
TradeMinuteLimit Minuto máximo dentro de la hora comercial para aceptar nuevas señales.
CloseHour Hora en la que la estrategia comienza a buscar salidas basadas en tiempo.
CloseMinuteThreshold Minuto dentro de CloseHour después del cual se cierra cualquier posición abierta.
CandleType Marco de tiempo utilizado para las suscripciones de velas (predeterminado 1 minuto).

Notas de implementación

  • La estrategia se basa en Security.PriceStep para convertir entradas basadas en puntos en distancias de precios absolutas. Si el instrumento no proporciona un paso de precio válido, la lógica vuelve a 1.0.
  • Los niveles de stop-loss y take-profit se monitorean en cada vela completa; la estrategia cierra posiciones con órdenes de mercado una vez que se supera el nivel dentro de ese rango de velas.
  • La ventana móvil contiene las últimas 60 velas para cubrir los cálculos de 29 barras requeridos e imitar los ayudantes Lowest/Highest utilizados en MetaTrader.
  • La visualización de gráficos (velas y operaciones propias) está disponible automáticamente cuando se crea un área de gráfico en la aplicación host.

Consejos de uso

  • Asegúrese de que el volumen de la cuenta comercial (propiedad Volume) esté configurado antes de comenzar la estrategia; EA nunca escala el tamaño de la posición dinámicamente.
  • Mantenga la fuente de datos alineada con la zona horaria de la sesión que esperaba el asesor experto original para mantener un comportamiento idéntico.
  • Optimice los parámetros del corredor al aplicar la estrategia a mercados con diferentes perfiles de volatilidad, porque los umbrales basados en puntos se ajustaron para el instrumento original.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class MorningPullbackCorridorStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MorningPullbackCorridorStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = default;
		_prevSlow = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevFast = fast;
		_prevSlow = slow;
	}
}