Стратегия Enhanced Bollinger Bands SL TP
Стратегия торгует отскоки от полос Боллинджера, размещая лимитные заявки и фиксированные стоп-лосс и тейк-профит в пунктах.
Детали
- Условия входа:
- Long: предыдущее закрытие <= предыдущей нижней полосы и текущее закрытие > нижней полосы
- Short: предыдущее закрытие >= предыдущей верхней полосы и текущее закрытие < верхней полосы
- Направление: Оба
- Стопы: Абсолютные стоп-лосс и тейк-профит в пунктах
- Значения по умолчанию:
BollingerLength= 20BollingerMultiplier= 2mEnableLong= trueEnableShort= truePipValue= 0.0001mStopLossPips= 10mTakeProfitPips= 20mCandleType= TimeSpan.FromMinutes(1).TimeFrame()
- Фильтры:
- Категория: Разворот
- Направление: Оба
- Индикаторы: Bollinger Bands
- Стопы: Да
- Сложность: Базовая
- Таймфрейм: Краткосрочный
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Enhanced Bollinger Bands SL TP strategy.
/// A close back above the lower band after the previous close was at or below the previous lower band places a buy limit order at
/// the close; a close back below the upper band after the previous close was at or above the previous upper band places a sell
/// limit order. An unfilled entry order is cancelled on the next candle. Stop loss and take profit are StopLossPips and
/// TakeProfitPips times PipValue from the entry.
/// </summary>
public class EnhancedBollingerBandsStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerLength;
private readonly StrategyParam<decimal> _bollingerMultiplier;
private readonly StrategyParam<bool> _enableLong;
private readonly StrategyParam<bool> _enableShort;
private readonly StrategyParam<decimal> _pipValue;
private readonly StrategyParam<decimal> _stopLossPips;
private readonly StrategyParam<decimal> _takeProfitPips;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevClose;
private decimal? _prevUpper;
private decimal? _prevLower;
private Order _entryOrder;
/// <summary>
/// Bollinger Bands length.
/// </summary>
public int BollingerLength
{
get => _bollingerLength.Value;
set => _bollingerLength.Value = value;
}
/// <summary>
/// Bollinger Bands deviation multiplier.
/// </summary>
public decimal BollingerMultiplier
{
get => _bollingerMultiplier.Value;
set => _bollingerMultiplier.Value = value;
}
/// <summary>
/// Allow long trades.
/// </summary>
public bool EnableLong
{
get => _enableLong.Value;
set => _enableLong.Value = value;
}
/// <summary>
/// Allow short trades.
/// </summary>
public bool EnableShort
{
get => _enableShort.Value;
set => _enableShort.Value = value;
}
/// <summary>
/// Price of one pip.
/// </summary>
public decimal PipValue
{
get => _pipValue.Value;
set => _pipValue.Value = value;
}
/// <summary>
/// Stop loss in pips.
/// </summary>
public decimal StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Take profit in pips.
/// </summary>
public decimal TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public EnhancedBollingerBandsStrategy()
{
_bollingerLength = Param(nameof(BollingerLength), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Length", "Bollinger Bands length", "Indicators");
_bollingerMultiplier = Param(nameof(BollingerMultiplier), 2m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Multiplier", "Bollinger Bands deviation multiplier", "Indicators");
_enableLong = Param(nameof(EnableLong), true)
.SetDisplay("Enable Long", "Allow long trades", "General");
_enableShort = Param(nameof(EnableShort), true)
.SetDisplay("Enable Short", "Allow short trades", "General");
_pipValue = Param(nameof(PipValue), 0.0001m)
.SetGreaterThanZero()
.SetDisplay("Pip Value", "Price of one pip", "Risk");
_stopLossPips = Param(nameof(StopLossPips), 10m)
.SetNotNegative()
.SetDisplay("Stop Loss Pips", "Stop loss in pips", "Risk");
_takeProfitPips = Param(nameof(TakeProfitPips), 20m)
.SetNotNegative()
.SetDisplay("Take Profit Pips", "Take profit in pips", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetState();
}
private void ResetState()
{
_prevClose = null;
_prevUpper = null;
_prevLower = null;
_entryOrder = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var bollinger = new BollingerBands { Length = BollingerLength, Width = BollingerMultiplier };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, ProcessCandle)
.Start();
StartProtection(
TakeProfitPips > 0m ? new Unit(TakeProfitPips * PipValue, UnitTypes.Absolute) : new Unit(),
StopLossPips > 0m ? new Unit(StopLossPips * PipValue, UnitTypes.Absolute) : new Unit(),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_entryOrder != null && _entryOrder.State == OrderStates.Active)
CancelOrder(_entryOrder);
_entryOrder = null;
if (!bollingerValue.IsFormed || bollingerValue is not IBollingerBandsValue { UpBand: decimal upper, LowBand: decimal lower })
return;
var prevClose = _prevClose;
var prevUpper = _prevUpper;
var prevLower = _prevLower;
_prevClose = candle.ClosePrice;
_prevUpper = upper;
_prevLower = lower;
if (prevClose is not decimal pc || prevUpper is not decimal pu || prevLower is not decimal pl)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (EnableLong && pc <= pl && close > lower && Position <= 0)
_entryOrder = BuyLimit(close, Volume + Math.Abs(Position));
else if (EnableShort && pc >= pu && close < upper && Position >= 0)
_entryOrder = SellLimit(close, Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, OrderStates
from StockSharp.Algo.Indicators import BollingerBands
from StockSharp.Algo.Strategies import Strategy
class enhanced_bollinger_bands_sl_tp_strategy(Strategy):
"""
Enhanced Bollinger Bands SL TP strategy.
A close back above the lower band after the previous close was at or below the previous lower band places a buy limit order at
the close; a close back below the upper band after the previous close was at or above the previous upper band places a sell
limit order. An unfilled entry order is cancelled on the next candle. Stop loss and take profit are StopLossPips and
TakeProfitPips times PipValue from the entry.
"""
def __init__(self):
super(enhanced_bollinger_bands_sl_tp_strategy, self).__init__()
self._bollinger_length = self.Param("BollingerLength", 20).SetGreaterThanZero().SetDisplay("Bollinger Length", "Bollinger Bands length", "Indicators")
self._bollinger_multiplier = self.Param("BollingerMultiplier", 2.0).SetGreaterThanZero().SetDisplay("Bollinger Multiplier", "Bollinger Bands deviation multiplier", "Indicators")
self._enable_long = self.Param("EnableLong", True).SetDisplay("Enable Long", "Allow long trades", "General")
self._enable_short = self.Param("EnableShort", True).SetDisplay("Enable Short", "Allow short trades", "General")
self._pip_value = self.Param("PipValue", 0.0001).SetGreaterThanZero().SetDisplay("Pip Value", "Price of one pip", "Risk")
self._stop_loss_pips = self.Param("StopLossPips", 10.0).SetNotNegative().SetDisplay("Stop Loss Pips", "Stop loss in pips", "Risk")
self._take_profit_pips = self.Param("TakeProfitPips", 20.0).SetNotNegative().SetDisplay("Take Profit Pips", "Take profit in pips", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_close = None
self._prev_upper = None
self._prev_lower = None
self._entry_order = None
def OnReseted(self):
super(enhanced_bollinger_bands_sl_tp_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(enhanced_bollinger_bands_sl_tp_strategy, self).OnStarted2(time)
self._reset_state()
bollinger = BollingerBands()
bollinger.Length = self._bollinger_length.Value
bollinger.Width = Decimal(float(self._bollinger_multiplier.Value))
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, self._process_candle).Start()
pip = float(self._pip_value.Value)
take = float(self._take_profit_pips.Value)
stop = float(self._stop_loss_pips.Value)
self.StartProtection(
Unit(Decimal(take * pip), UnitTypes.Absolute) if take > 0 else Unit(),
Unit(Decimal(stop * pip), UnitTypes.Absolute) if stop > 0 else Unit(),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawOwnTrades(area)
def _process_candle(self, candle, bollinger_value):
if candle.State != CandleStates.Finished:
return
if self._entry_order is not None and self._entry_order.State == OrderStates.Active:
self.CancelOrder(self._entry_order)
self._entry_order = None
if not bollinger_value.IsFormed or bollinger_value.UpBand is None or bollinger_value.LowBand is None:
return
upper = float(bollinger_value.UpBand)
lower = float(bollinger_value.LowBand)
close = float(candle.ClosePrice)
prev_close = self._prev_close
prev_upper = self._prev_upper
prev_lower = self._prev_lower
self._prev_close = close
self._prev_upper = upper
self._prev_lower = lower
if prev_close is None or prev_upper is None or prev_lower is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._enable_long.Value and prev_close <= prev_lower and close > lower and self.Position <= 0:
self._entry_order = self.BuyLimit(candle.ClosePrice, self.Volume + abs(self.Position))
elif self._enable_short.Value and prev_close >= prev_upper and close < upper and self.Position >= 0:
self._entry_order = self.SellLimit(candle.ClosePrice, self.Volume + abs(self.Position))
def CreateClone(self):
return enhanced_bollinger_bands_sl_tp_strategy()