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;
	}
}