Ver no GitHub

Estratégia de Reversão com Barra Externa

Uma barra externa ocorre quando o intervalo de uma vela excede o da vela anterior, criando um breve aumento de volatilidade. Esta estratégia opera contra o movimento se a barra externa fechar na direção oposta à tendência anterior, esperando um retorno ao equilíbrio.

Os testes indicam um retorno anual médio de aproximadamente 121%. Funciona melhor no mercado de criptomoedas.

Quando uma barra externa se forma, o algoritmo determina se a vela é de alta ou de baixa. Uma barra externa de alta após uma queda abre uma posição comprada com stop abaixo da mínima da barra. Uma barra externa de baixa após uma alta aciona uma posição vendida com stop acima de sua máxima. As operações são encerradas se o preço posteriormente romper esse extremo.

A configuração busca reversões rápidas após um impulso exaustivo e é melhor utilizada quando os mercados estão agitados em vez de seguirem uma tendência forte.

Detalhes

  • Critérios de entrada: Barra externa fechando em sentido oposto ao movimento anterior.
  • Comprado/Vendido: Ambos.
  • Critérios de saída: Preço rompendo a máxima/mínima da barra externa ou stop-loss.
  • Stops: Sim, colocados além do padrão.
  • Valores padrão:
    • CandleType = 5 minute
    • StopLossPercent = 1
  • Filtros:
    • Categoria: Padrão
    • Direção: Ambos
    • Indicadores: Candlestick
    • Stops: Sim
    • Complexidade: Intermediário
    • Período: Intradiário
    • Sazonalidade: Não
    • Redes neurais: Não
    • Divergência: Não
    • Nível de risco: Médio
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>
/// Outside Bar Reversal strategy.
/// Detects outside bar patterns (higher high and lower low than previous bar).
/// Bullish outside bar = buy, bearish outside bar = sell.
/// Uses SMA for exit signals.
/// </summary>
public class OutsideBarReversalStrategy : Strategy
{
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cooldownBars;

	private ICandleMessage _prevCandle;
	private int _cooldown;

	/// <summary>
	/// MA Period.
	/// </summary>
	public int MAPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	/// <summary>
	/// Candle type.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Cooldown bars.
	/// </summary>
	public int CooldownBars
	{
		get => _cooldownBars.Value;
		set => _cooldownBars.Value = value;
	}

	/// <summary>
	/// Constructor.
	/// </summary>
	public OutsideBarReversalStrategy()
	{
		_maPeriod = Param(nameof(MAPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Period for SMA", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");

		_cooldownBars = Param(nameof(CooldownBars), 500)
			.SetRange(1, 1000)
			.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
	}

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

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

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

		_prevCandle = null;
		_cooldown = 0;

		var sma = new SimpleMovingAverage { Length = MAPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (_cooldown > 0)
		{
			_cooldown--;
			_prevCandle = candle;
			return;
		}

		if (_prevCandle != null)
		{
			// Outside bar: higher high AND lower low than previous bar
			var isOutsideBar = candle.HighPrice > _prevCandle.HighPrice && candle.LowPrice < _prevCandle.LowPrice;

			if (isOutsideBar)
			{
				var isBullish = candle.ClosePrice > candle.OpenPrice;
				var isBearish = candle.ClosePrice < candle.OpenPrice;

				if (Position == 0 && isBullish)
				{
					BuyMarket();
					_cooldown = CooldownBars;
				}
				else if (Position == 0 && isBearish)
				{
					SellMarket();
					_cooldown = CooldownBars;
				}
			}

			// Exit logic using SMA
			if (Position > 0 && candle.ClosePrice < smaValue)
			{
				SellMarket();
				_cooldown = CooldownBars;
			}
			else if (Position < 0 && candle.ClosePrice > smaValue)
			{
				BuyMarket();
				_cooldown = CooldownBars;
			}
		}

		_prevCandle = candle;
	}
}