Ver no GitHub

Estratégia de Rompimento BB

Visão geral

A Estratégia de Rompimento BB replica o expert advisor MetaTrader Breakthrough_BB dentro da API de alto nível do StockSharp. O sistema combina Bandas de Bollinger com uma média móvel simples rápida para capturar rompimentos explosivos que ocorrem após a compressão do preço perto dos limites da banda. As operações são geradas exclusivamente em candles completos para manter sinais determinísticos e espelhar o comportamento original do MQL5.

Lógica de negociação

  • Filtro de tendência: Uma média móvel simples (SMA) com período configurável valida a direção da tendência. A estratégia compara o último valor da SMA com o valor da SMA de quatro barras antes. Operações compradas exigem que a SMA tenha inclinação ascendente, enquanto vendidas exigem inclinação descendente.
  • Rompimento das Bandas de Bollinger: A estratégia observa como o fechamento de quatro barras atrás interagiu com a banda superior ou inferior de Bollinger e compara com o preço de fechamento mais recente. Um rompimento válido ocorre quando o preço se move de dentro da banda para fora entre esses dois momentos.
  • Modelo de posição única: O algoritmo mantém no máximo uma posição aberta. Qualquer operação aberta é fechada antes de avaliar novas entradas para evitar exposição sobreposta.

Condições de entrada

Configuração comprada

  1. O preço de fechamento de quatro candles atrás estava abaixo da Banda de Bollinger superior.
  2. O preço de fechamento mais recente terminou acima da Banda de Bollinger superior atual.
  3. O valor da SMA calculado no último candle é maior que o valor da SMA de quatro candles atrás (inclinação positiva).
  4. Nenhuma posição está aberta atualmente.

Configuração vendida

  1. O preço de fechamento de quatro candles atrás estava acima da Banda de Bollinger inferior.
  2. O preço de fechamento mais recente terminou abaixo da Banda de Bollinger inferior atual.
  3. O valor da SMA calculado no último candle é menor que o valor da SMA de quatro candles atrás (inclinação negativa).
  4. Nenhuma posição está aberta atualmente.

Quando uma condição de entrada é satisfeita, a estratégia envia uma ordem a mercado usando o parâmetro de volume configurado.

Regras de saída

  • Saída de posição comprada: Se uma operação comprada estiver ativa e o último fechamento cair abaixo da linha média de Bollinger, a posição é fechada imediatamente com uma ordem de venda a mercado.
  • Saída de posição vendida: Se uma operação vendida estiver aberta e o último fechamento subir acima da linha média de Bollinger, a posição é coberta com uma ordem de compra a mercado.

Essas regras de saída imitam o expert advisor original, que removia operações sempre que o mercado revertia de volta para dentro da linha média da banda.

Indicadores

  • Média Móvel Simples (SMA): Define o viés direcional e fornece a comparação de inclinação em um intervalo de quatro candles.
  • Bandas de Bollinger: Fornece os envelopes superior, médio e inferior usados para detectar entradas por rompimento e gerenciar saídas.

Parâmetros

Nome Descrição Padrão Otimizável
MaPeriod Comprimento da SMA usada para o filtro de tendência. 9 ✔
BandsPeriod Comprimento de retrospectiva para cálculos das Bandas de Bollinger. 28 ✔
Deviation Multiplicador de desvio padrão aplicado às Bandas de Bollinger. 1.6 ✔
Volume Tamanho da ordem (em lotes ou contratos, dependendo do instrumento). 1 ✔
CandleType Tipo de agregação de candles processado pela estratégia. Período de 1 hora ✖

Todos os parâmetros expõem metadados StrategyParam do StockSharp para que possam ser ajustados na interface ou otimizados no designer.

Requisitos de dados

  • Funciona com qualquer instrumento que forneça dados de candles compatíveis com o CandleType selecionado.
  • Os sinais são avaliados apenas em candles concluídos. Candles incompletos são ignorados para manter a lógica determinística.
  • A configuração padrão usa candles horários, mas qualquer período suportado pela fonte de dados pode ser fornecido.

Notas adicionais

  • O algoritmo evita consultas ao histórico do indicador e mantém um cache deslizante de quatro barras para valores de fechamento e SMA, seguindo as diretrizes do projeto.
  • Recursos de proteção como stop-loss ou take-profit podem ser adicionados via StartProtection se desejado; eles não fazem parte da implementação MQL original e, portanto, são omitidos aqui.
  • Como a estratégia emite ordens a mercado, garanta liquidez suficiente no instrumento escolhido para minimizar o deslizamento.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Breakout strategy that trades Bollinger Bands breakouts with a moving average trend filter.
