在 GitHub 上查看
BollTrade Bollinger Reversion 策略
概述
BollTrade Bollinger Reversion Strategy 是将原始的 MetaTrader BollTrade 专家顾问迁移到 StockSharp 高级 API 的结果。策略使用布林带检测价格在极端位置的反转机会,并在价格远离带状区域后入场。完成的 K 线收于上轨之上时开空单,收于下轨之下时开多单,所有判断都基于已完成的 K 线以避免噪音。
交易逻辑
- 订阅指定的 K 线类型,并根据给定周期与标准差计算布林带。
- 计算额外的点数缓冲,以复制原策略要求价格突破更远距离后才交易的行为。
- 若收盘价低于下轨减去缓冲距离,则开多单;若收盘价高于上轨加上缓冲距离,则开空单。
- 每次开仓都会保存以点数表示的止盈与止损价格,当 K 线的最高价或最低价触发这些阈值时平仓。
- 策略一次只维护一个仓位,不会加仓或网格化操作。
资金管理
Lots 参数决定基础下单手数。
- 当启用
LotIncrease 时,手数会根据当前投资组合价值与初始价值的比例进行放大,并限制在 500 手以内,用以还原原策略随余额增长而增仓的特性。
参数
| 参数 |
说明 |
| Take Profit (pips) |
以点数表示的止盈距离,值为 0 时表示不设置止盈。 |
| Stop Loss (pips) |
以点数表示的止损距离,值为 0 时表示不设置止损。 |
| Band Offset |
在布林带之外额外要求的点数距离。 |
| Bollinger Period |
布林带均线的周期长度。 |
| Bollinger Deviation |
布林带宽度所使用的标准差倍数。 |
| Base Volume |
基础下单手数。 |
| Scale Volume |
启用后,随着账户权益的增长按比例放大手数。 |
| Candle Type |
用于生成信号的 K 线类型(时间框架)。 |
注意事项
- 策略只在完成的 K 线上工作,因此在实时运行前需要加载一定的历史数据以完成指标初始化。
- 止盈止损通过 K 线的最高价与最低价进行触发检测,这在使用高级 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()