Ver en GitHub

Estrategia HPCS Inter5

Descripción general

La Estrategia HPCS Inter5 es un script de impulso de un solo disparo convertido del MetaTrader 4 experto _HPCS_Inter5_MT4_EA_V01_WE. Cuando comienza la estrategia, inspecciona las últimas velas completadas y, si el precio de cierre de hace cinco barras es más alto que el cierre más reciente, envía una orden de compra de mercado. Las distancias protectoras opcionales de stop-loss y take-profit emulan el comportamiento basado en pips del EA original.

Lógica de trading

  1. Suscríbase a la serie de velas configuradas y mantenga los últimos seis cierres completos.
  2. Una vez que se llene el búfer, compare el cierre de hace cinco barras con el último cierre (Close[5] > Close[1] en términos MetaTrader).
  3. Si se cumple la condición y aún no se ha realizado ninguna operación, envíe una orden de compra de mercado con el volumen configurado.
  4. Las órdenes de protección se activan una vez al inicio hasta StartProtection, utilizando la conversión de pips estilo MetaTrader: los instrumentos con 3 o 5 decimales multiplican PriceStep por 10 para determinar el tamaño del pip; de lo contrario, se utiliza el PriceStep sin procesar.

La estrategia no abre operaciones adicionales e ignora todas las señales posteriores una vez que se llena la primera posición.

Parámetros

Nombre Predeterminado Descripción
Candle Type marco de tiempo de 1 minuto Tipo de vela utilizada para recoger los precios de cierre. Configúrelo en el período de tiempo que coincida con el intervalo de señal deseado.
Stop Loss (pips) 10 Distancia del stop-loss de protección en MetaTrader pips. Un valor de 0 desactiva la parada.
Take Profit (pips) 10 Distancia para la toma de ganancias protectora en MetaTrader pips. Un valor de 0 deshabilita la toma de ganancias.
Trade Volume 1 Volumen de la orden de mercado presentada cuando se activa la condición de entrada.

Notas de implementación

  • La estrategia requiere un Security.PriceStep (o Security.Step) configurado para convertir distancias de pips. Si falta esta información, las compensaciones de protección permanecen inactivas pero la señal de entrada aún funciona.
  • Solo se procesan velas terminadas (CandleStates.Finished) para que coincidan con el comportamiento MetaTrader que se basa en Close[1] y valores anteriores.
  • El buffer interno mantiene exactamente seis cierres sin utilizar el historial del indicador, respetando la naturaleza minimalista de la fuente EA.
  • IsFormedAndOnlineAndAllowTrading() se verifica antes de enviar la orden para garantizar que el entorno esté listo para la ejecución.

Consejos de uso

  1. Asigne un instrumento Forex con la configuración adecuada de precio y volumen.
  2. Ajuste el Candle Type para que coincida con el período de tiempo que desea analizar.
  3. Deje el stop-loss o el take-profit en cero si prefiere gestionar las salidas manualmente.
  4. Reinicie la estrategia siempre que desee volver a evaluar la condición de entrada porque solo se activa una vez por sesión.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

using StockSharp.Algo;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Single-shot momentum strategy converted from the "_HPCS_Inter5" MetaTrader script.
/// Places one market buy when the close price from five bars ago exceeds the most recent close.
/// </summary>
public class HpcsInter5Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _stopLossPips;
	private readonly StrategyParam<int> _takeProfitPips;
	private readonly StrategyParam<decimal> _tradeVolume;

	private readonly decimal?[] _recentCloses = new decimal?[6];
	private decimal _pipSize;
	private bool _wasLongSignal;
	private bool _hasSignal;

	/// <summary>
	/// Candle type used to evaluate the closing prices.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Stop-loss distance expressed in MetaTrader-style pips.
	/// </summary>
	public int StopLossPips
	{
		get => _stopLossPips.Value;
		set => _stopLossPips.Value = value;
	}

	/// <summary>
	/// Take-profit distance expressed in MetaTrader-style pips.
	/// </summary>
	public int TakeProfitPips
	{
		get => _takeProfitPips.Value;
		set => _takeProfitPips.Value = value;
	}

	/// <summary>
	/// Trade volume submitted with the market entry.
	/// </summary>
	public decimal TradeVolume
	{
		get => _tradeVolume.Value;
		set => _tradeVolume.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="HpcsInter5Strategy"/> class.
	/// </summary>
	public HpcsInter5Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(120).TimeFrame())
			.SetDisplay("Candle Type", "Candle type used for the close comparison", "General");

		_stopLossPips = Param(nameof(StopLossPips), 20)
			.SetDisplay("Stop Loss (pips)", "Stop-loss distance expressed in pips", "Risk Management");

		_takeProfitPips = Param(nameof(TakeProfitPips), 20)
			.SetDisplay("Take Profit (pips)", "Take-profit distance expressed in pips", "Risk Management");

		_tradeVolume = Param(nameof(TradeVolume), 1m)
			.SetGreaterThanZero()
			.SetDisplay("Trade Volume", "Volume submitted with the market entry", "Trading");
	}

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

		Array.Clear(_recentCloses, 0, _recentCloses.Length);
		_pipSize = 0m;
		_wasLongSignal = false;
		_hasSignal = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		if (Security is null)
			throw new InvalidOperationException("Security must be assigned before starting the strategy.");

		base.OnStarted2(time);

		InitializePipSize();
		Volume = TradeVolume;
		_wasLongSignal = false;
		_hasSignal = false;

		var stopLoss = StopLossPips > 0 && _pipSize > 0m
			? new Unit(StopLossPips * _pipSize, UnitTypes.Absolute)
			: null;

		var takeProfit = TakeProfitPips > 0 && _pipSize > 0m
			? new Unit(TakeProfitPips * _pipSize, UnitTypes.Absolute)
			: null;

		if (stopLoss != null || takeProfit != null)
			StartProtection(stopLoss: stopLoss, takeProfit: takeProfit);

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

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

		ShiftCloses(candle.ClosePrice);

		if (_recentCloses[1] is not decimal lastClose || _recentCloses[5] is not decimal olderClose)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var threshold = lastClose * 0.005m;
		var longSignal = olderClose - lastClose > threshold;
		var shortSignal = lastClose - olderClose > threshold;
		var crossedLong = longSignal && (!_hasSignal || !_wasLongSignal);
		var crossedShort = shortSignal && (!_hasSignal || _wasLongSignal);

		if (crossedLong && Position <= 0)
		{
			BuyMarket();
		}
		else if (crossedShort && Position >= 0)
		{
			SellMarket();
		}

		if (longSignal || shortSignal)
		{
			_wasLongSignal = longSignal;
			_hasSignal = true;
		}
	}

	private void ShiftCloses(decimal close)
	{
		for (var i = _recentCloses.Length - 1; i > 0; i--)
			_recentCloses[i] = _recentCloses[i - 1];

		_recentCloses[0] = close;
	}

	private void InitializePipSize()
	{
		var step = Security.PriceStep ?? 0.01m;
		if (step <= 0m)
			step = 0.01m;

		var pipFactor = Security.Decimals is 3 or 5 ? 10m : 1m;
		_pipSize = step * pipFactor;
	}
}