Ver en GitHub

Para Max V2

Descripción general

Para Max V2 es un puerto del MetaTrader 4 asesor experto for_max_v2.mq4. La estrategia espera patrones envolventes específicos de dos velas y luego coloca un par simétrico de órdenes buy-stop y sell-stop alrededor de la vela más reciente. Una vez que se completa una orden de ruptura, se elimina la orden pendiente opuesta y la posición se administra con paradas fijas, niveles de obtención de ganancias opcionales y una rutina de seguimiento que primero bloquea una pequeña ganancia en el punto de equilibrio y luego sigue el precio.

Lógica estratégica

Detección de patrones envolventes

El perito original expone dos bloques de entrada y ambos se conservan:

  • Configuración de tipo 1: escanea las velas Max Search anteriores (omitiendo la barra actual) y espera a que el mínimo más bajo dentro de ese rango ocurra hace dos barras o que el máximo más alto ocurra hace dos barras. Cuando eso sucede, la vela dos barras atrás debe engullir la vela anterior (máximo más alto y mínimo más bajo). La configuración se coloca alrededor de la vela terminada más reciente.
  • Configuración de tipo 2: también escanea las velas Max Search anteriores, pero busca que el extremo aparezca una barra atrás. Además, la vela que está una barra atrás debe envolver a la vela dos barras atrás. Luego se coloca una horquilla alrededor de la vela más reciente. Ambas configuraciones pueden coexistir; cada uno gestiona sus propias órdenes pendientes y su reloj de vencimiento.

Pendiente de realizar el pedido

  • Precios de entrada: las órdenes de compra se colocan en el máximo de la vela anterior más Gap Points, las órdenes de venta en el mínimo de la vela anterior menos Gap Points.
  • Stop-loss: para el Tipo 1, el stop largo está anclado en el mínimo de la vela dos barras atrás (menos el hueco) y el stop corto en el máximo de esa vela (más el hueco). El tipo 2 utiliza la vela anterior para ambos lados.
  • Take-profit – opcional. Los objetivos largos suman Gap Points + Buy Take Profit Points al máximo anterior y los cortos restan Gap Points + Sell Take Profit Points del mínimo anterior. Establecer las entradas de obtención de beneficios en 0 deshabilita los objetivos respectivos.
  • Vencimiento: cada combinación lleva una marca de tiempo de validez calculada como Order Expiry (bars) multiplicada por el período de tiempo de vela configurado. Si las órdenes pendientes todavía están funcionando cuando se alcanza la marca de tiempo, ambas partes se cancelan.

Gestión de posiciones

  • Una vez que se completa un stop de compra, se cancelan todas las órdenes de stop de venta restantes de cualquiera de las configuraciones; la regla simétrica se aplica después de una entrada breve.
  • Las paradas y los objetivos se controlan en las velas completadas. Si el mínimo de una vela alcanza el stop largo (o el máximo alcanza el stop corto), la posición se cierra con una orden de mercado. Se utiliza el mismo enfoque para los niveles de obtención de beneficios.
  • La rutina de equilibrio (Break-even Trigger y Break-even Offset) mueve el stop al precio de entrada más/menos el desplazamiento configurado una vez que la posición avanza por el monto de activación.
  • El bloque final mantiene los puntos de parada Long/Short Trailing Buffer alejados de la mejor excursión, pero solo después de que el precio haya viajado lo suficiente (y opcionalmente solo después de que la operación ya sea rentable). Trailing Step evita ajustes demasiado frecuentes al requerir una mejora mínima antes de apretar nuevamente el tope.

