Ver no GitHub

Estratégia HPCS Inter5

Visão geral

A Estratégia HPCS Inter5 é um script de impulso único convertido do MetaTrader 4 especialista _HPCS_Inter5_MT4_EA_V01_WE. Quando a estratégia é iniciada, ela inspeciona as últimas velas concluídas e, se o preço de fechamento de cinco barras atrás for superior ao fechamento mais recente, envia uma ordem de compra de mercado. As distâncias protetoras opcionais de stop-loss e take-profit emulam o comportamento baseado em pip do EA original.

Lógica de negociação

  1. Assine a série de velas configurada e mantenha os últimos seis fechamentos concluídos.
  2. Depois que o buffer for preenchido, compare o fechamento de cinco barras atrás com o fechamento mais recente (Close[5] > Close[1] em termos de MetaTrader).
  3. Se a condição for satisfeita e nenhuma negociação tiver sido realizada ainda, envie uma ordem de compra a mercado com o volume configurado.
  4. As ordens de proteção são armadas uma vez na inicialização por meio de StartProtection, usando a conversão de pip no estilo MetaTrader: instrumentos com 3 ou 5 decimais multiplicam PriceStep por 10 para determinar o tamanho do pip, caso contrário, o PriceStep bruto é usado.

A estratégia não abre negociações adicionais e ignora todos os sinais subsequentes quando a primeira posição é preenchida.

Parâmetros

Nome Padrão Descrição
Candle Type Período de 1 minuto Tipo de vela usado para coletar os preços de fechamento. Defina-o para o período de tempo que corresponde ao intervalo de sinal desejado.
Stop Loss (pips) 10 Distância para o stop loss de proteção em MetaTrader pips. Um valor de 0 desativa a parada.
Take Profit (pips) 10 Distância para o take-profit protetor em MetaTrader pips. Um valor de 0 desativa o lucro.
Trade Volume 1 Volume da ordem de mercado submetida quando a condição de entrada é acionada.

Notas de implementação

  • A estratégia requer um Security.PriceStep configurado (ou Security.Step) para converter distâncias pip. Se esta informação estiver faltando, os deslocamentos de proteção permanecerão inativos, mas o sinal de entrada ainda funcionará.
  • Somente velas finalizadas (CandleStates.Finished) são processadas para corresponder ao comportamento MetaTrader que depende de Close[1] e valores mais antigos.
  • O buffer interno contém exatamente seis fechamentos sem usar o histórico do indicador, respeitando a natureza minimalista da fonte EA.
  • IsFormedAndOnlineAndAllowTrading() é verificado antes de enviar o pedido para garantir que o ambiente esteja pronto para execução.

Dicas de uso

  1. Atribua um instrumento Forex com configurações adequadas de preço e volume.
  2. Ajuste o Candle Type para corresponder ao período que você deseja analisar.
  3. Deixe o stop-loss ou o take-profit em zero se preferir gerenciar as saídas manualmente.
  4. Reinicie a estratégia sempre que desejar reavaliar a condição de entrada, pois ela é acionada apenas uma vez por sessão.
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;
	}
}