Ver no GitHub

Estratégia de Grade OverHedgeV2

A estratégia replica o consultor especialista OverHedge V2 do MetaTrader na API de alto nível do StockSharp. Constrói uma grade com hedge seguindo a direção de uma EMA rápida e uma lenta, alternando então ordens compradas e vendidas dentro de um túnel dinâmico. As posições são adicionadas de acordo com uma progressão geométrica de lotes e toda a cesta é liquidada quando o lucro não realizado agregado atinge o alvo configurado.

Lógica de negociação

  • Filtro de tendência: Uma EMA de 8 períodos deve divergir de uma EMA de 21 períodos em pelo menos MinDistancePips. O filtro decide a direção da primeira negociação em cada ciclo.
  • Túnel de grade: A largura do túnel é igual ao spread atual multiplicado por dois mais TunnelWidthPips convertido em unidades de preço. Define o gatilho do lado oposto assim que o ciclo começa.
  • Alternância de ordens: As primeiras três posições são abertas na direção da tendência. Depois o algoritmo alterna de lado para fazer hedge da exposição usando os mesmos âncoras do túnel como referência.
  • Escalonamento de lotes: Cada ordem subsequente multiplica o volume anterior por BaseMultiplier começando em StartVolume. O tamanho é alinhado às restrições de volume do instrumento.
  • Saída do ciclo: Quando o ganho líquido não realizado por lote do instrumento está acima de MinProfitTargetPips e o lucro total da cesta excede ProfitTargetPips, a estratégia fecha todas as posições abertas e redefine o estado.
  • Desligamento manual: Definir ShutdownGrid como true fecha quaisquer posições restantes e evita novas ordens até que seja desativado.

Condições de entrada

Entradas compradas

  • O filtro de tendência indica tendência de alta (EMA_short - EMA_long > MinDistancePips).
  • O preço Ask é maior ou igual à âncora de compra atual.
  • A estratégia não está em modo de desligamento e a cesta não atingiu seu alvo de lucro.

Entradas vendidas

  • O filtro de tendência indica tendência de baixa (EMA_long - EMA_short > MinDistancePips).
  • O preço Ask é menor ou igual à âncora de venda atual.
  • A flag de desligamento é falsa e o alvo de lucro da cesta ainda não foi atingido.

Gestão de saída

  • Saída de lucro: Quando o lucro não realizado da cesta satisfaz ProfitTargetPips com cada lado aberto ganhando pelo menos MinProfitTargetPips por lote, todas as posições são fechadas a mercado.
  • Saída de emergência: Definir ShutdownGrid como true fecha imediatamente qualquer exposição aberta.

Indicadores e dados

  • EMA de 8 períodos (rápida) e EMA de 21 períodos (lenta) calculadas na série de velas configurada.
  • A assinatura de Nível 1 é usada para rastrear o melhor bid/ask para construir o túnel e comparar as condições de entrada com os spreads em tempo real.

Parâmetros

Parâmetro Descrição
StartVolume Volume inicial da primeira ordem em um ciclo.
BaseMultiplier Multiplicador geométrico aplicado ao volume de cada ordem subsequente.
TunnelWidthPips Largura adicional do túnel em pips adicionada ao dobro do spread atual.
ProfitTargetPips Alvo de lucro da cesta medido em pips convertidos em distância de preço.
MinProfitTargetPips Movimento mínimo favorável por lado antes que a cesta possa fechar.
ShortEmaPeriod Período da EMA rápida usada para confirmação de direção.
LongEmaPeriod Período da EMA lenta usada para confirmação de direção.
MinDistancePips Separação mínima de EMA necessária para declarar uma tendência.
CandleType Período de tempo das velas que alimentam as EMAs e o loop de negociação.
ShutdownGrid Interruptor booleano que força a liquidação e bloqueia novas negociações.

Notas práticas

  • O período de vela padrão é uma hora; ajuste-o para corresponder ao período de tempo usado no EA original.
  • A estratégia depende de dados de melhor bid/ask; forneça cotações de Nível 1 durante o trading ao vivo ou backtesting.
  • Como o StockSharp mantém uma posição líquida por instrumento, compras e vendas alternadas reduzirão ou reverterão a exposição líquida em vez de manter tickets com hedge independentes, mas a lógica da cesta ainda imita a captura de lucro pretendida.
  • Sempre verifique as etapas de volume específicas do instrumento e os tamanhos de tick para que o túnel gerado e a escala de lotes correspondam ao mercado que você negocia.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Grid hedging strategy based on EMA crossover direction.
/// Opens positions on EMA trend, reverses on direction change.
/// </summary>
public class OverHedgeV2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _shortEmaPeriod;
	private readonly StrategyParam<int> _longEmaPeriod;

	private int _prevSignal;

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

	public int ShortEmaPeriod
	{
		get => _shortEmaPeriod.Value;
		set => _shortEmaPeriod.Value = value;
	}

	public int LongEmaPeriod
	{
		get => _longEmaPeriod.Value;
		set => _longEmaPeriod.Value = value;
	}

	public OverHedgeV2Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_shortEmaPeriod = Param(nameof(ShortEmaPeriod), 8)
			.SetGreaterThanZero()
			.SetDisplay("Short EMA", "Fast EMA length", "Indicators");

		_longEmaPeriod = Param(nameof(LongEmaPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("Long EMA", "Slow EMA length", "Indicators");
	}

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

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

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

		_prevSignal = 0;

		var shortEma = new ExponentialMovingAverage { Length = ShortEmaPeriod };
		var longEma = new ExponentialMovingAverage { Length = LongEmaPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var signal = shortEma > longEma ? 1 : shortEma < longEma ? -1 : _prevSignal;

		if (signal == _prevSignal)
			return;

		var oldSignal = _prevSignal;
		_prevSignal = signal;

		if (signal == 1 && oldSignal <= 0)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (signal == -1 && oldSignal >= 0)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}