GitHub で見る
Bollinger バンド保留ストップ戦略
概要
このサンプルは、元の MQL「Bb_0_1」エキスパート アドバイザを StockSharp の高レベル API に変換します。この戦略は 1 つのローソク足サブスクリプションをリッスンし、Bollinger バンドを使用して現在の価格をブラケットします。市場が上限バンドと下限バンドの間にある場合、アルゴリズムは価格より上に 3 層の買いストップ注文を配置し、価格より下に 3 層の売りストップ注文を配置します。各レイヤーは、反対側のバンドから取得した同じストップリファレンスを共有しながら、個別のテイクプロフィットディスタンスで構成されます。
取引ロジック
- 構成されたタイムフレームをサブスクライブし、要求された期間と偏差を使用して Bollinger バンドを計算します。
- 取引ウィンドウ内 (
StartHour < 時間 < EndHour) で、価格がバンドの間にある間に未決注文を出します。
- 現在のアッパーバンドレベルで 3 つの買いストップがあり、テイクプロフィットはエントリーより
FirstTakeProfit、SecondTakeProfit、および ThirdTakeProfit の価格ステップだけ置き換えられます。
- 現在の下位バンドレベルで 3 つの売りストップがあり、エントリーの下にミラーリングされたテイクプロフィットがあります。
- すべてのエントリは、最初の保護停止として反対のバンドを継承します。
- 未決注文は、注文がインジケーターのエンベロープに従うように、バンドが価格に近づくたびに自動的に再登録されます。
- ストップ注文が実行されると、ストラテジーは約定したボリュームに対して明示的なストップロス注文とテイクプロフィット注文を登録します。
- トレーリング保護はオプションです。
UseBandTrailingStop はトレーリング用に反対側のバンドを選択します。それ以外の場合は、中間バンド (EMA) が使用されます。ストップは、終値がエントリー価格を超え、インジケーターの値がより良いレベルを提供する場合にのみ追跡します。
パラメーター
| 名前 |
説明 |
CandleType |
Bollinger バンドの計算に使用される時間枠。 |
BandPeriod |
バンドが使用するキャンドルの数。 |
BandDeviation |
バンドの標準偏差乗数。 |
Volume |
各保留中のレイヤーのボリューム。 |
StartHour / EndHour |
時間ごとの取引ウィンドウ (排他的範囲)。 |
FirstTakeProfit, SecondTakeProfit, ThirdTakeProfit |
各レイヤーの価格ステップで表されるテイクプロフィット距離。 |
UseBandTrailingStop |
末尾の参照を選択します: 反対側のバンド (true) または Bollinger の中央のライン (false)。 |
実装メモ
- 注文量は、静的なサイズ (
Volume) を使用して元のエキスパート アドバイザーを反映します。 StockSharp サンプル環境では口座履歴が提供されないため、MQL コードによるリスクベースのポジションサイジングは実装されていません。
- 高レベルの API がすでに現在のローソクに合わせた値を提供しているため、MQL スクリプトからのインジケーター シフト パラメーターは公開されません。
- プロテクション注文は、バンドベースのトレーリング条件がストップレベルを改善するたびに更新される通常のストップ注文および指値注文です。
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 Band breakout strategy.
/// Buys when price closes above upper band, sells when price closes below lower band.
/// Exits at middle band.
/// </summary>
public class BollingerBandPendingStopsStrategy : Strategy
{
private readonly StrategyParam<int> _bandPeriod;
private readonly StrategyParam<decimal> _bandWidth;
private readonly StrategyParam<DataType> _candleType;
public int BandPeriod { get => _bandPeriod.Value; set => _bandPeriod.Value = value; }
public decimal BandWidth { get => _bandWidth.Value; set => _bandWidth.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public BollingerBandPendingStopsStrategy()
{
_bandPeriod = Param(nameof(BandPeriod), 20)
.SetDisplay("Band Period", "Bollinger bands period", "Indicators");
_bandWidth = Param(nameof(BandWidth), 1m)
.SetDisplay("Band Width", "Bollinger bands deviation", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands { Length = BandPeriod, Width = BandWidth };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
if (!value.IsFinal || value.IsEmpty)
return;
var bbVal = value.IsEmpty ? null : value as BollingerBandsValue;
if (bbVal == null)
return;
var upper = bbVal.UpBand;
var lower = bbVal.LowBand;
var middle = bbVal.MovingAverage;
if (upper == null || lower == null || middle == null)
return;
var close = candle.ClosePrice;
// Breakout above upper band - buy
if (close > upper.Value && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Breakout below lower band - sell
else if (close < lower.Value && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Exit at middle band
else if (Position > 0 && close < middle.Value)
{
SellMarket();
}
else if (Position < 0 && close > middle.Value)
{
BuyMarket();
}
}
}
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_pending_stops_strategy(Strategy):
def __init__(self):
super(bollinger_band_pending_stops_strategy, self).__init__()
self._band_period = self.Param("BandPeriod", 20) \
.SetDisplay("Band Period", "Bollinger bands period", "Indicators")
self._band_width = self.Param("BandWidth", 1.0) \
.SetDisplay("Band Width", "Bollinger bands deviation", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def band_period(self):
return self._band_period.Value
@property
def band_width(self):
return self._band_width.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_band_pending_stops_strategy, self).OnReseted()
def OnStarted2(self, time):
super(bollinger_band_pending_stops_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.band_period
bb.Width = self.band_width
subscription = self.SubscribeCandles(self.candle_type)
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 or bb_value.IsEmpty:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
middle = float(bb_value.MovingAverage)
close = float(candle.ClosePrice)
if close > upper and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < lower and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
elif self.Position > 0 and close < middle:
self.SellMarket()
elif self.Position < 0 and close > middle:
self.BuyMarket()
def CreateClone(self):
return bollinger_band_pending_stops_strategy()