Стратегия Bollinger Bands Long
Стратегия покупает, когда цена закрывается ниже нижней границы полос Боллинджера и RSI находится в зоне перепроданности. Позиция закрывается при возвращении цены к средней полосе.
Детали
- Условия входа:
- Цена закрывается ниже нижней полосы Боллинджера.
- RSI ниже уровня перепроданности.
- Направление: Только лонг.
- Условия выхода:
- Цена закрывается на уровне или выше средней полосы.
- Стопы: Нет.
- Значения по умолчанию:
BbLength= 10BbDeviation= 2RsiLength= 14RsiOversold= 30
- Фильтры:
- Категория: Возврат к среднему
- Направление: Лонг
- Индикаторы: Bollinger Bands, RSI
- Стопы: Нет
- Сложность: Низкая
- Таймфрейм: Любой
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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>
/// Bollinger Bands Long strategy.
/// Long only: buys when the close is below the lower Bollinger band and RSI is below RsiOversold, and closes the long once the close
/// is at or above the middle band.
/// </summary>
public class BollingerBandsLongStrategy : Strategy
{
private readonly StrategyParam<int> _bbLength;
private readonly StrategyParam<decimal> _bbDeviation;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiOversold;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// Bollinger period.
/// </summary>
public int BbLength
{
get => _bbLength.Value;
set => _bbLength.Value = value;
}
/// <summary>
/// Bollinger standard deviation multiplier.
/// </summary>
public decimal BbDeviation
{
get => _bbDeviation.Value;
set => _bbDeviation.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public BollingerBandsLongStrategy()
{
_bbLength = Param(nameof(BbLength), 10)
.SetGreaterThanZero()
.SetDisplay("BB Length", "Bollinger period", "Bollinger");
_bbDeviation = Param(nameof(BbDeviation), 2m)
.SetGreaterThanZero()
.SetDisplay("BB Deviation", "Bollinger standard deviation multiplier", "Bollinger");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "RSI");
_rsiOversold = Param(nameof(RsiOversold), 30m)
.SetDisplay("RSI Oversold", "RSI oversold level", "RSI");
_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 OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bollinger = new BollingerBands { Length = BbLength, Width = BbDeviation };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
{
DrawIndicator(oscillators, rsi);
}
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!bollingerValue.IsFormed || !rsiValue.IsFormed)
return;
var bands = (BollingerBandsValue)bollingerValue;
if (bands.LowBand is not decimal lower || bands.MovingAverage is not decimal middle)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var rsi = rsiValue.GetValue<decimal>();
if (Position == 0 && close < lower && rsi < RsiOversold)
BuyMarket(Volume);
else if (Position > 0 && close >= middle)
SellMarket(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
from StockSharp.Algo.Indicators import BollingerBands, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class bollinger_bands_long_strategy(Strategy):
"""
Bollinger Bands Long strategy.
Long only: buys when the close is below the lower Bollinger band and RSI is below RsiOversold, and closes the long once the close
is at or above the middle band.
"""
def __init__(self):
super(bollinger_bands_long_strategy, self).__init__()
self._bb_length = self.Param("BbLength", 10).SetGreaterThanZero().SetDisplay("BB Length", "Bollinger period", "Bollinger")
self._bb_deviation = self.Param("BbDeviation", 2.0).SetGreaterThanZero().SetDisplay("BB Deviation", "Bollinger standard deviation multiplier", "Bollinger")
self._rsi_length = self.Param("RsiLength", 14).SetGreaterThanZero().SetDisplay("RSI Length", "RSI period", "RSI")
self._rsi_oversold = self.Param("RsiOversold", 30.0).SetDisplay("RSI Oversold", "RSI oversold level", "RSI")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(bollinger_bands_long_strategy, self).OnStarted2(time)
bollinger = BollingerBands()
bollinger.Length = self._bb_length.Value
bollinger.Width = Decimal(self._bb_deviation.Value)
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, rsi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
def _process_candle(self, candle, bollinger_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not bollinger_value.IsFormed or not rsi_value.IsFormed:
return
lower = bollinger_value.LowBand
middle = bollinger_value.MovingAverage
if lower is None or middle is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
close = candle.ClosePrice
rsi = rsi_value.GetValue[Decimal](None)
if self.Position == 0 and close < lower and rsi < Decimal(self._rsi_oversold.Value):
self.BuyMarket(self.Volume)
elif self.Position > 0 and close >= middle:
self.SellMarket(self.Position)
def CreateClone(self):
return bollinger_bands_long_strategy()