布林带距离策略
利用布林带的反转并增加额外距离过滤。价格收于上轨加距离时做空,收于下轨减距离时做多。仓位通过以价格步长表示的止盈或止损退出。
细节
- 入场条件:
- 多头:收盘价低于下轨减去距离
- 空头:收盘价高于上轨加上距离
- 多空方向:双向
- 出场条件:
- 达到止盈
- 触及止损
- 止损:以价格步长的绝对值
- 默认参数:
BollingerPeriod= 4BollingerDeviation= 2mBandDistance= 3mProfitTarget= 3mLossLimit= 20mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- 筛选:
- 分类:反转
- 方向:双向
- 指标:布林带
- 止损:是
- 复杂度:基础
- 时间框架:短期
- 季节性:否
- 神经网络:否
- 背离:否
- 风险等级:中
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy trading reversals from Bollinger Bands with extra distance.
/// </summary>
public class BollingerBandsDistanceStrategy : Strategy
{
private readonly StrategyParam<int> _bbPeriod;
private readonly StrategyParam<decimal> _bbDeviation;
private readonly StrategyParam<decimal> _bandDistance;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _closes = new();
public int BollingerPeriod
{
get => _bbPeriod.Value;
set => _bbPeriod.Value = value;
}
public decimal BollingerDeviation
{
get => _bbDeviation.Value;
set => _bbDeviation.Value = value;
}
public decimal BandDistance
{
get => _bandDistance.Value;
set => _bandDistance.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public BollingerBandsDistanceStrategy()
{
_bbPeriod = Param(nameof(BollingerPeriod), 20)
.SetDisplay("BB Period", "Bollinger Bands length", "Parameters");
_bbDeviation = Param(nameof(BollingerDeviation), 2m)
.SetDisplay("Deviation", "Bollinger Bands deviation", "Parameters");
_bandDistance = Param(nameof(BandDistance), 1m)
.SetDisplay("Band Distance", "Extra distance from bands in price steps", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_closes.Clear();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType)
.Bind(ProcessCandle)
.Start();
StartProtection(
new Unit(2000m, UnitTypes.Absolute),
new Unit(1000m, UnitTypes.Absolute));
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_closes.Add(candle.ClosePrice);
if (_closes.Count > BollingerPeriod)
_closes.RemoveAt(0);
if (_closes.Count < BollingerPeriod)
return;
var sum = 0m;
foreach (var close in _closes)
sum += close;
var middle = sum / _closes.Count;
var variance = 0m;
foreach (var close in _closes)
{
var delta = close - middle;
variance += delta * delta;
}
var stdDev = (decimal)Math.Sqrt((double)(variance / _closes.Count));
var upper = middle + BollingerDeviation * stdDev;
var lower = middle - BollingerDeviation * stdDev;
var closePrice = candle.ClosePrice;
var distance = BandDistance * (Security?.PriceStep ?? 1m);
if (Position > 0 && closePrice >= middle)
SellMarket();
else if (Position < 0 && closePrice <= middle)
BuyMarket();
if (Position == 0)
{
if (closePrice > upper + distance)
SellMarket();
else if (closePrice < lower - distance)
BuyMarket();
}
}
}
import clr
import math
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class bollinger_bands_distance_strategy(Strategy):
def __init__(self):
super(bollinger_bands_distance_strategy, self).__init__()
self._bb_period = self.Param("BollingerPeriod", 20)
self._bb_deviation = self.Param("BollingerDeviation", 2.0)
self._band_distance = self.Param("BandDistance", 1.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._closes = []
@property
def BollingerPeriod(self):
return self._bb_period.Value
@BollingerPeriod.setter
def BollingerPeriod(self, value):
self._bb_period.Value = value
@property
def BollingerDeviation(self):
return self._bb_deviation.Value
@BollingerDeviation.setter
def BollingerDeviation(self, value):
self._bb_deviation.Value = value
@property
def BandDistance(self):
return self._band_distance.Value
@BandDistance.setter
def BandDistance(self, value):
self._band_distance.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(bollinger_bands_distance_strategy, self).OnStarted2(time)
self._closes = []
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
self.StartProtection(
Unit(2000.0, UnitTypes.Absolute),
Unit(1000.0, UnitTypes.Absolute))
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
close_price = float(candle.ClosePrice)
period = int(self.BollingerPeriod)
self._closes.append(close_price)
if len(self._closes) > period:
self._closes.pop(0)
if len(self._closes) < period:
return
total = 0.0
for c in self._closes:
total += c
middle = total / len(self._closes)
variance = 0.0
for c in self._closes:
delta = c - middle
variance += delta * delta
std_dev = math.sqrt(variance / len(self._closes))
dev = float(self.BollingerDeviation)
upper = middle + dev * std_dev
lower = middle - dev * std_dev
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
distance = float(self.BandDistance) * step
if self.Position > 0 and close_price >= middle:
self.SellMarket()
elif self.Position < 0 and close_price <= middle:
self.BuyMarket()
if self.Position == 0:
if close_price > upper + distance:
self.SellMarket()
elif close_price < lower - distance:
self.BuyMarket()
def OnReseted(self):
super(bollinger_bands_distance_strategy, self).OnReseted()
self._closes = []
def CreateClone(self):
return bollinger_bands_distance_strategy()