GitHub で見る

移動平均クロス戦略

概要

  • MetaTrader 5エキスパートアドバイザー**「Crossing Moving Average (barabashkakvn's edition)」**をソースMQL/21515から変換したもの。
  • ローソク足サブスクリプションとインジケーターバインディングを使用したStockSharpの高レベルAPIでロジックを実装。
  • モメンタムと移動平均クロスがトレンドリバーサルを捉えるインストゥルメント向けに設計。
  • このパッケージはC#バージョンのみ含みます。Pythonの翻訳はリクエスト通り意図的に省略されています。

コアアイデア

戦略はオプションの先行シフトを持つ2つの設定可能な移動平均(高速と低速)を監視し、そのクロスをモメンタム確認フィルターと組み合わせます。トレードは以下の場合のみ開きます:

  1. 高速平均が最新の2つの完成したバー上で設定された最小距離(pips)以上で低速平均を交差します。
  2. モメンタムインジケーターがユーザー定義の閾値を上回る(ロング)または下回る(ショート)と上昇し、トレードの方向に改善しています。
  3. シグナル価格ソースは、MetaTraderの適用価格モードを模倣するために、始値、高値、安値、終値、中央値、典型値、または加重ローソク足価格から選択できます。

リスクとトレード管理

  • 注文ボリュームはトレードごとに固定されており、新しいポジションへのエントリー時も既存のポジションの逆転時も適用されます。
  • ストップロス/テイクプロフィット距離はpipsで設定され、Security.PriceStepを使用して自動的に価格オフセットに変換されます。3桁または5桁の小数で引用されるインストゥルメントの場合、戦略はMetaTraderのpipサイズを再現するためにステップを10倍にします。
  • トレーリングストップは、価格がエントリーからTrailingStop + TrailingStep(pips)移動した後に活性化します。一旦トリガーされると、少なくともTrailingStep pips進むことができる場合はいつでも、ロングポジションの場合は現在価格 - TrailingStop(またはショートの場合は現在価格 + TrailingStop)にストップが移動します。
  • 保護レベルは各完成したローソク足で評価されます:ローソク足の範囲がストップロスまたはテイクプロフィットに触れると、MetaTraderでの注文執行を模倣するためにポジションが成行でクローズされます。

インジケーター

  • 高速移動平均 – 設定可能な期間、シフト、平滑化方法(SMA、EMA、SMMA、WMA)。
  • 低速移動平均 – 高速MAと同じオプション。
  • モメンタム – 期間と価格ソースは移動平均と同一。戦略はインジケーターが0または100付近の値を出力するかを自動検出し、それに応じてフィルターを適用します。

シグナルロジック

  1. すべてのインジケーターが完全に形成されるまで待ちます。アルゴリズムは、オリジナルのエキスパートアドバイザーと全く同様にシフトされたクロスを評価するために、最新の値の内部履歴を維持します。
  2. 前の2つのバー(適用されたシフト付き)の高速と低速平均間の価格距離を計算します。高速ラインは低速ラインを交差し、最小距離フィルターを超えなければなりません。
  3. 同じバーのモメンタム値を取得します。ロングエントリーの場合、現在のモメンタムは設定された閾値と前のモメンタム値の両方より大きくなければなりません;ショートエントリーの場合は逆が必要です。
  4. ポジションが反対の状態で新しいシグナルが現れると、戦略は既存のポジションをクローズし、設定されたロットサイズで新しい方向にすぐに開きます。

パラメーター参照

パラメーター 説明 デフォルト
OrderVolume 各成行注文のベースボリューム。 1
StopLossPips pipsでのストップロス距離(0はストップを無効にします)。 50
TakeProfitPips pipsでのテイクプロフィット距離(0はターゲットを無効にします)。 50
TrailingStopPips pipsでのトレーリングストップ距離(0はトレーリングを無効にします)。 5
TrailingStepPips トレーリングストップを移動するために必要な最小pip改善。 5
MinDistancePips クロスを検証するためのMA間の最小間隔。 0
MomentumFilter エントリーを許可するために必要な最小モメンタム差。 0.1
FastPeriod / FastShift 高速MA長と水平シフト(バー)。 13 / 1
SlowPeriod / SlowShift 低速MA長と水平シフト(バー)。 34 / 3
MaMethod 移動平均平滑化タイプ(Simple、Exponential、Smoothed、Weighted)。 Exponential
AppliedPrice インジケーター計算のローソク足価格。 Close
MomentumPeriod バーでのモメンタムルックバック長。 14
CandleType 戦略に供給されるローソク足のデータタイプ。 TimeFrame(1m)

実践的なノート

  • インストゥルメントに対してSecurity.PriceStepが設定されていることを常に確認します;そうでない場合、pipベースのリスク管理は生の価格単位にフォールバックします。
  • トレーリングロジックはTrailingStopPipsが有効な場合、正のTrailingStepPipsを必要とします — オリジナルのMetaTrader検証を反映しています。
  • ストップとテイクレベルはローソク足の範囲で評価されるため、より高解像度のローソク足を使用することでtickベースの実行に近い近似が得られます。
  • エントリーとトレーリング調整のログメッセージが含まれており、デバッグとパラメーター調整を容易にします。
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>
/// Moving average crossover strategy.
/// Enters long when fast EMA crosses above slow EMA, enters short on the opposite crossover.
/// </summary>
public class CrossingMovingAverageStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevFast;
	private decimal? _prevSlow;

	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 CrossingMovingAverageStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 13)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 34)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevFast = null;
		_prevSlow = null;

		var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
		var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fastEma);
			DrawIndicator(area, slowEma);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		if (_prevFast == null || _prevSlow == null)
		{
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		// Crossover detection
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;

		_prevFast = fast;
		_prevSlow = slow;

		// Golden cross: fast crosses above slow
		if (!prevAbove && currAbove)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		// Death cross: fast crosses below slow
		else if (prevAbove && !currAbove)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}