GitHub で見る
ラバーバンド 3 戦略
この戦略は、MetaTrader 4 Expert Advisor RUBBERBANDS_3 の StockSharp 移植です。 2 つの現在の価格の極端な値を維持し、設定可能な距離だけ価格が拡大するたびに追加のポジションをオープンし、指定されたサイズの反対動きが発生するとシーケンス全体を清算します。リトレースメントの後、セッションレベルの損益目標を監視しながら、戦略はオプションで反対方向に切り替わります。
注: StockSharp はネットされたポジションで動作します。元の MT4 スクリプトはロング注文とショート注文を同時に保持できますが、ポートは方向を切り替える前にアクティブなシーケンスを閉じます。トレンドに合わせてスケールし、反落時に巻き戻すという一般的な動作は維持されます。
取引ロジック
- 現在の終値を現在の最高値と最低値の両方として記録します (または、再開時に保存した値を再利用します)。
- 価格が現在の最高値より
PipStep ポイント上昇した場合は、サイズ OrderVolume の成行買い注文を送信し、最高値を新しい価格に更新します。
- 価格が現在の最低値より
PipStep ポイント下がったら、サイズ OrderVolume の成行売り注文を送信し、最低値を更新します。
- 市場がアクティブな方向に対して
BackStep ポイント引き下がった場合は、その方向のすべてのポジションを閉じて反転を設定します。前のシーケンスが完全に清算されると、反対側がオープンされます。
- 累積セッション結果を監視します。実現プラスオープン利益が
SessionTakeProfit × OrderVolume に達した場合、セッションを終了します。反転中のドローダウンが SessionStopLoss × OrderVolume を超えたら、同様にすべてを閉じます。
QuiesceNow トグルは、戦略がフラットな場合に新しい取引を防止します。 StopNow フラグはすべてのロジックを一時停止し、CloseNow はポートフォリオの即時フラット化を要求します。
注文は、構成された CandleType の完成したキャンドルから生成されます。デフォルトの時間枠は 1 分で、各分の初めにチェックをトリガーした元の EA のタイミングと一致します。
パラメーター
| パラメータ |
説明 |
デフォルト |
OrderVolume |
各成行注文の基本サイズ。 |
0.02 |
MaxOrders |
単一方向の同時ポジションの最大数。制限に達すると、追加のエントリはブロックされます。 |
10 |
PipStep |
新しい取引を追加するポイント単位の拡張距離。 |
100 |
BackStep |
カウンターでポイントを移動して退場を強制し、逆転の準備をします。 |
20 |
QuiesceNow |
true の場合、オープンなポジションがない間、ストラテジーはアイドル状態になります。 |
false |
DoNow |
戦略開始直後に最初の長いシーケンスを開きます。 |
false |
StopNow |
それ以上の処理を禁止するハードストップ フラグ。既存のポジションはそのまま残ります。 |
false |
CloseNow |
即時フラット ポジションを要求し、順次クローズをトリガーします。 |
false |
UseSessionTakeProfit |
累積セッションのテイクプロフィットを有効にします。 |
true |
SessionTakeProfit |
セッションを終了するために使用されるロットごとのアカウント通貨の目標利益。 |
2000 |
UseSessionStopLoss |
累積セッションストップロスを有効にします。 |
true |
SessionStopLoss |
セッションが終了する前に反転する際のロットあたりの最大許容損失。 |
4000 |
UseInitialValues |
再起動するときは、最新の終値の代わりに手動で指定した InitialMax と InitialMin を再利用します。 |
false |
InitialMax |
UseInitialValues が有効な場合、保存された上限が再利用されます。 |
0 |
InitialMin |
UseInitialValues が有効な場合、保存された下限が再利用されます。 |
0 |
CandleType |
戦略的に加工されたキャンドルシリーズ。デフォルトは 1 分間のローソク足です。 |
TimeFrame(1m) |
セッション管理
- 利益の集計: 実現利益は完全決済のたびに累積され、未実現利益はすべてのオープンポジションの加重平均エントリー価格から再計算されます。
- セッションのテイクプロフィット:
SessionTakeProfit に達すると、ストラテジーはすべての取引を終了し、保存されている極値をリセットします。
- セッションのストップロス: 反転シーケンス中 (
BackStep がトリガーされた) 戦略は変動損失を追跡します。ドローダウンが SessionStopLoss を超えると、すべてのポジションが清算され、統計がクリアされた状態でセッションが再開されます。
使用上の注意
- ポイントを価格に変換するために使用される価格ステップは、
Security.PriceStep から取得されます。それに応じて機器のメタデータを構成します。それ以外の場合は、0.0001 のフォールバックが適用されます。
- 注文はネッティングされるため、この戦略は反対方向にオープンする前にクローズ取引を実行します。レガシーデータを移行するときは、注文履歴がヘッジされたプラットフォームとは異なる可能性があることに注意してください。
DoNow フラグは、最初のロング ポジションのみをオープンします。追加のエントリは通常のブレイクアウト条件に従います。
- ストラテジーをロードしたままにしておくが、ブックを平坦化した後は非アクティブにしておく場合は、
QuiesceNow を使用します。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Rubberbands 3: Grid expansion strategy using SMA+ATR bands.
/// Enters at band extremes, adds on continuation, exits at mean.
/// </summary>
public class Rubberbands3Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _smaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _entryPrice;
private int _gridCount;
public Rubberbands3Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_smaLength = Param(nameof(SmaLength), 20)
.SetDisplay("SMA Length", "SMA period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int SmaLength
{
get => _smaLength.Value;
set => _smaLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_gridCount = 0;
var sma = new SimpleMovingAverage { Length = SmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (atrVal <= 0)
return;
var close = candle.ClosePrice;
var upper = smaVal + atrVal * 1.5m;
var lower = smaVal - atrVal * 1.5m;
if (Position > 0)
{
if (close >= smaVal)
{
SellMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (close <= _entryPrice - atrVal * 5m)
{
SellMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (_gridCount < 4 && close <= _entryPrice - atrVal * 0.8m)
{
_entryPrice = (_entryPrice + close) / 2m;
_gridCount++;
BuyMarket();
}
}
else if (Position < 0)
{
if (close <= smaVal)
{
BuyMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (close >= _entryPrice + atrVal * 5m)
{
BuyMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (_gridCount < 4 && close >= _entryPrice + atrVal * 0.8m)
{
_entryPrice = (_entryPrice + close) / 2m;
_gridCount++;
SellMarket();
}
}
if (Position == 0)
{
if (close <= lower)
{
_entryPrice = close;
_gridCount = 0;
BuyMarket();
}
else if (close >= upper)
{
_entryPrice = close;
_gridCount = 0;
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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class rubberbands_3_strategy(Strategy):
def __init__(self):
super(rubberbands_3_strategy, self).__init__()
self._sma_length = self.Param("SmaLength", 20).SetDisplay("SMA Length", "SMA period", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(rubberbands_3_strategy, self).OnReseted()
self._entry_price = 0
self._grid_count = 0
def OnStarted2(self, time):
super(rubberbands_3_strategy, self).OnStarted2(time)
self._entry_price = 0
self._grid_count = 0
sma = SimpleMovingAverage()
sma.Length = self._sma_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(sma, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def OnProcess(self, candle, sma_val, atr_val):
if candle.State != CandleStates.Finished:
return
if atr_val <= 0:
return
close = float(candle.ClosePrice)
upper = sma_val + atr_val * 1.5
lower = sma_val - atr_val * 1.5
if self.Position > 0:
if close >= sma_val:
self.SellMarket()
self._entry_price = 0
self._grid_count = 0
elif close <= self._entry_price - atr_val * 5.0:
self.SellMarket()
self._entry_price = 0
self._grid_count = 0
elif self._grid_count < 4 and close <= self._entry_price - atr_val * 0.8:
self._entry_price = (self._entry_price + close) / 2.0
self._grid_count += 1
self.BuyMarket()
elif self.Position < 0:
if close <= sma_val:
self.BuyMarket()
self._entry_price = 0
self._grid_count = 0
elif close >= self._entry_price + atr_val * 5.0:
self.BuyMarket()
self._entry_price = 0
self._grid_count = 0
elif self._grid_count < 4 and close >= self._entry_price + atr_val * 0.8:
self._entry_price = (self._entry_price + close) / 2.0
self._grid_count += 1
self.SellMarket()
if self.Position == 0:
if close <= lower:
self._entry_price = close
self._grid_count = 0
self.BuyMarket()
elif close >= upper:
self._entry_price = close
self._grid_count = 0
self.SellMarket()
def CreateClone(self):
return rubberbands_3_strategy()