Ver no GitHub

Estratégia de Captura de Mercado

Visão geral

A estratégia de Captura de Mercado reproduz a lógica do especialista original do MetaTrader 5. O algoritmo constrói uma grade dinâmica em torno de um preço central em movimento e abre operações no estilo de cobertura sempre que o preço oscila em torno desse centro. As posições são distribuídas acima e abaixo do centro com metas de lucro fixas, enquanto marcos de patrimônio da conta controlam quando liquidar as operações com maiores perdas.

Regras de trading

  • Linha central – a estratégia armazena um nível central interno que começa no fechamento do primeiro candle processado. Quando o mercado se move além do espaçamento de grade configurado, o centro é deslocado passo a passo para acompanhar o preço.
  • Curto inicial – uma posição vendida opcional pode ser aberta imediatamente após o início para corresponder ao comportamento do script MQL.
  • Entradas compradas – uma operação comprada é permitida quando o último fechamento está acima do centro e o candle anterior operou abaixo dele. Uma verificação de proximidade garante que nenhuma outra operação comprada esteja ativa perto do mesmo nível.
  • Entradas vendidas – uma operação vendida é permitida quando o último fechamento está abaixo do centro e o candle anterior operou acima dele. O mesmo filtro de proximidade evita o empilhamento de vendas idênticas.
  • Take profit – cada operação armazena um nível alvo que está a um múltiplo fixo do passo de preço do instrumento a partir do preço de entrada. Máximas dos candles (para comprados) ou mínimas (para vendidos) que atingem o alvo acionam uma saída de mercado.
  • Gerenciamento de patrimônio – a estratégia monitora o patrimônio do portfólio. Após um ganho percentual configurável, fecha uma série das operações com pior desempenho para garantir lucros. Outro limiar percentual define quando reduzir o risco durante a queda liquidando operações perdedoras. Cada vez que um limiar é acionado, a linha de base de patrimônio é recalculada.

Parâmetros

  • Enable Long / Enable Short – permitir ou bloquear operações em cada direção.
  • Grid Steps – espaçamento entre níveis de grade medido em passos de preço.
  • Take Profit Steps – distância de take profit medida em passos de preço.
  • Open Initial Short – habilitar a primeira ordem vendida colocada logo após o início.
  • Use Equity Target – ativar a regra de crescimento de patrimônio para cortar operações perdedoras.
  • Track Drawdown – ativar a regra de redução para cortar operações perdedoras durante a queda.
  • Equity Gain % / Equity Loss % – percentuais de mudança de patrimônio que acionam as regras acima.
  • Loss Trades Up / Loss Trades Down – número máximo de operações perdedoras fechadas quando cada regra é acionada.
  • Candle Type – período ou tipo de candle personalizado usado para o processo de decisão.
  • Volume (propriedade da estratégia) – tamanho da operação para cada ordem de mercado.

Notas

  • A estratégia mantém um registro interno de operações abertas para imitar o estilo de cobertura do especialista original enquanto trabalha com o modelo de posição líquida do StockSharp.
  • Os parâmetros de distância são multiplicados pelo passo de preço do ativo; garanta que o instrumento selecionado exponha um valor PriceStep válido.
  • A lógica opera apenas em candles finalizados. Selecione um tipo de candle que corresponda ao horizonte de trading pretendido, de grades de curtíssimo prazo a grades de swing mais amplas.
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>
/// Market capture strategy using EMA crossover to capture market direction changes.
/// </summary>
public class MarketCaptureStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevFast;
	private decimal? _prevSlow;

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

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

		_fastPeriod = Param(nameof(FastPeriod), 8)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
	}

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

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

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

		_prevFast = null;
		_prevSlow = null;

		var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
		var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		if (_prevFast == null || _prevSlow == null)
		{
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;

		_prevFast = fast;
		_prevSlow = slow;

		if (!prevAbove && currAbove)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (prevAbove && !currAbove)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}