GitHub で見る
ブレッドアンドバター2 戦略
概要
Breadandbutter2 戦略は、MQL/7710/Breadandbutter2.mq4 の MT4 エキスパート アドバイザーを直接変換したものです。このシステムは 1 時間足のローソク足を監視し、ローソク足の始値に基づいて構築された 3 つの線形加重移動平均 (LWMA) を追跡します。 3 つの平均の同期クロスオーバーは、傾向の反転を示します。この戦略は、新しい方向に合わせてポジションを即座に反転し、トレンドが持続する間にオプションで追加注文をピラミッド型にします。
中核ロジック
- 1 時間キャンドルを購読します (キャンドル タイプ で設定可能)。
- ローソク足のオープン時に LWMA(5)、LWMA(10)、および LWMA(15) を計算します。
- 前のローソク足が
LWMA5 < LWMA10 < LWMA15 で、現在のローソク足が LWMA5 > LWMA10 > LWMA15 を示したときに強気の反転を検出します。逆の不等数列で弱気反転を検出します。
- 強気のクロスオーバーでは、ボリューム ロットのロング ポジションをターゲットにします。弱気のクロスオーバーでは、同じサイズのショートポジションをターゲットにします。この戦略は、現在のエクスポージャーとターゲットのエクスポージャーの差のみを売買することによって、既存のポジションを調整します。
- エントリが入力されるたびに、間隔 カウンターがリセットされます。 インターバル が完了したローソク足が新たなクロスオーバーなしで通過すると、戦略は現在の方向に別の注文 (ピラミッド) を追加し、保護注文を更新します。
- 利益目標と損失制限は、価格ステップで表される利益確定とストップロスの距離を使用して、結果として得られるすべてのポジションに適用されます。いずれかの値をゼロに設定すると、対応する保護が無効になります。
パラメーター
| 名前 |
デフォルト |
説明 |
| ボリューム |
0.1 |
ベースエントリーとピラミッドレイヤーごとにロット単位でサイズを注文します。 |
| 利益確定 |
20 |
利益確定注文の価格ステップの距離。無効にするには 0 に設定します。 |
| ストップロス |
20 |
保護ストップの価格ステップの距離。無効にするには 0 に設定します。 |
| 間隔 |
4 |
別のピラミッド位置を追加する前に待機する完成したキャンドルの数。ゼロはピラミディングを無効にします。 |
| クロスフィルター |
1.1 |
将来の ADX フィルタリングのために元のコードから保持される予約パラメータ (現在は使用されていません)。 |
| キャンドルタイプ |
1時間枠 |
LWMA 計算用のキャンドル データ ソース。 |
ポジション管理
- ヘルパー メソッド
AdjustPosition は、クロスオーバーのたびに最終位置が目的の露出と正確に一致することを保証します。
- ピラミッド取引は、
Position の現在の符号に依存して、既存の方向にのみロットを追加します。
SetTakeProfit と SetStopLoss は、リスク管理を最新のポジション サイズと同期させるために、各取引の後に呼び出されます。
注意事項
- MT4 スクリプトは ADX 値を計算しましたが、それを使用しませんでした。 クロス フィルター パラメーターは、互換性と将来の拡張のために残されています。
- 元の MQL 実装では、間隔カウンターがコメント化されていました。 StockSharp バージョンは、完成したキャンドルを数えることで、意図したピラミッド動作を有効にします。
StartProtection() は、組み込みの位置保護サービスを有効にするために、OnStarted 中に呼び出されます。
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>
/// Bread and Butter strategy - triple WMA crossover.
/// Buys when WMA(5) crosses above WMA(10) and WMA(10) is above WMA(15).
/// Sells when WMA(5) crosses below WMA(10) and WMA(10) is below WMA(15).
/// </summary>
public class Breadandbutter2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private decimal _prevWma5;
private decimal _prevWma10;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Breadandbutter2Strategy()
{
_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(); _prevWma5 = 0m; _prevWma10 = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var wma5 = new WeightedMovingAverage { Length = 5 };
var wma10 = new WeightedMovingAverage { Length = 10 };
var wma15 = new WeightedMovingAverage { Length = 15 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(wma5, wma10, wma15, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal wma5, decimal wma10, decimal wma15)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevWma5 = wma5;
_prevWma10 = wma10;
_hasPrev = true;
return;
}
if (_prevWma5 <= _prevWma10 && wma5 > wma10 && wma10 > wma15 && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (_prevWma5 >= _prevWma10 && wma5 < wma10 && wma10 < wma15 && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevWma5 = wma5;
_prevWma10 = wma10;
}
}
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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class breadandbutter2_strategy(Strategy):
def __init__(self):
super(breadandbutter2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_wma5 = 0.0; self._prev_wma10 = 0.0; self._has_prev = False
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(breadandbutter2_strategy, self).OnReseted()
self._prev_wma5 = 0.0; self._prev_wma10 = 0.0; self._has_prev = False
def OnStarted2(self, time):
super(breadandbutter2_strategy, self).OnStarted2(time)
self._has_prev = False
wma5 = WeightedMovingAverage()
wma5.Length = 5
wma10 = WeightedMovingAverage()
wma10.Length = 10
wma15 = WeightedMovingAverage()
wma15.Length = 15
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(wma5, wma10, wma15, self.process_candle).Start()
def process_candle(self, candle, wma5, wma10, wma15):
if candle.State != CandleStates.Finished: return
w5 = float(wma5); w10 = float(wma10); w15 = float(wma15)
if not self._has_prev:
self._prev_wma5 = w5; self._prev_wma10 = w10; self._has_prev = True; return
if self._prev_wma5 <= self._prev_wma10 and w5 > w10 and w10 > w15 and self.Position <= 0:
if self.Position < 0: self.BuyMarket()
self.BuyMarket()
elif self._prev_wma5 >= self._prev_wma10 and w5 < w10 and w10 < w15 and self.Position >= 0:
if self.Position > 0: self.SellMarket()
self.SellMarket()
self._prev_wma5 = w5; self._prev_wma10 = w10
def CreateClone(self): return breadandbutter2_strategy()