GitHub で見る

Advanced EA Panel戦略

この戦略は MQL5 の Advanced EA Panel ユーティリティの StockSharp ポートです。元のエキスパートアドバイザーはマルチタイムフレーム分析、ピボット管理、クイックトレードボタンを備えた手動取引ダッシュボードを提供していました。C# 実装はチャート上のコントロールパネルなしに利用できるよう、それらの分析機能を自動化された戦略内に再現します。

主な特徴

  • 9 つの時間軸(M1 … MN1)を集約し、各ホライズンの EMA(3/6/9)、SMA(50/200)、CCI(14)、RSI(21) の投票を追跡します。
  • 設定可能なローソク足シリーズでフロアートレーダー、Woodie、Camarilla のピボットレベルを計算します。
  • ATR フィードでボラティリティを監視し、各重要な変化を記録します。
  • アクティブポジションのストップ距離、リワード距離、ライブのリスク/リワード比を計算することで内部リスクパネルを維持します。
  • マルチタイムフレームの投票が設定可能な閾値を超えると自動的に注文実行をサポートします。反対取引はパネルボタンを押す時と全く同様に、反転前に均されます。
  • StartProtection を活用して、ストップロスとテイクプロフィットのガードが再起動後も存続し、元のパネルの保護ロジックを反映します。

取引ロジック

  1. 各タイムフレームのサブスクリプションは EMA(3/6/9)、SMA(50/200)、CCI(14)、RSI(21) のインジケーター値を生成します。終値が移動平均を上回り、CCI が +100 を超え、RSI が 60 を超えると強気票が追加されます。弱気票は逆の条件で生成されます。中立の読みはスコアに寄与しません。
  2. 準備できたタイムフレームの合計スコアが DirectionalThreshold と比較されます。スコア ≥ 閾値で買いシグナルが生成され;スコア ≤ –閾値で売りシグナルが生成されます。
  3. 自動取引が有効な場合、戦略は:
    • 反転注文を送る前に ClosePosition() で逆ポジションを閉じます。
    • Volume に従ってサイズされ、最近の Security.VolumeStep に丸められた成行注文を送ります。
    • pips で表現されたストップロス/テイクプロフィットのブラケットを付加するために StartProtection に依存します。
  4. 主要ローソク足シリーズの ATR が記録されます。丸め精度を超えた変化はすべて新しいボラティリティレポートを出力します。
  5. ピボットレベルはピボットタイムフレームが完成したローソク足を生成するたびに再計算されます。ログは PP、R1–R4、S1–S4 を表示し、裁量レベルとして使用したりダッシュボードにエクスポートしたりできます。

パラメーター

名前 説明 グループ デフォルト
Volume ロット単位の取引出来高。注文送信前に VolumeStep に丸められます。 取引 1.0
StopLossPips エントリーからストップロスまでの距離(価格ステップ単位)。0 でストップを無効化。 リスク 50
TakeProfitPips エントリーからテイクプロフィットまでの距離(価格ステップ単位)。0 でテイクを無効化。 リスク 100
VolatilityPeriod ボラティリティ記録に使用する ATR ルックバック長。 ボラティリティ 14
PrimaryCandleType ATR 計算とチャート描画を駆動するローソク足タイプ。 一般 15 分足ローソク
PivotCandleType ピボットレベル再計算に使用するローソク足タイプ。 一般 1 時間足ローソク
DirectionalThreshold 買い/売りシグナルをトリガーするために必要な絶対スコア。 シグナル 3
AutoTradingEnabled 検出されたシグナルの自動実行を有効にします。 シグナル true
PivotFormula ピボットプリセット(ClassicWoodieCamarilla)。 一般 Classic

リスク管理

  • StartProtectionStopLossPipsTakeProfitPips から計算された価格ベースのブラケットを付加します(PriceStep を使用して絶対価格に変換)。
  • _entryPrice_stopPrice_takePrice はフィル時に更新されるため、戦略は pips 単位のリスク、リワード、リスク/リワード比を記録できます。
  • 自動取引が無効な場合、リスクモニターは戦略外で実行された手動エントリーにも機能し続けます。

MQL5 パネルとの違い

  • 元の EA はチャート上にボタンとドラッグ可能なラインを表示していました;StockSharp バージョンはログと戦略パラメーターを通じて同じ分析を公開します。コード内のすべてのコメントは、必要に応じて結果を UI に拡張または接続する方法を説明しています。
  • ポジション管理は自動化されています。買い売り反転閉じるのクリックは、マルチタイムフレームスコアへの反応として RequestExecutionSendOrderClosePosition() に置き換えられます。
  • インタレストポイント、手動タブ編集、チャートオブジェクト操作はポートされていません。代わりにピボットはプログラム的に再計算され記録されます。トレーダーはログを使用するか、必要に応じてオブジェクトを描画するために戦略を拡張できます。
  • ボラティリティ、リスク指標、ピボットはチャートオブジェクトに依存せずライブデータから再計算されるため、再起動後も持続します。

使用上の注意

  1. 戦略をシンボルに接続し、コネクターが PanelTimeFrames にリストされているすべてのローソク足タイプを提供することを確認します。データが欠けていると、タイムフレームごとに少なくとも 1 本のローソク足が完成するまでシグナル生成が遅れます。
  2. 感度を制御するために DirectionalThreshold を調整します。閾値が高いほど、取引前にタイムフレーム間でより多くの合意が必要です。
  3. AutoTradingEnabled = false を設定して、別のツールから手動で注文を出しながら、モジュールを情報ダッシュボードとして使用します。
  4. クラスは主要ローソク足、ATR、自己取引のデフォルトチャートレンダリングを追加します。カスタムビジュアライゼーションが必要な場合は、これらの呼び出しを削除または拡張してください。

変換サマリー

  • UI アクション → 戦略メソッド。 パネルボタンハンドラー(EAPanelClickHandlerT0ClickHandler など)は、買い/売り/反転/閉じるフローを保持する注文実行ヘルパーにマッピングされます。
  • ピボット数式。 MQL5 のスピナーはレベルごとに独立した数式を許可していました;このポートはパネルがクイック選択ボタンで提供していたプリセットの組み合わせ(ClassicWoodieCamarilla)を維持します。
  • インジケーター追跡。 ネイティブの MQL5 インジケーターハンドルは、Bind コールバックを持つ StockSharp の ExponentialMovingAverageSimpleMovingAverageCommodityChannelIndexRelativeStrengthIndex に置き換えられます。
  • リスクパネル。 以前は編集ボックスにレンダリングされていたすべてのリスク/リワード計算が記録され、任意の監視コンポーネントで利用できます。

したがって、この戦略は Advanced EA Panel の意図—クイックリアクションロジックを備えた集中的な状況認識—を保持しながら、最適化や裁量監視のための完全自動化された StockSharp 戦略として提示します。

using System;
using System.Collections.Generic;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Advanced EA Panel strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class AdvancedEaPanelStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public AdvancedEaPanelStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}