GitHub で見る
TradeXpert 手動取引パネル戦略
概要
オリジナルの TradeXpert MQL5 エキスパートアドバイザーは、ポジションを開く、保留注文を配置する、保護的なストップを適用する、既存の取引を素早く反転または閉じるためのボタンのコレクションを公開する手動操作の取引パネルです。この C# ポートは、すべてのパネルアクションをストラテジーパラメーターに変換することで、StockSharp 内で同じツールキットを再現します。ストラテジー自体は取引シグナルを生成しません。代わりに手動の指示を受け取り、要求された注文を実行し、入ってくるローソク足フロー上での保護的な決済を監督します。
再現された機能
- 成行アクション。 設定された取引ボリュームを使用した
Buy または Sell 成行注文の一度限りのリクエスト。
- 保留注文。 絶対価格または最新のローソク足終値からのオフセットを使用した Buy Limit/Stop と Sell Limit/Stop 注文の一回限りの配置。
- 保護管理。 ストップロスとテイクプロフィットレベルは絶対価格レベルとして、または記録されたエントリー価格からのオフセットとして定義できます。ストラテジーはローソク足の極値を監視し、保護レベルが違反されるとポジションを成行注文で閉じます。
- 手動決済コントロール。 専用パラメーターが MQL パネルの Close および Reverse ボタンを複製し、オンデマンドでポジションを閉じるか反転させることができます。
ストラテジーロジック
- ストラテジーは
CandleType で指定されたローソク足タイプをサブスクライブします。ストリームはオフセット用の最新終値を決定し、保護レベルが交差したかどうかを検出するために使用されます。
- 完成した各ローソク足でストラテジーは:
- 最新の
TradeVolume を基底クラスの Volume プロパティに適用します。
- インジケーターがまだ形成されていない場合でも、手動の閉じるまたは反転リクエストを処理します。
- 市場データが準備完了として確認されると、保留中のエントリーリクエストを実行し、保留注文を登録し、ストップロス/テイクプロフィットトリガーを評価します。
- ポジションサイズが変化すると(新規エントリー、スケールイン、または縮小)、ストラテジーは保存されたエントリー価格を更新し、オフセットベースのストップが最新の取引を即座に反映するようにします。
- 保護ロジックはローソク足の高値/安値を使用して違反を特定します。レベルが越えられると、ポジションが完全に閉じられることを確実にするために、現在の絶対ポジションサイズで反対方向に成行注文が送信されます。
パラメーター
CandleType – オフセットとリスクチェックのために価格を監視するために使用されるローソク足シリーズ。
TradeVolume – 各成行注文と保留注文に適用されるボリューム(正でなければなりません)。
EntryAction – None、BuyMarket、または SellMarket の値を持つ瞬時セレクター。None とは異なる値を設定すると、対応する成行注文が正確に一度トリガーされ、その後 None にリセットされます。
PendingAction – 保留注文セレクター(None、BuyLimit、BuyStop、SellLimit、SellStop)。有効な注文が登録された後にアクションは消費されます。
PendingPrice – 保留注文の絶対価格。PendingOffset に依存するには 0 のままにします。
PendingOffset – PendingPrice がゼロの場合に最新のローソク足終値に適用されるオフセット。正のオフセットは選択されたアクションに応じて終値の上下に自動的に価格を調整します。
UseStopLoss / StopLossPrice / StopLossOffset – ストップロス保護を有効にして設定します。絶対価格が提供されない場合、オフセットは保存されたエントリー価格から測定されます。
UseTakeProfit / TakeProfitPrice / TakeProfitOffset – テイクプロフィット管理のための類似の設定。
ClosePositionRequest – ポジション全体の即時成行決済を出すには true に設定します。リクエストが処理された後、フラグは false にリセットされます。
ReversePositionRequest – 現在のエクスポージャーを反転するには true に設定します。ストラテジーは既存のポジションを閉じ、ReverseVolume を使用して反対のものを開き、その後フラグをリセットします。
ReverseVolume – 反転後に確立される新しいポジションのボリューム。反転サイズが既存のポジションと一致する必要がある場合は、現在の絶対ポジションと等しく設定します。
使用ガイドライン
- オフセットとリスクをどのように測定するかに合わせてローソク足の集計(
CandleType)を選択します。デフォルトの 1 分間の時間軸は、受信ティックに反応したオリジナルパネルの動作を反映しています。
TradeVolume とオプションの保護レベル(StopLoss*、TakeProfit*)を設定します。絶対レベルとオフセットの間を自由に切り替えられます。絶対値がゼロのままにされると、オフセットが有効になります。
- 保留注文の場合、固定価格(
PendingPrice)または最新の終値からのオフセット(PendingOffset)のどちらを好むか決めます。ストラテジーは注文が提出される時点で価格を再計算します。
EntryAction、PendingAction、ClosePositionRequest、または ReversePositionRequest を変更して取引指示を送信します。各パラメーターはボタンのように動作します:リクエストが実行されると値は自動的にリセットされ、次のローソク足でアクションが繰り返されません。
- ストラテジーはポジションが開いている間、価格アクションを監視し続けます。ストップロスまたはテイクプロフィットの閾値が越えられると、ポジションは成行注文で閉じられます。重複注文を避けるために、両方の保護トリガーは次のエントリーまで無効化されます。
オリジナル MQL バージョンとの違い
- ビジュアルパネルはストラテジーパラメーターに置き換えられます。オリジナル UI のすべてのボタンは、StockSharp パラメーターグリッドまたは自動化スクリプトから編集できるトグルまたはセレクターとして公開されています。
- 保護のためにストップまたはリミット注文を配置する代わりに、指定された価格レベルが違反されるとストラテジーは成行注文でポジションを閉じます。これにより実装が高水準 API と互換性を保ち、別々のストップ注文の維持を避けます。
- 価格オフセットは生のティックの代わりに完成したローソク足を使用します。これによりバックテストとライブ取引セッション全体で動作が決定論的に保たれながら、イントラデイの応答性が提供されます。
メモ
- 同じローソク足内に複数の指示を並べることができます(例えば、成行買いをリクエストして、すぐにテイクプロフィットオフセットをリクエストする)。ストラテジーは次の完成したローソク足でそれらを順次処理します。
- 同じアクションを再度出す必要がある場合は、望む値を再選択するだけです。内部追跡ロジックが変更を検出して新しいリクエストを実行します。
- ポジションにスケールインする場合、保存されたエントリー価格は新しいサイズを反映するローソク足の終値に更新されます。精密な保護距離が必要な場合はそれに応じてオフセットを調整してください。
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>
/// TradeXpert Manual Trading Panel strategy. Uses CCI zero-line crossover (period 20).
/// </summary>
public class TradeXpertManualTradingPanelStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private decimal? _prevCci;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public TradeXpertManualTradingPanelStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 20).SetGreaterThanZero().SetDisplay("CCI Period", "CCI lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = null;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal cciVal)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevCci = cciVal; return; }
if (_prevCci == null) { _prevCci = cciVal; return; }
if (_prevCci.Value < 0m && cciVal >= 0m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevCci.Value > 0m && cciVal <= 0m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevCci = cciVal;
}
}
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 CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class trade_xpert_manual_trading_panel_strategy(Strategy):
"""CCI zero-line crossover."""
def __init__(self):
super(trade_xpert_manual_trading_panel_strategy, self).__init__()
self._cci_period = self.Param("CciPeriod", 20).SetGreaterThanZero().SetDisplay("CCI Period", "CCI lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).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(trade_xpert_manual_trading_panel_strategy, self).OnReseted()
self._prev_cci = None
def OnStarted2(self, time):
super(trade_xpert_manual_trading_panel_strategy, self).OnStarted2(time)
self._prev_cci = None
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(cci, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle, cci_val):
if candle.State != CandleStates.Finished:
return
if self._prev_cci is None:
self._prev_cci = float(cci_val)
return
cci_f = float(cci_val)
if self._prev_cci < 0 and cci_f >= 0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_cci > 0 and cci_f <= 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_cci = cci_f
def CreateClone(self):
return trade_xpert_manual_trading_panel_strategy()