Ver en GitHub

Estrategia HPCS Inter7

Descripción general

La estrategia Hpcs Inter7 es un sistema de ruptura de Bollinger bandas convertido del MetaTrader asesor experto de 4 _HPCS_Inter7_MT4_EA_V01_We.mq4. El algoritmo monitorea las bandas Bollinger estándar calculadas en la serie de velas seleccionada. Cuando el precio cruza fuera de las bandas, lo interpreta como una ruptura de impulso y abre una posición en la dirección de la ruptura. Para cada nueva entrada, la estrategia coloca inmediatamente los objetivos de parada de pérdidas y toma de ganancias a una distancia fija del precio de entrada para replicar el comportamiento original del asesor experto.

Lógica de trading

  • Entrada corta: Cuando la vela anterior cerró por encima de la banda inferior y la última vela cerrada termina por debajo de la banda inferior, la estrategia abre una venta de mercado. Esto recrea la condición original Close[0] < LowerBand[0] && Close[1] > LowerBand[1].
  • Entrada larga: Cuando la vela anterior cerró por debajo de la banda superior y la última vela cerrada termina por encima de la banda superior, la estrategia abre una compra de mercado. Esto replica Close[0] > UpperBand[0] && Close[1] < UpperBand[1] de la implementación MQL.
  • Operación única por vela: El algoritmo recuerda la hora de apertura de la vela que generó la última orden. Se ignora una nueva señal en la misma vela para evitar operaciones duplicadas, reflejando la variable de protección gdt_Candle de MQL4.
  • Órdenes de protección: Inmediatamente después de que se abre una nueva posición, la estrategia llama a SetStopLoss y SetTakeProfit usando la distancia configurada. Ambos se colocan simétricamente alrededor del precio de entrada, por lo que la posición siempre tiene objetivos de riesgo y recompensa predefinidos.

Parámetros

Nombre Descripción Predeterminado Optimizable
BollingerLength Número de velas utilizadas para construir las Bollinger Bandas. 20 si
BollingerDeviation Multiplicador de desviación estándar para el ancho de bandas Bollinger. 2 si
CandleType Serie de velas utilizadas para los cálculos (el valor predeterminado es un período de tiempo de 1 minuto). velas de 1 minuto No
ProtectionDistancePoints Distancia de parada de pérdidas y toma de ganancias expresada en pasos de precio. 10 si

Notas adicionales

  • La estrategia utiliza el nivel alto StockSharp API (SubscribeCandles().Bind(...)) y no almacena matrices de historial personalizadas.
  • StartProtection() se activa al inicio para que la plataforma administre automáticamente las órdenes de protección realizadas por SetStopLoss y SetTakeProfit.
  • El tamaño de la posición está controlado por la propiedad base Strategy.Volume, al igual que el asesor experto original que negoció un volumen fijo de un lote.
  • La estrategia fue diseñada para instrumentos FX donde se implementó el EA original, pero se puede usar en cualquier valor que proporcione señales de banda Bollinger significativas y un valor PriceStep válido.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy converted from _HPCS_Inter7_MT4_EA_V01_We.mq4.
/// Sells when price crosses below the lower Bollinger band and buys when price crosses above the upper band.
/// </summary>
public class HpcsInter7Strategy : Strategy
{
	private readonly StrategyParam<int> _bollingerLength;
	private readonly StrategyParam<decimal> _bollingerDeviation;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _bandPercent;

	private decimal? _prevClose;
	private decimal? _prevLower;
	private decimal? _prevUpper;

	/// <summary>
	/// Initializes a new instance of the <see cref="HpcsInter7Strategy"/> class.
	/// </summary>
	public HpcsInter7Strategy()
	{
		_bollingerLength = Param(nameof(BollingerLength), 20)
			.SetGreaterThanZero()
			.SetDisplay("Bollinger Length", "Number of candles included in the Bollinger Bands calculation", "Indicators");

		_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
			.SetGreaterThanZero()
			.SetDisplay("Bollinger Deviation", "Standard deviation multiplier for the Bollinger Bands", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Time frame used for Bollinger Bands", "General");

		_bandPercent = Param(nameof(BandPercent), 0.01m)
			.SetGreaterThanZero()
			.SetDisplay("Band Percent", "MA percentage band width", "Indicators");
	}

	/// <summary>
	/// Bollinger Bands length.
	/// </summary>
	public int BollingerLength
	{
		get => _bollingerLength.Value;
		set => _bollingerLength.Value = value;
	}

	/// <summary>
	/// Bollinger Bands deviation multiplier.
	/// </summary>
	public decimal BollingerDeviation
	{
		get => _bollingerDeviation.Value;
		set => _bollingerDeviation.Value = value;
	}

	/// <summary>
	/// Candle type used for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public decimal BandPercent
	{
		get => _bandPercent.Value;
		set => _bandPercent.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = null;
		_prevLower = null;
		_prevUpper = null;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevClose = null;
		_prevLower = null;
		_prevUpper = null;

		var bollinger = new ExponentialMovingAverage { Length = BollingerLength };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var upper = middle * (1 + BandPercent);
		var lower = middle * (1 - BandPercent);

		if (_prevClose.HasValue && _prevLower.HasValue && _prevUpper.HasValue)
		{
			// Downward cross through the lower band - open short
			if (_prevClose.Value > _prevLower.Value && candle.ClosePrice < lower && Position >= 0)
			{
				SellMarket();
			}
			// Upward cross through the upper band - open long
			else if (_prevClose.Value < _prevUpper.Value && candle.ClosePrice > upper && Position <= 0)
			{
				BuyMarket();
			}
		}

		_prevClose = candle.ClosePrice;
		_prevLower = lower;
		_prevUpper = upper;
	}
}