Ver no GitHub

Estratégia de Lacunas (Gaps)

Uma estratégia de price action que reage a lacunas de abertura entre velas consecutivas. Ela espera que uma nova barra abra além da máxima ou mínima anterior por uma distância configurável em pips, entra na direção da reversão esperada e gerencia a operação com stops fixos, alvos e um trailing stop escalonado opcional.

Como funciona

  1. A estratégia monitora um único símbolo usando o período selecionado.
  2. Quando uma nova vela é formada, ela compara o preço de abertura com a vela anterior:
    • Se a abertura estiver abaixo da mínima anterior menos GapPips, a estratégia entra em uma posição comprada esperando um recuo altista.
    • Se a abertura estiver acima da máxima anterior mais GapPips, ela entra em uma posição vendida antecipando uma correção descendente.
  3. Dentro de uma operação, o gerenciamento de risco é tratado inteiramente dentro da estratégia:
    • Um stop-loss fixo é colocado a StopLossPips abaixo (para comprado) ou acima (para vendido) do preço de entrada.
    • Um take-profit fixo é definido a TakeProfitPips do preço de entrada na direção da operação.
    • Um trailing stop pode ser ativado; ele só se move depois que o preço avançou TrailingStopPips + TrailingStepPips e então bloqueia lucros mantendo o stop a TrailingStopPips do preço mais favorável.
  4. Os níveis de proteção são avaliados em cada vela concluída usando os extremos de máxima/mínima para que toques intrabarra disparem saídas de forma confiável.
  5. Ordens abertas são canceladas antes de tomar uma nova posição, e reversões de posição fecham automaticamente o lado oposto.

Parâmetros

  • OrderVolume = 0.1 — volume de trading em lotes para cada nova posição.
  • StopLossPips = 50 — distância do preço de entrada ao nível de stop-loss em pips. Definir como 0 para desabilitar o stop.
  • TakeProfitPips = 50 — distância do preço de entrada ao nível de take-profit em pips. Definir como 0 para desabilitar o alvo.
  • TrailingStopPips = 5 — tamanho do trailing stop em pips. Definir como 0 para desativar o trailing.
  • TrailingStepPips = 5 — melhoria mínima de preço (em pips) necessária antes que o trailing stop se mova novamente.
  • GapPips = 1 — lacuna de abertura mínima, expressa em pips, necessária para gerar um sinal de entrada.
  • CandleType = período de 1 hora — velas usadas para detecção de lacunas e gerenciamento de posições.

Notas de implementação

  • Entradas baseadas em pips são convertidas para distâncias de preço absolutas usando o tamanho de tick do instrumento. Cotações forex de cinco e três dígitos são ajustadas automaticamente para trabalhar com valores reais de pip.
  • A lógica de trailing stop requer que TrailingStepPips seja positivo quando TrailingStopPips está habilitado; caso contrário, a estratégia lança uma exceção na inicialização, espelhando a validação MQL original.
  • A estratégia avalia controles de risco apenas em velas terminadas de acordo com as diretrizes da API de alto nível do StockSharp.
  • O gerenciamento manual de stop e alvo depende de ordens de mercado, portanto não há ordens de proteção separadas no livro.
  • As configurações padrão assumem instrumentos forex; ajuste as distâncias em pips ao negociar ativos com volatilidade ou tamanhos de tick diferentes.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Gap trading strategy. Detects price gaps between candles and trades the gap fill.
/// </summary>
public class GapsStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _gapPercent;

	private decimal? _prevClose;

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

	public decimal GapPercent
	{
		get => _gapPercent.Value;
		set => _gapPercent.Value = value;
	}

	public GapsStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_gapPercent = Param(nameof(GapPercent), 0.05m)
			.SetDisplay("Gap Percent", "Minimum gap size as percentage", "Trading");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

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

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

		_prevClose = null;

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

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent)
		);

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

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

		if (_prevClose == null)
		{
			_prevClose = candle.ClosePrice;
			return;
		}

		var prevClose = _prevClose.Value;
		var open = candle.OpenPrice;
		var close = candle.ClosePrice;
		_prevClose = close;

		if (prevClose == 0)
			return;

		var gapPct = (open - prevClose) / prevClose * 100;

		// Gap up detected - sell expecting gap fill
		if (gapPct > GapPercent && Position == 0)
		{
			SellMarket();
		}
		// Gap down detected - buy expecting gap fill
		else if (gapPct < -GapPercent && Position == 0)
		{
			BuyMarket();
		}
	}
}