The Blockbuster Bollinger Breakout strategy is a direct port of the MetaTrader 4 expert advisor "BLOCKBUSTER EA". The original system searched for aggressive reversals after price pushed beyond a Bollinger Band by a configurable distance. This StockSharp version keeps the same logic while embracing the high-level API for candle subscriptions, indicator binding and position management.
Core Idea
Build Bollinger Bands with a user-defined period and deviation.
Measure when the close of the current candle breaks above the upper band or below the lower band by an extra offset (in points).
Enter short if the close exceeds the upper band plus the offset. Enter long if the close drops below the lower band minus the offset.
Manage the position with point-based profit and loss thresholds identical to the MQL settings.
The distance, stop and target are expressed in instrument points. They adapt to the instrument's price step, so a value of 3 means three PriceStep units regardless of the underlying symbol.
Detailed Logic
Indicator Calculation
Indicator: Bollinger Bands.
Inputs: candle close prices (the MT4 code used PRICE_OPEN; this port keeps close prices for better StockSharp compatibility while preserving band length and deviation parameters).
Parameters:
BollingerPeriod: number of candles used in the moving average and standard deviation.
BollingerDeviation: standard deviation multiplier for the upper and lower bands.
Additional offset DistancePoints (converted to price using the instrument PriceStep).
Entry Conditions
Long: Close < LowerBand - Distance and the current net position is flat or short.
Short: Close > UpperBand + Distance and the current net position is flat or long.
Any open opposite position is flattened by the market order size TradeVolume + |Position| to mirror the MT4 "One order only" behaviour.
Exit Conditions
Positions are monitored on every finished candle. The unrealised profit in points is computed using the instrument PriceStep.
Take Profit: if profit reaches or exceeds ProfitTargetPoints.
Stop Loss: if loss reaches or exceeds LossLimitPoints.
Exits are performed with market orders that close the entire position.
Risk & Money Management
TradeVolume sets the base order size. Matching the MetaTrader "Lots" input is as simple as setting the same numeric value.
Both stop and target can be disabled by setting the respective parameter to 0.
When both thresholds are enabled, the stop is evaluated after the target, exactly as the original EA checked the profit branch first.
State Tracking
The strategy records the entry price at the time of the signal and uses it for all subsequent profit/loss calculations.
If an exit order flattens the position, the state is reset automatically.
Parameters
Parameter
Default
Description
BollingerPeriod
20
Number of candles in the Bollinger Bands moving average.
BollingerDeviation
2.0
Standard deviation multiplier.
DistancePoints
3
Extra distance beyond the band before a trade is placed (instrument points).
ProfitTargetPoints
3
Take-profit threshold in instrument points. Set to 0 to disable.
LossLimitPoints
20
Stop-loss threshold in instrument points. Set to 0 to disable.
TradeVolume
1
Volume for new entries.
CandleType
1-minute time frame
Candle type used for calculations.
Usage Notes
Works on any instrument that supplies candles and a non-zero PriceStep. Forex pairs, index CFDs and liquid futures mirror the original EA environment best.
Because the indicator now relies on closing prices, testing on the intended time frame is recommended to ensure behaviour similar to the MT4 version.
The strategy uses CreateChartArea helpers to visualise candles, the Bollinger Bands and executed trades when a chart is available in the UI.
The logic assumes continuous evaluation on finished candles, ensuring deterministic behaviour in backtesting and live trading.
Tags
Category: Counter-trend breakout
Direction: Both
Indicators: Bollinger Bands
Stops: Yes (configurable)
Timeframe: Short-term (default 1 minute)
Complexity: Simple
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Blockbuster Bollinger breakout strategy.
/// Buys when price closes below lower Bollinger band (mean reversion).
/// Sells when price closes above upper Bollinger band.
/// Exits at middle band.
/// </summary>
public class BlockbusterBollingerStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerWidth;
private readonly StrategyParam<DataType> _candleType;
public int BollingerPeriod { get => _bollingerPeriod.Value; set => _bollingerPeriod.Value = value; }
public decimal BollingerWidth { get => _bollingerWidth.Value; set => _bollingerWidth.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public BlockbusterBollingerStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetDisplay("BB Period", "Bollinger bands period", "Indicators");
_bollingerWidth = Param(nameof(BollingerWidth), 1m)
.SetDisplay("BB Width", "Bollinger bands deviation", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands { Length = BollingerPeriod, Width = BollingerWidth };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
if (!value.IsFinal || value.IsEmpty)
return;
var bbVal = value as BollingerBandsValue;
if (bbVal == null)
return;
var upper = bbVal.UpBand;
var lower = bbVal.LowBand;
var middle = bbVal.MovingAverage;
if (upper == null || lower == null || middle == null)
return;
var close = candle.ClosePrice;
// Breakout above upper band - momentum buy
if (close > upper.Value && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Breakout below lower band - momentum sell
else if (close < lower.Value && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Exit long at middle
else if (Position > 0 && close < middle.Value)
{
SellMarket();
}
// Exit short at middle
else if (Position < 0 && close > middle.Value)
{
BuyMarket();
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands
from StockSharp.Algo.Strategies import Strategy
class blockbuster_bollinger_strategy(Strategy):
def __init__(self):
super(blockbuster_bollinger_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("BB Period", "Bollinger bands period", "Indicators")
self._bollinger_width = self.Param("BollingerWidth", 1.0) \
.SetDisplay("BB Width", "Bollinger bands deviation", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def bollinger_period(self):
return self._bollinger_period.Value
@property
def bollinger_width(self):
return self._bollinger_width.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(blockbuster_bollinger_strategy, self).OnReseted()
def OnStarted2(self, time):
super(blockbuster_bollinger_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.bollinger_period
bb.Width = self.bollinger_width
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, self.process_candle).Start()
def process_candle(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
if not bb_value.IsFinal or bb_value.IsEmpty:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
middle = float(bb_value.MovingAverage)
close = float(candle.ClosePrice)
if close > upper and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < lower and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
elif self.Position > 0 and close < middle:
self.SellMarket()
elif self.Position < 0 and close > middle:
self.BuyMarket()
def CreateClone(self):
return blockbuster_bollinger_strategy()