GitHub で見る

Test MACD戦略

概要

Test MACD戦略は、MetaTraderのTestMACDエキスパートアドバイザーをStockSharp高レベルAPIへ忠実に変換したものです。Moving Average Convergence Divergence(MACD)指標を使ってモメンタム変化を検出し、確定ローソク足でMACDラインがシグナルラインをクロスするたびに取引を実行します。戦略は、CandleTypeパラメーターで指定された単一銘柄と時間軸で動作します。

取引ロジック

  1. CandleTypeで定義されたローソク足データを購読し、設定可能な高速、低速、シグナル期間でMACD指標を計算します。
  2. 各確定ローソク足でMACD値の差(MACD - Signal)を監視します。
  3. 差が非正から正へ符号変化したとき、MACDラインがシグナルラインを上抜けたことを意味し、強気エントリーを発動します。ロングを開く前にショートエクスポージャーを閉じます。
  4. 差が非負から負へ符号変化したとき、MACDラインがシグナルラインを下抜けたことを意味し、弱気エントリーを発動します。ショートを開く前にロングエクスポージャーを閉じます。
  5. すべての注文はTradeVolumeで設定した固定数量の成行で発行されます。
  6. 元のエキスパートのポイントベースのリスク管理を再現するため、各エントリーは価格ステップで表したストップロスとテイクプロフィット水準で自動保護されます。

リスク管理

  • ストップロスとテイクプロフィット距離はMetaTrader入力を反映し、価格ステップで指定されます。銘柄にPriceStep情報がない場合、戦略はMinPriceStepまたは1を乗数として絶対価格距離へフォールバックします。
  • 保護注文は戦略開始時にStartProtectionで一度作成され、再設定なしですべての後続取引に適用されます。

パラメーター

パラメーター 説明 既定値
FastPeriod MACD計算に使う高速EMA長。 12
SlowPeriod MACD計算に使う低速EMA長。 24
SignalPeriod MACD平滑化用シグナルラインEMA長。 9
StopLossPoints 価格ステップで表すストップロス距離。 90
TakeProfitPoints 価格ステップで表すテイクプロフィット距離。 110
TradeVolume すべての成行注文の固定数量。 1
CandleType 戦略が購読するローソク足データタイプと時間軸。 30分時間軸

使用上の注意

  • PriceStepMinPriceStepを利用できるよう、開始前に戦略を銘柄へ接続してください。
  • 選択したCandleTypeに市場データが提供されることを確認してください。そうでなければMACD指標が形成されず、取引は発生しません。
  • 戦略は各クロスイベントをログに記録するため、バックテスト中の取引判断を追跡しやすくなります。

変換詳細

  • 元のMetaTraderクラスCSignalMACDCTrailingNoneCMoneyFixedLotは、StockSharpの指標バインディングとStartProtection機構に置き換えられています。
  • MACDクロスをチェックしていたExtStateMACDのロジックは、連続する確定ローソク足間のMACD差分に対する符号変化検出器で表現されています。
  • 資金管理は固定数量パラメーターへ簡略化され、パーセントベースサイズが無効な場合のCMoneyFixedLotの固定ロット動作に近いものです。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Test MACD strategy: MACD histogram zero-cross.
/// Buys when MACD histogram crosses above zero.
/// Sells when MACD histogram crosses below zero.
/// </summary>
public class TestMacdStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;

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

	public TestMacdStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

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

		var macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd = { ShortMa = { Length = 12 }, LongMa = { Length = 26 } },
			SignalMa = { Length = 9 }
		};

		decimal? prevHistogram = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(macd, (candle, macdVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (macdVal.IsEmpty)
					return;

				var v = (MovingAverageConvergenceDivergenceSignalValue)macdVal;
				if (v.Macd is not decimal macdDec || v.Signal is not decimal signalDec)
					return;

				var histogram = macdDec - signalDec;

				if (prevHistogram.HasValue)
				{
					if (prevHistogram.Value <= 0m && histogram > 0m && Position <= 0)
						BuyMarket();
					else if (prevHistogram.Value >= 0m && histogram < 0m && Position >= 0)
						SellMarket();
				}

				prevHistogram = histogram;
			})
			.Start();

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