BollTrade Bollinger Reversion Strategy — это конвертация оригинального эксперта BollTrade из MetaTrader в высокоуровневую стратегию StockSharp. Стратегия торгует одним инструментом по сигналам индикатора полос Боллинджера и ожидает, когда цена выйдет за границы полосы на величину дополнительного буфера в пунктах. Если свеча закрывается выше верхней полосы, стратегия открывает короткую позицию, а если закрывается ниже нижней полосы — длинную позицию. Расчёты выполняются только по завершённым свечам, чтобы избежать реакции на незавершённые данные.
Логика торговли
Подписаться на выбранный тип свечей и рассчитать Bollinger Bands с заданным периодом и отклонением.
Вычислить дополнительное смещение в пунктах, чтобы повторить буфер, использовавшийся в оригинальном советнике.
При закрытии свечи ниже нижней полосы минус смещение открыть длинную позицию. При закрытии выше верхней полосы плюс смещение открыть короткую позицию.
Для каждой позиции сохранить уровни стоп-лосса и тейк-профита, заданные в пунктах. Это имитирует закрытие сделок при достижении заданной прибыли или убытка в версии MetaTrader.
Закрывать позицию, если диапазон свечи пересекает уровни стоп-лосса или тейк-профита. Дополнительного наращивания позиции не выполняется.
Управление капиталом
Параметр Lots задаёт базовый объём сделки.
При включенном LotIncrease объём увеличивается пропорционально росту стоимости портфеля относительно значения на момент запуска стратегии, но не более 500 лотов. Это повторяет логику масштабирования из MetaTrader.
Параметры
Параметр
Описание
Take Profit (pips)
Расстояние в пунктах для расчёта тейк-профита от цены входа. Ноль отключает тейк-профит.
Stop Loss (pips)
Расстояние в пунктах для расчёта стоп-лосса от цены входа. Ноль отключает стоп-лосс.
Band Offset
Дополнительное расстояние в пунктах сверх полос Боллинджера перед открытием сделки.
Bollinger Period
Количество свечей в расчёте среднего Bollinger Bands.
Bollinger Deviation
Множитель стандартного отклонения для ширины полос.
Base Volume
Базовый торговый объём в лотах.
Scale Volume
При включении увеличивает объём заявок при росте стоимости портфеля.
Candle Type
Тип свечей (таймфрейм), по которым формируются сигналы.
Примечания
Стратегия работает только по завершённым свечам, поэтому ей необходима историческая подкачка данных для прогрева.
Проверка стоп-лоссов и тейк-профитов выполняется по диапазону свечей, что приблизительно повторяет тиковую логику оригинала при использовании высокоуровневого API.
Защитный механизм StartProtection активирован для предотвращения нежелательных позиций при остановке стратегии.
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>
/// Bollinger Bands reversion strategy.
/// Buys when price closes below lower band, sells when above upper band.
/// Uses middle band as exit target.
/// </summary>
public class BollTradeBollingerReversionStrategy : 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 BollTradeBollingerReversionStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
_bollingerWidth = Param(nameof(BollingerWidth), 0.5m)
.SetDisplay("BB Width", "Bollinger Bands width", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
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 bbValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!bbValue.IsFinal)
return;
var bb = (BollingerBandsValue)bbValue;
var upper = bb.UpBand;
var lower = bb.LowBand;
var middle = bb.MovingAverage;
if (upper == null || lower == null || middle == null)
return;
var close = candle.ClosePrice;
var upperVal = upper.Value;
var lowerVal = lower.Value;
var midVal = middle.Value;
// Buy when close below lower band (oversold)
if (close < lowerVal && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Sell when close above upper band (overbought)
else if (close > upperVal && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands
from StockSharp.Algo.Strategies import Strategy
class boll_trade_bollinger_reversion_strategy(Strategy):
"""Bollinger Bands reversion strategy.
Buys when price closes below lower band, sells when above upper band."""
def __init__(self):
super(boll_trade_bollinger_reversion_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators")
self._bollinger_width = self.Param("BollingerWidth", 0.5) \
.SetDisplay("BB Width", "Bollinger Bands width", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def BollingerPeriod(self):
return self._bollinger_period.Value
@property
def BollingerWidth(self):
return self._bollinger_width.Value
def OnReseted(self):
super(boll_trade_bollinger_reversion_strategy, self).OnReseted()
def OnStarted2(self, time):
super(boll_trade_bollinger_reversion_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.BollingerPeriod
bb.Width = self.BollingerWidth
subscription = self.SubscribeCandles(self.CandleType)
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:
return
up_band = bb_value.UpBand if hasattr(bb_value, 'UpBand') else None
low_band = bb_value.LowBand if hasattr(bb_value, 'LowBand') else None
if up_band is None or low_band is None:
return
upper = float(up_band)
lower = float(low_band)
close = float(candle.ClosePrice)
# Buy when close below lower band (oversold)
if close < lower and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Sell when close above upper band (overbought)
elif close > upper and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return boll_trade_bollinger_reversion_strategy()