GitHub で見る

Triple SMA Spread戦略

概要

この戦略は、MetaTrader 5エキスパートアドバイザー3sma.mq5(id 21495)のC#ポートです。3つの単純移動平均が設定可能なスプレッドで互いに離れたときにトレードするという同じアイデアに従います。実装はローソク足サブスクリプションとインジケーターバインディングを使用したStockSharpの高レベルAPIを使用するため、手動のシリーズ管理は不要です。

オリジナルMT5の動作

MT5エキスパートは異なる期間と表示シフトを持つ3つの単純移動平均に基づいています。高速平均は現在のバーを使用し、中速と低速の平均はそれぞれ1バーと2バー過去にシフトされています。各tickで:

  1. シンボルの精度に基づいて、ユーザー定義のスプレッドをpipsから価格単位に変換します。
  2. 高速SMAが中速SMAの少なくともスプレッドの半分を下回ったときにロングポジションをクローズし、高速SMAが中速SMAのスプレッドの半分を上回ったときにショートポジションをクローズします。
  3. MA1 > MA2 + spread かつ MA2 > MA3 + spread で、エキスパートからの他のロングトレードが残っていない場合に新しいロングポジションを開きます。同様に、3つの平均すべてが反対の順序で整列している場合にショートポジションを開きます。
  4. 固定ロットサイズの成行注文のみを使用し、明示的なストップロスまたはテイクプロフィットレベルを適用しません。

StockSharp実装

  • インジケーター – 3つのSimpleMovingAverageインスタンスが同じローソク足ソースにサブスクライブします。コンパクトな履歴バッファーがMT5の「シフト」パラメーターを再現し、各比較が要求されたオフセットから完成したバー値を使用するようにします。
  • スプレッド処理 – スプレッドパラメーターはpipsで入力されます。戦略はSecurity.PriceStep(またはSecurity.Step)からpipサイズを導出し、3/5桁のFXシンボルに対して10を乗算し、小数点以下の引用符に対するMT5調整と一致します。
  • 注文フロー – 注文はBuyMarket/SellMarketで送信されます。逆転条件が現れると、戦略は反対のエクスポージャーを解消し、1つの成行注文で新しい方向を確立するために、現在のネットポジションの絶対値をベースボリュームに追加します。
  • 可視化 – チャートが利用可能な場合、戦略はソースローソク足と3つの移動平均、実行されたトレードを一緒にプロットします。

パラメーター

名前 説明 デフォルト
Volume 各市場エントリーに使用される注文ボリューム。 0.1
FastMaPeriod 高速SMAの期間(MT5のMA1に相当)。 9
FastMaShift 高速SMAをシフトするために使用された完成したバーの数。 0
MiddleMaPeriod 中速SMAの期間(MA2)。 14
MiddleMaShift 中速SMAの完成したバーのシフト。 1
SlowMaPeriod 低速SMAの期間(MA3)。 29
SlowMaShift 低速SMAの完成したバーのシフト。 2
MaSpreadPips pipsで測定された連続するSMA間の最小必要スプレッド。 10
CandleType 計算に使用されるローソク足シリーズ。 1分タイムフレーム

トレードロジック

  1. 3つの移動平均すべてが形成され、履歴バッファーに要求されたシフトの値が含まれるまで待ちます。
  2. スプレッドパラメーターをpipsから価格単位に変換し、エグジットフィルターのためにハーフスプレッドを計算します。
  3. エグジットフィルター
    • シフトされた高速SMAがシフトされた中速SMAを少なくともスプレッドの半分下回った場合、ロングエクスポージャーをクローズします。
    • シフトされた高速SMAがシフトされた中速SMAを少なくともスプレッドの半分上回った場合、ショートエクスポージャーをクローズします。
  4. エントリー条件
    • 高速SMAが中速SMAプラススプレッドより大きく、かつ中速SMAが低速SMAプラススプレッドより大きい場合にロングエントリー(またはショートからロングへの逆転)。
    • 高速SMAが中速SMAマイナススプレッドより小さく、かつ中速SMAが低速SMAマイナススプレッドより小さい場合にショートエントリー(またはロングからショートへの逆転)。

MT5バージョンとの違い

  • StockSharpは銘柄ごとに1つのネットポジションで作業します。逆転シグナルが現れると、戦略は前のネットエクスポージャーを解消して新しいものを確立するようにサイズ設定された1つの成行注文を発行します。MT5エキスパートは独立したロングとショートポジションを保持できました。
  • pipの変換は利用可能な最良のSecurityメタデータを使用します。ブローカーがPriceStepStepも提供しない場合、1がフォールバックとして使用されます。
  • 注文は高レベルAPIがローソク足サブスクリプションで動作するため、各tickではなく完成したローソク足で送信されます。
  • 戦略はMT5コードから詳細なログヘルパーを実装していません;必要に応じてStockSharp組み込みログを使用できます。

使用上の注意

  • 選択したローソク足シリーズがオリジナルのMT5設定で使用されたタイムフレームと一致することを確認します。
  • インストゥルメントが非標準のpipサイズを使用する場合は常にスプレッドパラメーターを調整します。
  • 戦略は完成したローソク足で作業するため、現在のローソク足が閉じるまで実行が遅延します。
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>
/// Triple SMA strategy that trades when three moving averages are properly aligned.
/// Enters long when fast > middle > slow, enters short when fast &lt; middle &lt; slow.
/// </summary>
public class TripleSmaSpreadStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _middlePeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private int _prevSignal;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int MiddlePeriod
	{
		get => _middlePeriod.Value;
		set => _middlePeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public TripleSmaSpreadStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

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

		_middlePeriod = Param(nameof(MiddlePeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("Middle Period", "Middle SMA period", "Indicators");

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevSignal = 0;
	}

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

		_prevSignal = 0;

		var fastSma = new ExponentialMovingAverage { Length = FastPeriod };
		var slowSma = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastSma, slowSma, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var close = candle.ClosePrice;
		var signal = 0;
		if (fast > slow && close > fast)
			signal = 1;
		else if (fast < slow && close < fast)
			signal = -1;

		if (signal == _prevSignal)
			return;

		var oldSignal = _prevSignal;
		_prevSignal = signal;

		if (signal == 1 && oldSignal <= 0)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (signal == -1 && oldSignal >= 0)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}