Ver no GitHub

Estratégia Bago EA

A estratégia replica o consultor especialista de MetaTrader "Bago EA". Opera com rompimentos de seguidor de tendência confirmados por cruzamentos de média móvel e RSI, enquanto o túnel Vegas (par de EMA 144/169) fornece filtros espaciais e âncoras de trailing.

Lógica de Trading

  1. Preparação de indicadores
    • Duas EMAs (períodos FastPeriod e SlowPeriod, método MaMethod, preço MaAppliedPrice).
    • EMAs do túnel Vegas (períodos 144 e 169, mesmo método/preço) para detectar o canal direcional.
    • RSI (RsiPeriod, RsiAppliedPrice) para confirmação.
    • Todas as conversões preço-para-pip usam o PriceStep do instrumento com ajuste de 3/5 dígitos como o EA original.
  2. Máquina de estados de cruzamento
    • O cruzamento de EMA para cima/baixo e o cruzamento de RSI acima/abaixo de 50 são rastreados com temporizadores. Cada estado permanece ativo por CrossEffectiveBars candles e é redefinido pelo cruzamento oposto ou pelo tempo limite.
    • Os cruzamentos do túnel marcam quando o preço se move de um lado do túnel Vegas para o outro.
  3. Condições de entrada
    • Comprado: tanto o cruzamento de EMA quanto o de RSI estão ativos para cima e o preço:
      • Fecha acima do túnel em pelo menos TunnelBandWidthPips mas não mais que TunnelSafeZonePips, com corpo de candle altista, ou
      • Fecha abaixo do túnel em TunnelBandWidthPips, sinalizando um rebote de baixo.
    • Vendido: lógica espelho com cruzamentos de EMA/RSI para baixo.
    • O trading é permitido apenas dentro das sessões habilitadas (Londres 07–16, Nova York 12–21, Tóquio 00–08, ou qualquer barra que feche após as 23:00).
  4. Gestão de ordens
    • Novas posições são abertas com volume TradeVolume. Posições opostas são fechadas antes de reverter.
    • O stop inicial é definido em StopLossPips a partir do preço de fechamento. Os deslocamentos stop-para-túnel usam StopLossToFiboPips.
  5. Trailing e saídas parciais
    • À medida que o preço avança além dos níveis do túnel Vegas, o stop se move:
      • Dentro do túnel, o stop para em tunnel ± (TrailingStepX + StopLossToFibo).
      • Fora do túnel, um trailing fixo de TrailingStopPips é aplicado atrás do preço.
    • Saídas parciais fecham PartialClose1Volume em TrailingStep1Pips e PartialClose2Volume em TrailingStep2Pips uma vez que o preço viajou longe o suficiente da entrada.
    • Um cruzamento oposto de EMA/RSI fecha toda a posição imediatamente.
  6. Stops
    • Ordens de proteção são mantidas como ordens de stop de mercado. São canceladas sempre que a posição é fechada.

Parâmetros

Parâmetro Tipo Padrão Descrição
TradeVolume decimal 3 Tamanho da ordem em lotes.
StopLossPips decimal 30 Distância inicial de stop-loss.
StopLossToFiboPips decimal 20 Buffer adicional ao estacionar stops em torno do túnel Vegas.
TrailingStopPips decimal 30 Distância do trailing stop quando o preço sai do túnel.
TrailingStep1Pips decimal 55 Primeira camada de lucro para saída parcial e realocação de stop.
TrailingStep2Pips decimal 89 Segunda camada de lucro para saída parcial e trailing.
TrailingStep3Pips decimal 144 Camada final antes de usar trailing puro.
PartialClose1Volume decimal 1 Volume fechado em TrailingStep1Pips.
PartialClose2Volume decimal 1 Volume fechado em TrailingStep2Pips.
CrossEffectiveBars int 2 Número de barras durante as quais cruzamentos de EMA/RSI permanecem válidos.
TunnelBandWidthPips decimal 5 Zona neutra em torno do túnel Vegas onde nenhuma operação é feita.
TunnelSafeZonePips decimal 120 Distância máxima acima do túnel para entradas compradas (e abaixo para vendidas).
EnableLondonSession bool true Permitir sinais durante as horas de Londres.
EnableNewYorkSession bool true Permitir sinais durante as horas de Nova York.
EnableTokyoSession bool false Permitir sinais durante as horas de Tóquio.
FastPeriod int 5 Comprimento de EMA rápida.
SlowPeriod int 12 Comprimento de EMA lenta.
MaShift int 0 Deslocamento horizontal aplicado a todas as EMAs.
MaMethod MovingAverageType Exponential Modo de suavização da média móvel.
MaAppliedPrice AppliedPriceType Close Preço da candle enviado para as EMAs.
RsiPeriod int 21 Comprimento de médio do RSI.
RsiAppliedPrice AppliedPriceType Close Preço da candle enviado para o RSI.
CandleType DataType Período H1 Série de candles para o cálculo.

Notas

  • A estratégia mantém os estados dos indicadores mesmo fora do horário de trading, exatamente como no EA original.
  • As ordens de stop são gerenciadas via API de alto nível (SellStop/BuyStop) para imitar as chamadas PositionModify do MetaTrader.
  • Todos os comentários e estrutura seguem as diretrizes do repositório (tabulações para recuo, comentários em inglês).
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Bago EA trend-following strategy using EMA crossover with RSI confirmation.
/// Buys when fast EMA crosses above slow EMA and RSI above 50.
/// Sells on reverse conditions.
/// </summary>
public class BagoEaStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	/// <summary>
	/// Fast EMA period.
	/// </summary>
	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	/// <summary>
	/// Slow EMA period.
	/// </summary>
	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	/// <summary>
	/// Stop-loss distance in price steps.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Take-profit distance in price steps.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="BagoEaStrategy"/> class.
	/// </summary>
	public BagoEaStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Indicator");

		_slowPeriod = Param(nameof(SlowPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Indicator");

		_stopLossPoints = Param(nameof(StopLossPoints), 200)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

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

		_fast = null;
		_slow = null;
		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
		_cooldown = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

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

		if (!_fast.IsFormed || !_slow.IsFormed)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		if (_cooldown > 0)
		{
			_cooldown--;
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		// Check SL/TP
		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}

		// EMA crossover
		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();

			BuyMarket();
			_entryPrice = close;
			_cooldown = 80;
		}
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();

			SellMarket();
			_entryPrice = close;
			_cooldown = 80;
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
	}
}