GitHub で見る
取引コントロールパネル戦略
概要
取引コントロールパネル戦略は、元のMQL5スクリプトからの手動取引パネルをStockSharp高レベルAPIにポートします。クラスはパネルのすべてのボタンを複製するヘルパーメソッドを公開します:ボリュームプリセットトグル、マーケット買い/売りアクション、現在のポジションのクローズ、エクスポージャーの反転、専用のブレイクイーブンルーティン。保護的なストップロスとテイクプロフィット注文は、ソースエキスパートアドバイザーの安全機能を反映して、平均エントリー価格を中心に自動的に生成できます。
チャートコントロールを描画する代わりに、StockSharp実装はUIコード、スクリプト、または自動化されたワークフローから呼び出せる強く型付けされたインターフェースを提供します。戦略は選択されたボリュームプリセットを追跡し、ボリュームを最も近い取引所ステップに丸め、BuyMarket、SellMarket、SellStop、BuyLimitなどの組み込みStrategyヘルパーを通じてマーケット/ストップ/リミット注文を発行します。
パラメーター
- VolumeList – 元のチェックボックスのように動作するセミコロン区切りのボリュームプリセット。MLQレイアウトとの互換性を保つために最初の9つの値のみが使用されます。空白は無視され、無効な数値はスキップされます。
- CurrentVolume – 現在トグルされたプリセットに基づく集計ボリューム。セッターは
Security.VolumeStep(利用可能な場合)または2小数点(forexスタイルのロット)を使用して値を丸めます。外部UIと統合する際にこのパラメーターを手動で設定することもできます。
- BreakEvenSteps –
ApplyBreakEven()を通じて保護ストップをブレイクイーブンに移動する際にエントリー価格に追加される価格ステップ数。インストゥルメントにPriceStepがない場合、値は直接価格オフセットとして扱われます。
- StopLossSteps – 価格ステップで表された初期ストップロス距離。ゼロの値はポジションが開かれたり変更されたりした際の自動ストップを無効にします。
- TakeProfitSteps – 価格ステップでの初期テイクプロフィット距離。ストップロスパラメーターと同じように機能します。
手動コントロール
すべての実行時アクションは、ホストアプリケーションがボタン、ホットキー、またはスクリプトに接続できるように、公開メソッドを通じて公開されています:
ToggleVolumeSelection(int index) – 集計量からボリュームを追加または削除することでプリセットチェックボックスを模倣します。無効なインデックスはサイレントな間違いを防ぐためにスローします。
ResetVolumeSelection() – すべてのプリセットをクリアし、CurrentVolumeをゼロにリセットします。
ExecuteBuy() / ExecuteSell() – 現在のボリュームを使用してマーケット注文を送信します。どちらのメソッドもボリュームが選択されていない場合にfalseを返します。
CloseAllPositions() – 現在のポジションサイズと反対のマーケット注文を送信します(ショートにはBuyMarket、ロングにはSellMarket)。
ReversePosition() – 既存のポジションをクローズし、集計ボリュームを使用して反対方向にすぐに新しいポジションを開きます。MQLパネルの「Reverse」ボタンと全く同じです。
ApplyBreakEven() – 保護ストップを平均エントリー ± BreakEvenSteps * PriceStepとして再計算し、新しいストップ注文を置きます(ロングにはSellStop、ショートにはBuyStop)。戦略がオープンポジションを保持し、ゼロより大きいオフセットが提供される場合にのみtrueを返します。
ポジションサイズが変わるたびに、OnPositionChangedは保護注文を再構築します。最初に前のストップ/ターゲットペアをキャンセルし、次に最新の平均エントリー価格と設定されたオフセットを使用してそれらを再作成します。ポジションをクローズする(手動またはストップ/ターゲットの約定による)とアクティブな保護注文が削除されて、取引所に孤立した指示が残らないようにします。
使用ワークフロー
- VolumeListで希望するボリュームプリセットを設定します(例:
0.05; 0.10; 0.25; 0.50; 1.00)。
ToggleVolumeSelectionで1つ以上のプリセットをトグルします。CurrentVolumeパラメーターは丸め後の累積値を表示します。
ExecuteBuyまたはExecuteSellを呼び出して市場に入ります。StopLossStepsまたはTakeProfitStepsがゼロより大きい場合、戦略は平均エントリー価格に対して自動的にSellStop/BuyStopとSellLimit/BuyLimit注文を置きます。
- 価格が有利に動いたら
ApplyBreakEvenを使用して、ストップをエントリーの上(ロングの場合)または下(ショートの場合)に設定されたオフセット分トレーリングします。
CloseAllPositionsはすぐに市場を出ます。ReversePositionは現在選択されているロットサイズを再利用しながらクローズとエクスポージャーの反転の両方を行います。
ResetVolumeSelectionはすべてのプリセットをクリアして、次の取引に向けてパネルを準備します。
ノートと推奨事項
- ブレイクイーブンと保護ロジックは
PositionAvgPriceと現在のSecurity.PriceStepに依存します。戦略を開始する前にインストゥルメントのメタデータが入力されていることを確認してください。
StartProtection()はOnStarted中に呼び出されるため、組み込みの保護エンジンがこの戦略が登録するストップ/ターゲット注文を追跡できます。
- ヘルパーメソッドはStockSharp注文ヘルパーに対する同期ラッパーです。厳格な順序付けが必要な場合、非同期確認を必要とする取引所またはアダプターは次のコマンドを発行する前に注文イベントを待つ必要があります。
- クラスはUIイベントを公開されたメソッドにマッピングすることで、カスタムWPF/WinFormsパネル、RESTサービス、またはコンソールツールに埋め込むことができます。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class ControlPanelStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _momPeriod;
private decimal? _prevMom;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int MomPeriod { get => _momPeriod.Value; set => _momPeriod.Value = value; }
public ControlPanelStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_momPeriod = Param(nameof(MomPeriod), 10).SetGreaterThanZero().SetDisplay("Momentum Period", "Momentum lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMom = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMom = null;
var mom = new Momentum { Length = MomPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(mom, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal momVal)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevMom = momVal; return; }
if (_prevMom == null) { _prevMom = momVal; return; }
if (_prevMom.Value < 100m && momVal >= 100m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevMom.Value > 100m && momVal <= 100m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevMom = momVal;
}
}
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 Momentum
from StockSharp.Algo.Strategies import Strategy
class control_panel_strategy(Strategy):
def __init__(self):
super(control_panel_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._mom_period = self.Param("MomPeriod", 10) \
.SetDisplay("Momentum Period", "Momentum lookback", "Indicators")
self._prev_mom = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def MomPeriod(self):
return self._mom_period.Value
def OnReseted(self):
super(control_panel_strategy, self).OnReseted()
self._prev_mom = None
def OnStarted2(self, time):
super(control_panel_strategy, self).OnStarted2(time)
self._prev_mom = None
mom = Momentum()
mom.Length = self.MomPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(mom, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, mom_value):
if candle.State != CandleStates.Finished:
return
mv = float(mom_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_mom = mv
return
if self._prev_mom is None:
self._prev_mom = mv
return
if self._prev_mom < 100.0 and mv >= 100.0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_mom > 100.0 and mv <= 100.0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_mom = mv
def CreateClone(self):
return control_panel_strategy()