布林带反转策略
当价格突破布林带外侧时,往往会迅速回到中轨。本策略利用这一特性,在收盘价跌破下轨且蜡烛为阳时买入,在收盘价突破上轨且蜡烛为阴时做空。
测试表明年均收益约为 94%,该策略在股票市场表现最佳。
算法在每根K线计算布林带,并检测收盘价是否越过外带。若看涨蜡烛收于下轨之外,则开多仓;若看跌蜡烛收于上轨之外,则开空仓。止损依赖于ATR倍数,平仓则在价格回到中轨时执行。
均值回归交易通常只持续几根K线,因此该策略适合短期波动收缩阶段。
细节
- 入场条件:阳线收盘低于下轨或阴线收盘高于上轨。
- 多/空:双向。
- 退出条件:价格回到中轨或止损。
- 止损:是,基于 ATR。
- 默认值:
BollingerPeriod= 20BollingerDeviation= 2.0AtrMultiplier= 2.0CandleType= 5 分钟
- 过滤条件:
- 类别: 均值回归
- 方向: 双向
- 指标: 布林带, ATR
- 止损: 有
- 复杂度: 基础
- 时间框架: 日内
- 季节性: 无
- 神经网络: 无
- 背离: 无
- 风险级别: 中等
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 Band Reversal strategy.
/// Enters long when price is below the lower Bollinger Band and candle is bullish.
/// Enters short when price is above the upper Bollinger Band and candle is bearish.
/// Exits at middle band.
/// </summary>
public class BollingerBandReversalStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private int _cooldown;
/// <summary>
/// Bollinger Bands period.
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// Bollinger Bands deviation multiplier.
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public BollingerBandReversalStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Period", "Period for Bollinger Bands", "Indicators");
_bollingerDeviation = Param(nameof(BollingerDeviation), 2.0m)
.SetNotNegative()
.SetDisplay("Bollinger Deviation", "Standard deviations for Bollinger Bands", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cooldown = 0;
var bollingerBands = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollingerBands, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollingerBands);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!bollingerValue.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
var bb = (BollingerBandsValue)bollingerValue;
var upperBand = bb.UpBand;
var lowerBand = bb.LowBand;
var middleBand = bb.MovingAverage;
var isBullish = candle.ClosePrice > candle.OpenPrice;
var isBearish = candle.ClosePrice < candle.OpenPrice;
if (Position == 0 && candle.ClosePrice < lowerBand && isBullish)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && candle.ClosePrice > upperBand && isBearish)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && candle.ClosePrice > middleBand)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice < middleBand)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
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 bollinger_band_reversal_strategy(Strategy):
"""
Bollinger Band Reversal strategy.
Enters long when price is below the lower Bollinger Band and candle is bullish.
Enters short when price is above the upper Bollinger Band and candle is bearish.
Exits at middle band.
"""
def __init__(self):
super(bollinger_band_reversal_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20).SetDisplay("Bollinger Period", "Period for Bollinger Bands", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0).SetDisplay("Bollinger Deviation", "Standard deviations for Bollinger Bands", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_band_reversal_strategy, self).OnReseted()
self._cooldown = 0
def OnStarted2(self, time):
super(bollinger_band_reversal_strategy, self).OnStarted2(time)
self._cooldown = 0
bb = BollingerBands()
bb.Length = self._bollinger_period.Value
bb.Width = self._bollinger_deviation.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bb)
self.DrawOwnTrades(area)
def _process_candle(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
if not bb_value.IsFormed:
return
if self._cooldown > 0:
self._cooldown -= 1
return
upper_band = bb_value.UpBand
lower_band = bb_value.LowBand
middle_band = bb_value.MovingAverage
if upper_band is None or lower_band is None or middle_band is None:
return
close = float(candle.ClosePrice)
ub = float(upper_band)
lb = float(lower_band)
mb = float(middle_band)
cd = self._cooldown_bars.Value
is_bullish = candle.ClosePrice > candle.OpenPrice
is_bearish = candle.ClosePrice < candle.OpenPrice
if self.Position == 0 and close < lb and is_bullish:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and close > ub and is_bearish:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and close > mb:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and close < mb:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return bollinger_band_reversal_strategy()