/// </summary>
public class BreakthroughBbStrategy : Strategy
{
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<int> _bandsPeriod;
	private readonly StrategyParam<decimal> _deviation;
	private readonly StrategyParam<DataType> _candleType;

	private SimpleMovingAverage _sma;
	private BollingerBands _bollingerBands;

	private decimal? _closeLag0;
	private decimal? _closeLag1;
	private decimal? _closeLag2;
	private decimal? _closeLag3;

	private decimal? _maLag0;
	private decimal? _maLag1;
	private decimal? _maLag2;
	private decimal? _maLag3;

	/// <summary>
	/// Moving average period that defines the long term trend.
	/// </summary>
	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	/// <summary>
	/// Bollinger Bands lookback period.
	/// </summary>
	public int BandsPeriod
	{
		get => _bandsPeriod.Value;
		set => _bandsPeriod.Value = value;
	}

	/// <summary>
	/// Bollinger Bands width measured in standard deviations.
	/// </summary>
	public decimal Deviation
	{
		get => _deviation.Value;
		set => _deviation.Value = value;
	}


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

	/// <summary>
	/// Initializes a new instance of <see cref="BreakthroughBbStrategy"/>.
	/// </summary>
	public BreakthroughBbStrategy()
	{
		_maPeriod = Param(nameof(MaPeriod), 9)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Simple moving average length", "Parameters")
			;

		_bandsPeriod = Param(nameof(BandsPeriod), 28)
			.SetGreaterThanZero()
			.SetDisplay("Bands Period", "Bollinger Bands lookback", "Parameters")
			;

		_deviation = Param(nameof(Deviation), 1.6m)
			.SetGreaterThanZero()
			.SetDisplay("Deviation", "Bollinger Bands width in deviations", "Parameters")
			;


		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle series processed by the strategy", "General");
	}

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

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

		_sma = default;
		_bollingerBands = default;

		_closeLag0 = null;
		_closeLag1 = null;
		_closeLag2 = null;
		_closeLag3 = null;

		_maLag0 = null;
		_maLag1 = null;
		_maLag2 = null;
		_maLag3 = null;
	}

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

		_sma = new SimpleMovingAverage { Length = MaPeriod };
		_bollingerBands = new BollingerBands
		{
			Length = BandsPeriod,
			Width = Deviation
		};

		var subscription = SubscribeCandles(CandleType);

		subscription
			.BindEx(_sma, _bollingerBands, ProcessCandle)
			.Start();
	}

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

		var smaValue = smaIndValue.IsFormed ? smaIndValue.ToDecimal() : 0m;
		var bb = bbValue as IBollingerBandsValue;
		var middleBand = bb?.MovingAverage ?? 0m;
		var upperBand = bb?.UpBand ?? 0m;
		var lowerBand = bb?.LowBand ?? 0m;

		var close = candle.ClosePrice;
		var maPrev4 = _maLag2;
		var closePrev4 = _closeLag2;

		if (_sma is null || _bollingerBands is null)
		{
			UpdateHistory(close, smaValue);
			return;
		}

		if (!_sma.IsFormed || !_bollingerBands.IsFormed)
		{
			UpdateHistory(close, smaValue);
			return;
		}

		if (Position > 0 && close < middleBand)
		{
			SellMarket();
			UpdateHistory(close, smaValue);
			return;
		}

		if (Position < 0 && close > middleBand)
		{
			BuyMarket();
			UpdateHistory(close, smaValue);
			return;
		}

		if (maPrev4 is null || closePrev4 is null)
		{
			UpdateHistory(close, smaValue);
			return;
		}

		if (Position == 0)
		{
			if (closePrev4.Value < upperBand && close > upperBand && smaValue > maPrev4.Value)
			{
				BuyMarket();
				UpdateHistory(close, smaValue);
				return;
			}

			if (closePrev4.Value > lowerBand && close < lowerBand && smaValue < maPrev4.Value)
			{
				SellMarket();
				UpdateHistory(close, smaValue);
				return;
			}
		}

		UpdateHistory(close, smaValue);
	}

	private void UpdateHistory(decimal close, decimal maValue)
	{
		_maLag3 = _maLag2;
		_maLag2 = _maLag1;
		_maLag1 = _maLag0;
		_maLag0 = maValue;

		_closeLag3 = _closeLag2;
		_closeLag2 = _closeLag1;
		_closeLag1 = _closeLag0;
		_closeLag0 = close;
	}
}