Ver en GitHub

Estrategia de Rompimiento BB

Descripción general

La Estrategia de Rompimiento BB replica el asesor experto de MetaTrader Breakthrough_BB dentro de la API de alto nivel de StockSharp. El sistema combina Bandas de Bollinger con una media móvil simple rápida para capturar rupturas explosivas que ocurren después de que el precio se comprime cerca de los límites de la banda. Las operaciones se generan exclusivamente en velas completadas para mantener señales deterministas y reflejar el comportamiento original de MQL5.

Lógica de trading

  • Filtro de tendencia: Una media móvil simple (SMA) con período configurable valida la dirección de la tendencia. La estrategia compara el último valor de la SMA con el valor de la SMA de cuatro barras antes. Las operaciones largas requieren que la SMA tenga pendiente ascendente, mientras que los cortos requieren una pendiente descendente.
  • Ruptura de Bandas de Bollinger: La estrategia observa cómo el cierre de hace cuatro barras interactuó con la banda superior o inferior de Bollinger y lo compara con el precio de cierre más reciente. Una ruptura válida ocurre cuando el precio se mueve desde el interior de la banda hacia el exterior entre esos dos momentos.
  • Modelo de posición única: El algoritmo mantiene como máximo una posición abierta. Cualquier operación abierta se cierra antes de evaluar nuevas entradas para evitar exposición solapada.

Condiciones de entrada

Configuración larga

  1. El precio de cierre de hace cuatro velas completas estaba por debajo de la Banda de Bollinger superior.
  2. El precio de cierre más reciente terminó por encima de la Banda de Bollinger superior actual.
  3. El valor de la SMA calculado en la última vela es mayor que el valor de la SMA de hace cuatro velas (pendiente positiva).
  4. No hay ninguna posición abierta actualmente.

Configuración corta

  1. El precio de cierre de hace cuatro velas completas estaba por encima de la Banda de Bollinger inferior.
  2. El precio de cierre más reciente terminó por debajo de la Banda de Bollinger inferior actual.
  3. El valor de la SMA calculado en la última vela es menor que el valor de la SMA de hace cuatro velas (pendiente negativa).
  4. No hay ninguna posición abierta actualmente.

Cuando se cumple una condición de entrada, la estrategia envía una orden de mercado usando el parámetro de volumen configurado.

Reglas de salida

  • Salida de posición larga: Si una operación larga está activa y el último cierre cae por debajo de la línea media de Bollinger, la posición se cierra inmediatamente con una orden de venta a mercado.
  • Salida de posición corta: Si una operación corta está abierta y el último cierre sube por encima de la línea media de Bollinger, la posición se cubre con una orden de compra a mercado.

Estas reglas de salida imitan el asesor experto original, que eliminaba operaciones cada vez que el mercado revertía de vuelta dentro de la línea media de la banda.

Indicadores

  • Media Móvil Simple (SMA): Define el sesgo direccional y proporciona la comparación de pendiente en un intervalo de cuatro velas.
  • Bandas de Bollinger: Suministra las envolventes superior, media e inferior usadas para detectar entradas por ruptura y gestionar salidas.

Parámetros

Nombre Descripción Predeterminado Optimizable
MaPeriod Longitud de la SMA usada para el filtro de tendencia. 9
BandsPeriod Longitud de retrospectiva para los cálculos de Bandas de Bollinger. 28
Deviation Multiplicador de desviación estándar aplicado a las Bandas de Bollinger. 1.6
Volume Tamaño de la orden (en lotes o contratos, según el instrumento). 1
CandleType Tipo de agregación de velas procesado por la estrategia. Marco temporal de 1 hora

Todos los parámetros exponen metadatos StrategyParam de StockSharp para que puedan ajustarse en la interfaz o optimizarse en el diseñador.

Requisitos de datos

  • Funciona con cualquier instrumento que proporcione datos de velas compatibles con el CandleType seleccionado.
  • Las señales se evalúan solo en velas terminadas. Las velas incompletas se ignoran para mantener la lógica determinista.
  • La configuración predeterminada usa velas horarias, pero se puede suministrar cualquier marco temporal compatible con la fuente de datos.

Notas adicionales

  • El algoritmo evita búsquedas en el historial del indicador y en su lugar mantiene una caché deslizante de cuatro barras para valores de cierre y SMA, cumpliendo con las pautas del proyecto.
  • Las funciones de protección como stop-loss o take-profit pueden agregarse mediante StartProtection si se desea; no forman parte de la implementación MQL original y por lo tanto se omiten aquí.
  • Dado que la estrategia emite órdenes de mercado, asegúrese de contar con suficiente liquidez en el instrumento elegido para minimizar el deslizamiento.
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;
	}
}