GitHub で見る

グラール EMA の勢い戦略

この戦略は、MetaTrader 4 エキスパート アドバイザー 0Graal-CROSSmuvingi の変換です。終値の速い指数移動平均 (EMA) が、始値で計算されたより遅い EMA を横切るときに発生するトレンドの反転を取引します。モメンタムオシレーターはブレイクアウトの方向を確認し、固定距離のテイクプロフィットはオリジナルのMT4実行モデルを再現します。

取引アイデア

  1. Fast EMA on Close は、最新の価格動向を追跡します。
  2. オープン時の遅い EMA は遅れてクロスオーバー ベースラインを形成します。
  3. モメンタムオシレーター (期間 14) は、価格が中立値 (100) からどれだけ強く加速するかを測定します。この戦略は、モメンタムが設定可能なフィルターを超えて 100 から逸脱し、同じ方向に強化され続ける場合にのみ取引されます。
  4. 利益確定 は、MT4 TakeProfit パラメーターを反映して、商品ポイントで測定される事前定義された距離の後に取引を終了します。

エントリールール

  • 長いセットアップ
    • 現在終了しているローソク足の速い EMA が遅い EMA を上回っていますが、前のバーの速い EMA は遅い EMA 以下でした。
    • モメンタム (値から 100 を引いた値) は、MomentumFilter のしきい値を超えており、前のバーのモメンタム読み取り値よりも高くなります。
    • 既存のショート ポジションは、新しいロングをオープンする前にクローズされます。新しいロング サイズは、設定された Volume にオープン ショートを反転するのに必要な量を加えたものと等しくなります。
  • 簡単なセットアップ
    • 速い EMA は遅い EMA を下回っていますが、前のバーには速い EMA が遅い EMA 以上でした。
    • モメンタム(値から 100 を引いた値)は、マイナスの MomentumFilter しきい値を下回り、前のバーのモメンタム読み取り値よりも小さいです。
    • 既存のロングポジションは、新しいショートをオープンする前にクローズされます。新しいショート サイズは、設定された Volume にオープン ロングをカバーするのに必要な数量を加えたものと等しくなります。

終了ルール

  • 価格が計算されたテイクプロフィットターゲット(TakeProfitPoints * PriceStep)に達すると、ポジションは自動的にクローズされます。
  • 注文サイズには常に現在のポジションの数量が含まれるため、新しい逆シグナルもポジションを即座に反転させます。

パラメーター

名前 説明 デフォルト
FastPeriod 終値における EMA の長さ。 13
SlowPeriod 始値における EMA の長さ。 34
MomentumPeriod モメンタムオシレーターの振り返り。 14
MomentumFilter 取引に必要な 100 からの最小絶対モメンタム偏差。 0.1
TakeProfitPoints 価格ポイントでの利益目標までの距離 (PriceStep を乗算)。 200
CandleType 計算に使用されるローソク足のデータ型 (デフォルトでは 15 分の時間枠)。 15分の時間枠
Volume 新しいエントリに使用される注文サイズ。エンジンはそれを基本クラスから継承します。 1

実装メモ

  • シグナルは閉じたローソク足 (CandleStates.Finished) でのみ処理されます。
  • この戦略は、選択されたローソク足タイプを SubscribeCandles でサブスクライブし、高レベルの API を介して EMA とモメンタム インジケーターの両方をバインドします。
  • 遅い EMA はバインド コールバック内で始値を使用して手動で更新され、PRICE_OPEN が使用された MT4 の動作を再現します。
  • テイクプロフィット管理は、MT4 のポイントベースの出口ロジックをエミュレートするためにバー内の高値と安値を監視します。
  • StartProtection() は、戦略が取引を開始する前に予期しないオープンポジションを防ぐために開始時に有効になります。
using System;

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

namespace StockSharp.Samples.Strategies;

public class GraalEmaMomentumStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _momentumPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int MomentumPeriod { get => _momentumPeriod.Value; set => _momentumPeriod.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public GraalEmaMomentumStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
		_momentumPeriod = Param(nameof(MomentumPeriod), 14).SetDisplay("Momentum", "Momentum period", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = default;
		_prevSlow = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var mom = new Momentum { Length = MomentumPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, mom, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal mom)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		if (_prevFast <= _prevSlow && fast > slow && mom > 0 && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevFast >= _prevSlow && fast < slow && mom < 0 && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevFast = fast;
		_prevSlow = slow;
	}
}