Ver no GitHub

Estratégia Bollinger Band Squeeze Breakout

Visão geral

A estratégia replica o expert advisor original do MetaTrader 4 "BOLINGER BAND SQUEEZE" usando a API de alto nível do StockSharp. Procura por períodos onde as Bollinger Bands se contraem e então entra em operações assim que as bandas se expandem, desde que os filtros de momentum e tendência confirmem o movimento. A conversão mantém a lógica de confirmação multi-períodos e transforma os blocos de gestão monetária em expressões idiomáticas do StockSharp.

Lógica de negociação

  1. Squeeze e expansão de bandas
    • As Bollinger Bands (comprimento 20, desvio 2 por padrão) são calculadas no período de trabalho.
    • A largura do candle concluído mais recente é comparada contra a largura RetraceCandles barras atrás.
    • Um breakout válido requer que a razão de largura exceda SqueezeRatio, sinalizando que o preço está se expandindo para fora do squeeze.
  2. Filtro de tendência
    • Duas médias móveis ponderadas (WMA 6 e WMA 85 no preço típico) definem a tendência imediata. Operações compradas requerem que a WMA rápida esteja acima da WMA lenta, vendidas o contrário.
  3. Confirmação de momentum
    • Um indicador de Momentum de período superior (comprimento 14) verifica se o preço se desvia suficientemente do nível 100. O desvio máximo dos últimos três valores do período superior deve exceder o limiar específico de direção.
    • O período superior é selecionado automaticamente para corresponder ao mapeamento usado no script MT4 (ex., M15 → H1, H1 → D1, D1 → mensal). Os dados semanais também recorrem à confirmação mensal. Se nenhum período superior estiver disponível, o filtro de momentum é ignorado.
  4. Filtro macro
    • Um MACD mensal (12/26/9) garante que o momentum de longo prazo corresponde à direção da operação (linha MACD acima do sinal para comprados, abaixo para vendidos).
  5. Regras de entrada
    • Comprados: expansão de bandas, WMA rápida acima da WMA lenta, MACD mensal altista, desvio de momentum do período superior acima de MomentumBuyThreshold, e sobreposição estrutural de candles (candle[-2].Low < candle[-1].High).
    • Vendidos: expansão de bandas, WMA rápida abaixo da WMA lenta, MACD mensal baixista, desvio de momentum acima de MomentumSellThreshold, e a condição de candle espelhada (candle[-1].Low < candle[-2].High).
  6. Regras de saída
    • As posições são fechadas quando o preço fecha em ou além da Bollinger Band exterior na direção da operação (ou seja, comprados saem na banda superior, vendidos na banda inferior), refletindo a implementação MT4.
    • StartProtection() habilita a infraestrutura de ordens protetoras do StockSharp para que extensões de stop-loss/take-profit possam ser adicionadas se necessário.

Indicadores e assinaturas de dados

  • Candles do período primário definidos por CandleType.
  • Candles do período superior para confirmação de momentum (mapeados automaticamente do período base).
  • Candles mensais para filtragem MACD (aproximação de 30 dias).
  • Indicadores: Bollinger Bands, duas Médias Móveis Ponderadas (preço típico), Momentum e MovingAverageConvergenceDivergenceSignal.

Parâmetros

Nome Padrão Descrição
CandleType Candles de 15 minutos Período de trabalho primário.
BollingerPeriod 20 Comprimento da Bollinger Band.
BollingerWidth 2.0 Multiplicador de desvio padrão da Bollinger Band.
SqueezeRatio 1.1 Razão mínima de expansão de largura entre bandas atuais e históricas.
RetraceCandles 10 Retrospectiva usada para comparação de squeeze.
FastMaLength 6 Comprimento da WMA rápida (preço típico).
SlowMaLength 85 Comprimento da WMA lenta (preço típico).
MomentumLength 14 Período de Momentum no período superior.
MomentumBuyThreshold 0.3 Desvio mínimo de 100 necessário para validar entradas compradas.
MomentumSellThreshold 0.3 Desvio mínimo de 100 necessário para validar entradas vendidas.

Todos os parâmetros são expostos como valores StrategyParam<T> e podem ser otimizados dentro do StockSharp Designer ou em tempo de execução.

Notas de implementação

  • A estratégia usa SubscribeCandles().BindEx(...) para manter o cabeamento do indicador declarativo e evita coleções de indicadores manuais, conforme exigido pelas diretrizes da API de alto nível.
  • As médias móveis ponderadas são impulsionadas pelo preço típico dentro do callback de processamento de candles para preservar o comportamento dos cálculos LWMA no script MT4.
  • Os valores de momentum do período superior são armazenados em uma fila de três elementos para imitar os retornos 1–3 de iMomentum do código original.
  • Os valores MACD mensais persistem em campos de classe para que cada candle do período primário tenha acesso ao viés de longo prazo mais recente.
  • As saídas acionadas pelas bandas exteriores substituem os blocos de trailing stop/break-even MT4 enquanto retêm a intenção visual de fechar quando o preço toca o envelope oposto.
  • A estratégia deixa o dimensionamento de ordens para a base Strategy.Volume. Os giros de posição automaticamente compensam qualquer exposição existente adicionando Math.Abs(Position) ao volume da ordem.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

public class BollingerBandSqueezeBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast, _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 BollingerBandSqueezeBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 10).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 30).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(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 fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); 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 && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}