Parámetros

  • Volumen: volumen de orden para cada orden de parada pendiente.
  • Comprar Take Profit (puntos): distancia en puntos utilizada para calcular el take-profit largo (establecido en 0 para desactivarlo).
  • Vender Take Profit (puntos): distancia en puntos utilizada para calcular la toma de ganancias corta (establecida en 0 para desactivarla).
  • Gap (puntos) – buffer agregado a máximos/mínimos antes de colocar entradas de stop y plegado en la distancia de toma de ganancias.
  • Profundidad de búsqueda: número de velas terminadas escaneadas al verificar configuraciones envolventes de Tipo 1 y Tipo 2.
  • Vencimiento de la orden (barras): número de longitudes de vela que una combinación pendiente permanece activa antes de que se cancelen ambos lados.
  • Activador de equilibrio (puntos): umbral de beneficio que activa el ajuste del punto de equilibrio.
  • Compensación del punto de equilibrio (puntos): colchón adicional que se agrega al precio de entrada cuando se coloca el punto de equilibrio.
  • Buffer de seguimiento largo (puntos): distancia de seguimiento para posiciones largas una vez que se ha alcanzado el punto de equilibrio.
  • Búfer de seguimiento corto (puntos): distancia de seguimiento para posiciones cortas una vez que se ha alcanzado el punto de equilibrio.
  • Paso de seguimiento (puntos): se requiere una mejora mínima en la ubicación de la parada antes de actualizar la parada de seguimiento nuevamente.
  • Seguro solo después de la ganancia: si está habilitado, el seguimiento espera hasta que la posición se haya movido más allá del buffer antes de activarse.
  • Tipo de vela: período de tiempo de las velas utilizadas para la detección de patrones, el vencimiento de la orden y el procesamiento de salida.

Notas adicionales

  • Las compensaciones de precios expresadas en “puntos” dependen del valor PriceStep. Los símbolos con cinco (o tres) decimales se convierten automáticamente a tamaños de pips fraccionarios como en MetaTrader.
  • Stop Loss y Take Profits se ejecutan a través de órdenes de mercado dentro de la estrategia para reflejar el comportamiento de EA de gestionar niveles en velas cerradas.
  • La estrategia no implementa la función vhod_3 no utilizada de la fuente original; sólo se trasladaron los dos bloques de entrada activos.
  • Este paquete contiene sólo la implementación de C#; no se proporciona ninguna versión de Python.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// For Max V2: N-bar engulfing breakout with EMA filter and ATR stops.
/// </summary>
public class ForMaxV2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<int> _lookback;

	private decimal _entryPrice;
	private decimal _prevHigh;
	private decimal _prevLow;
	private readonly decimal[] _highs = new decimal[10];
	private readonly decimal[] _lows = new decimal[10];
	private int _barCount;

	public ForMaxV2Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_emaLength = Param(nameof(EmaLength), 30)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");

		_lookback = Param(nameof(Lookback), 10)
			.SetDisplay("Lookback", "N-bar channel lookback.", "Indicators");
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public int Lookback
	{
		get => _lookback.Value;
		set => _lookback.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_entryPrice = 0;
		_barCount = 0;
		_prevHigh = 0;
		_prevLow = 0;
		Array.Clear(_highs, 0, _highs.Length);
		Array.Clear(_lows, 0, _lows.Length);
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_entryPrice = 0;
		_barCount = 0;
		_prevHigh = 0;
		_prevLow = 0;

		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, atr, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, ema);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var len = Math.Min(Lookback, _highs.Length);
		var idx = _barCount % len;
		_highs[idx] = candle.HighPrice;
		_lows[idx] = candle.LowPrice;
		_barCount++;

		if (_barCount < len || atrVal <= 0)
			return;

		var high = decimal.MinValue;
		var low = decimal.MaxValue;
		for (var i = 0; i < len; i++)
		{
			if (_highs[i] > high) high = _highs[i];
			if (_lows[i] < low) low = _lows[i];
		}

		var close = candle.ClosePrice;

		if (_prevHigh == 0 || _prevLow == 0)
		{
			_prevHigh = high;
			_prevLow = low;
			return;
		}

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 3m || close <= _entryPrice - atrVal * 1.5m)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 3m || close >= _entryPrice + atrVal * 1.5m)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		if (Position == 0)
		{
			if (close > _prevHigh && close > emaVal)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (close < _prevLow && close < emaVal)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevHigh = high;
		_prevLow = low;
	}
}