GitHub で見る
ピーターパネル戦略
ピーター パネル戦略は、任意の MetaTrader 5 コントロール パネル「ピーター パネル」を StockSharp に移植します。オリジナルのエキスパートアドバイザーは、3 本の水平線 (エントリー、テイクプロフィット、ストップロス) とボタンマトリックスを描画し、トレーダーがそれらのレベルを使用して成行注文または指値注文を即座に提出できるようにしました。この C# 戦略は、グラフィカル パネルを対話型戦略パラメーターに置き換えながら、意思決定フローをそのまま維持します。すべてのトグルは元のボタンと同様に動作します。パラメータを true に設定すると、アクションがすぐに実行され、フラグが false にリセットされます。
主要な概念
- 手動アシスタント – 戦略はシグナルを生成しません。戦略 UI または自動化スクリプトで公開されているパラメーターを切り替えることで、いつ取引するかを決定します。
- 共有価格ライン – 水色のエントリーライン、緑色のテイクプロフィットライン、赤色のストップロスラインは 3 つの 10 進パラメータで表されます。値は手動で設定することも、
ResetCommand トグルを使用して現在の中間価格を中心に再計算することもできます。
- 包括的な注文範囲 – パネルからの 6 つの注文タイプすべてが実装されています:成行買い/売り、買いストップ、買い指値、売りストップ、売り指値。保護注文は、MetaTrader パネルが自動的に入力した TP/SL フィールドをエミュレートして、約定のたびに添付されます。
- 一括変更 –
ModifyCommand パラメータは、現在の価格ラインをすべてのアクティブな未決注文と、オープンポジションの保護的なストップロス/テイクプロフィット注文に再適用します。
- ワンタッチ清算 –
CloseCommand ボタンは、未処理の未決注文をキャンセルし、保護注文を削除し、市場でのネットポジションを平らにします。
元の実装と StockSharp の実装
| 特徴 |
MetaTrader 5 ピーター・パネル |
StockSharp ピーターパネル戦略 |
| ユーザーインターフェース |
ボタンと編集可能なフィールドを備えたチャート上のダイアログ |
スイッチや数値入力のように動作する戦略パラメータ |
| エントリー/TP/SL操作 |
水平線をドラッグするか、「リセット」を押して中央に戻します |
パラメータ値を直接編集するか、ResetCommand トグルを使用します |
| 注文の送信 |
ボタンが同期 OrderSend リクエストをトリガーします |
パラメータの切り替えは、対応する Buy/Sell ヘルパーを呼び出し、注文参照を保存します |
| TP/SLの取り扱い |
すべての注文で MqlTradeRequest.tp と .sl を通じて注文が完了します |
プロテクティブストップとターゲットは、約定直後に個別のストップ/リミット注文として登録されます。 |
| 注文変更 |
リストからチケットを選択し、「変更」を押します。 |
ModifyCommand は、アクティブな保留中の注文をすべてキャンセル/交換し、保護注文を更新します |
| 注文のクローズ |
強調表示されたチケットで「閉じる」を押します |
CloseCommand はポジション全体を決済し、保留中の注文と保護注文をすべてキャンセルします |
| 注文リスト |
チケットとレベルのグラフィカルな表 |
戦略は StockSharp の注文追跡に依存しています。詳細なステータスはログで確認できます |
注: MetaTrader を使用すると、トレーダーはリストから 1 つのチケットを選択できます。 StockSharp ポートは、ストラテジー パラメーター内でシングル チケットを直接選択できないため、ストラテジーによって作成されたすべての注文に変更とクローズを適用します。
パラメーター
| パラメータ |
説明 |
Volume |
ロット単位の取引量。セキュリティ ボリューム ステップと最小/最大制限に対して検証されます。 |
EntryLevel |
未決注文に使用される価格 (水色の線)。 |
TakeProfitLevel |
緑線の価格です。これは、ロングトレードのテイクプロフィットレベルとして機能し、ショートトレードの保護ストップレベルとして機能し、元のパネルを反映します。 |
StopLossLevel |
赤線の価格。これは、ロングトレードの保護ストップとして機能し、ショートトレードのテイクプロフィットターゲットとして機能します。 |
BuyMarketCommand |
true に設定されている場合は、成行買い注文を送信します。注文が送信されると、フラグは false にリセットされます。 |
BuyStopCommand |
EntryLevel で買い逆指値注文を出します。 |
BuyLimitCommand |
EntryLevel で買い指値注文を出します。 |
SellMarketCommand |
成行売り注文を送信します。 |
SellStopCommand |
EntryLevel で売りストップ注文を出します。 |
SellLimitCommand |
EntryLevel で売り指値注文を出します。 |
ModifyCommand |
EntryLevel、TakeProfitLevel、および StopLossLevel を既存の未決注文と現在のポジションの保護注文に再適用します。 |
CloseCommand |
未決注文をキャンセルし、保護注文を削除し、市場でのポジションをフラットにします。 |
ResetCommand |
現在の買値/買値中間点付近の 3 つの価格レベルを再計算します。 |
ワークフロー
- 目的の証券とポートフォリオが接続されたら、戦略を開始します。レベル 1 サブスクリプションは、
ResetCommand 機能を強化する内部入札/売値キャッシュを更新します。
ResetCommand トグルまたは手動編集を使用して、アクア、グリーン、レッドの価格レベルを設定します。
- アクションパラメータの 1 つを
true に切り替えて取引をトリガーします。この戦略では、トグルが自動的に false にリセットされるため、次のアクティブ化は意図的に行われます。
- 約定後、ストラテジーはポジションの方向に基づいて適切なストップロス注文とテイクプロフィット注文を送信します。たとえば、ロングポジションは赤のラインで売りストップを取得し、緑のラインで売りリミットを取得しますが、ショートポジションは逆の組み合わせを受け取ります。
- いつでもレベルを変更し、
ModifyCommand を押すと、戦略を再開せずに未決注文と保護的出口を更新できます。
- 取引セッションが終了したら、
CloseCommand を切り替えて、戦略によって管理されているすべての注文をフラット化してクリーンアップします。
純正パネルとの違い
- チケットのグラフィカルなリストはありません。代わりに、StockSharp ログは、登録されたすべての注文と取引を追跡します。個別のチケット管理が必要な場合は、戦略を任意の外部 UI に接続できます。
- StockSharp は TP/SL 価格をメイン注文リクエストに直接埋め込むことができないため、ストップロスとテイクプロフィットの値は明示的な子注文として実装されます。この動作は、MetaTrader パネルの最終結果と一致します。ポジションは最終的に同じレベルによって保護されます。
- 注文の交換は、キャンセルと再作成のサイクルを通じて実行されます。これにより、インプレース変更をサポートしていない会場でもワークフローの決定性が保たれます。
使用のヒント
- この戦略を StockSharp のグラフまたはダッシュボードと組み合わせて、元のパネル エクスペリエンスを再作成し、グラフ上のボタンを公開パラメータを切り替える UI 要素に置き換えます。
- この戦略では、複数のアクションをキューに入れません。シーケンスを自動化する必要がある場合(たとえば、レベルをリセットしてから未決注文を発注する)、前のトグルが
false にリセットされた後、順番にトグルをトリガーします。
- 保護注文はゼロ以外のポジションに対してのみ作成されます。ポジションを持たずに未決注文を発注する場合は、注文が約定した後に
ModifyCommand を呼び出して、最新のレベルが適用されていることを確認してください。
安全上の考慮事項
- 注文を送信する前に、ポートフォリオ、証券、および価格ステップの情報が利用可能であることを必ず確認してください。この戦略は、必要なデータが欠落している場合に警告をログに記録します。
Volume パラメータは機器の制限に制限されています。ステップまたは最小ボリュームに互換性がないために調整されたボリュームがゼロになった場合、オーダーは送信されず、ログに警告が表示されます。
CloseCommand が実行されると、戦略は最初に保護注文をキャンセルし、次に未決注文をキャンセルし、最後にポジションをフラット化します。これは、元のエキスパートアドバイザーからの防御的な操作順序を反映しています。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Peter Panel strategy: MACD histogram crossover.
/// Buys when MACD histogram turns positive, sells when it turns negative.
/// </summary>
public class PeterPanelStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _signalPeriod;
private decimal _prevMacd;
private decimal _prevSignal;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int SignalPeriod { get => _signalPeriod.Value; set => _signalPeriod.Value = value; }
public PeterPanelStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "MACD fast period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "MACD slow period", "Indicators");
_signalPeriod = Param(nameof(SignalPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Signal Period", "MACD signal period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacd = 0m;
_prevSignal = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = FastPeriod },
LongMa = { Length = SlowPeriod },
},
SignalMa = { Length = SignalPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(macd, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished) return;
if (!macdValue.IsFinal) return;
var macdTyped = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
if (macdTyped.Macd is not decimal macdLine || macdTyped.Signal is not decimal signal) return;
var histogram = macdLine - signal;
if (_hasPrev)
{
var prevHist = _prevMacd - _prevSignal;
if (prevHist <= 0 && histogram > 0 && Position <= 0)
BuyMarket();
else if (prevHist >= 0 && histogram < 0 && Position >= 0)
SellMarket();
}
_prevMacd = macdLine;
_prevSignal = signal;
_hasPrev = true;
}
}
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 MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class peter_panel_strategy(Strategy):
def __init__(self):
super(peter_panel_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._fast_period = self.Param("FastPeriod", 12)
self._slow_period = self.Param("SlowPeriod", 26)
self._signal_period = self.Param("SignalPeriod", 9)
self._prev_macd = 0.0
self._prev_signal = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def SignalPeriod(self):
return self._signal_period.Value
@SignalPeriod.setter
def SignalPeriod(self, value):
self._signal_period.Value = value
def OnReseted(self):
super(peter_panel_strategy, self).OnReseted()
self._prev_macd = 0.0
self._prev_signal = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(peter_panel_strategy, self).OnStarted2(time)
self._has_prev = False
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self.FastPeriod
macd.Macd.LongMa.Length = self.SlowPeriod
macd.SignalMa.Length = self.SignalPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, self._process_candle).Start()
def _process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal:
return
macd_line = macd_value.Macd
signal = macd_value.Signal
if macd_line is None or signal is None:
return
macd_line = float(macd_line)
signal = float(signal)
histogram = macd_line - signal
if self._has_prev:
prev_hist = self._prev_macd - self._prev_signal
if prev_hist <= 0 and histogram > 0 and self.Position <= 0:
self.BuyMarket()
elif prev_hist >= 0 and histogram < 0 and self.Position >= 0:
self.SellMarket()
self._prev_macd = macd_line
self._prev_signal = signal
self._has_prev = True
def CreateClone(self):
return peter_panel_strategy()