GitHub で見る
トレーディングパネル戦略 (ID 3468)
概要
TradingPanelStrategy は、MQL5 エキスパート アドバイザー EA_TradingPanel から変換された手動注文入力ヘルパーです。元のチャート上のパネルを再現するプログラムによるメソッドを公開します。1 回のアクションで複数の成行注文を発行したり、ピップ単位で測定されるストップロスとテイクプロフィットの距離を自動的に付加したり、オプションで取引するカスタム証券を選択したりできます。デフォルトはソース EA を反映しています (1 つのトレード、2 ピップのストップ、10 ピップのテイク、0.01 ボリューム)。
グラフィカル パネルとは異なり、この StockSharp ポートは自動化に適したエントリ ポイントに焦点を当てています。呼び出し元 (カスタム UI やスクリプトなど) は、必要に応じていつでも PlaceBuyOrders() または PlaceSellOrders() をトリガーできます。その一方で、戦略は出来高の正規化、価格の丸め、保護注文の配置を処理します。
パラメーター
| 名前 |
説明 |
注意事項 |
TradeCount |
アクションごとに送信された成行注文の数。 |
少なくともゼロを保証します。デフォルトは 1。 |
StopLossPips |
ピップス単位のストップロス距離。 |
ゼロを指定すると、ストップの作成が無効になります。デフォルトは 2。 |
TakeProfitPips |
利益確定距離 (pips)。 |
ゼロを指定すると、ターゲットの作成が無効になります。デフォルトは 10。 |
VolumePerTrade |
個々の成行注文の出来高。 |
Security.VolumeStep 経由で四捨五入されます。デフォルトは 0.01。 |
TargetSecurity |
取引商品のオプションのオーバーライド。 |
null の場合は Strategy.Security に戻ります。 |
すべてのパラメータは StrategyParam<T> を通じて公開されるため、StockSharp UI からの最適化とランタイム再構成がサポートされます。
実行フロー
- アクティブなセキュリティ (
TargetSecurity または Strategy.Security) を解決します。
- 金融商品のメタデータから pip サイズを導出します。金融商品の小数点以下の桁数が 3 桁以上の場合、
PriceStep に 10 を掛けます。これは、3 桁または 5 桁のシンボルの場合に乗算する MQL ロジックと同じです。
- 最新の参照価格 (最高の買値/売値、最後の取引に遡る) を取得し、
Security.ShrinkPrice で四捨五入します。
- 希望のボリューム:
TradeCount × VolumePerTrade を計算し、為替リミット (MinVolume、MaxVolume、VolumeStep) に合わせて、1 つのアクションでフラット化と反転の両方ができるように反対のオープン ポジションを調整します。
BuyMarket または SellMarket 経由で成行注文を送信します。
- 再び為替ティックサイズに正規化されたピップオフセットを使用して保護注文(ストップとリミット)を作成します。
- 立場が反転するか戦略が停止するたびに、廃止された保護命令をキャンセルします。
保護命令のロジック
- ロングエントリーでは、ストップロスの場合は
SellStop、テイクプロフィットの場合は SellLimit が配置されます。
- ショートエントリーではストップロスの
BuyStop とテイクプロフィットの BuyLimit が配置されます。
- 各保護命令は、新しくリクエストされたパネルのボリューム (元の MQL パネルに対する 1 回のアクションと同じ量) をカバーします。
- 注文は、
OnStopped、OnReseted、および反対側がトリガーされるたびに自動的にキャンセルされます。
使用上の注意
- ホスト アプリケーションで
Strategy.Security を割り当てるか、パネル メソッドを呼び出す前に TargetSecurity を指定します。それ以外の場合、取引は送信されません。
PlaceBuyOrders() を呼び出して、「BUY」ボタンの MQL と「SELL」ボタンの PlaceSellOrders() を複製します。
- 価格はライブ市場データに依存します。最良の買値/売値も最後の取引も利用できない場合、戦略はエラーをログに記録し、注文の送信をスキップします。
- ヘルパーは、再起動後に古い位置を防ぐために、
OnStarted で StartProtection() を呼び出します。
- 金融商品のメタデータに
PriceStep が含まれていない場合、ピップ サイズはデフォルトで 0.0001 (ほとんどの FX シンボルでは 1 ピップ) になります。ブローカーが代替増分を使用する場合は、PriceStep を明示的に設定します。
MQL パネルとの違い
- 埋め込まれたグラフィカル UI はありません。インテグレータは独自のインターフェイスを構築するか、外部ロジックからパブリック メソッドをトリガーすることが期待されます。
- プロテクト注文は、個別の MT5 チケットごとではなく、アクションごとに集約されます。結果として得られる純エクスポージャーは、StockSharp の実装を簡潔に保ちながら、MT5 の動作と一致します。
- 数量と価格の検証は、StockSharp の規則 (
Security.ShrinkPrice、VolumeStep、MinVolume、MaxVolume) に従います。これにより、厳密な増分を伴う会場での注文の拒否を回避できます。
- 実行ログは、
LogInfo および LogError を通じて提供され、StockSharp 端末での監視を支援します。
はじめに
- 戦略をインスタンス化し、ポートフォリオと証券を割り当てます (または
TargetSecurity を設定します)。
StartProtection() が内部の安全装置を装備できるように戦略を開始します。
- ユーザー入力または自動トリガーに基づいて、
PlaceBuyOrders() または PlaceSellOrders() を呼び出します。
- ログを監視して確認メッセージを確認し、必要に応じて追加の UI ロジックを管理します。
この手動取引パネル変換は、StockSharp の高レベルの戦略フレームワークに適応した、元の MT5 エキスパート アドバイザーの軽量かつ忠実な再現を提供します。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Trading Panel strategy: WMA crossover.
/// Buys when fast WMA crosses above slow WMA, sells on cross below.
/// </summary>
public class TradingPanelStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal _prevFast;
private decimal _prevSlow;
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 TradingPanelStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
BuyMarket();
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
SellMarket();
}
else
{
if (fastValue > slowValue && Position <= 0)
BuyMarket();
else if (fastValue < slowValue && Position >= 0)
SellMarket();
}
_prevFast = fastValue;
_prevSlow = slowValue;
_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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class trading_panel_strategy(Strategy):
def __init__(self):
super(trading_panel_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._fast_period = self.Param("FastPeriod", 10)
self._slow_period = self.Param("SlowPeriod", 30)
self._prev_fast = 0.0
self._prev_slow = 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
def OnReseted(self):
super(trading_panel_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(trading_panel_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._has_prev:
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
self.SellMarket()
else:
if fast_val > slow_val and self.Position <= 0:
self.BuyMarket()
elif fast_val < slow_val and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
self._has_prev = True
def CreateClone(self):
return trading_panel_strategy()