GitHub で見る

MACD と SAR 戦略

この戦略は、MetaTrader のオリジナル EA「MACD and SAR」を再現したものです。完成した各ローソク足で、MACD のメイン線とシグナル線の関係、およびパラボリック SAR のレベルを評価します。各比較を反転させる設定可能なスイッチにより、同じテンプレートを逆張りまたはトレンドフォローのセットアップに使用できます。設定された最大積み上げポジション数を超えない限り、複数のエントリーが許可されます。

ロングシグナルが現れると、既存のショートポジションが決済され、新しいロットが買いで建てられます(上限に達していない場合)。同様に、ショートシグナルは最初にロングを決済してからショートロットを追加します。追加のストップロスやテイクプロフィット注文はなく、反対のシグナルが生成されたときのみポジションが決済されます。

戦略ロジック

  1. 設定されたタイムフレームの完成したローソク足を待つ。
  2. 終値で計算された MACD 値(メイン、シグナル、ヒストグラム)とパラボリック SAR レベルを読み取る。
  3. 以下の比較を評価する。それぞれ対応するブールパラメーターで反転可能:
    • MACD メイン線 vs. シグナル線。
    • MACD シグナル線 vs. ゼロレベル。
    • パラボリック SAR vs. 終値。
  4. ロング側の 3 つの比較がすべて満たされ、戦略にまだ新しいポジションを積み上げる余裕がある場合、指定されたロットサイズを買う(ショートを決済するのに必要な数量を含む)。
  5. ショート側の 3 つの比較がすべて満たされ、積み上げ限度が許す場合、指定されたロットサイズを売る(ロングを決済するのに必要な数量を含む)。

パラメーター

  • TradeVolume — 個別トレードあたりの数量(デフォルト 0.1)。
  • MaxPositions — 一方向に積み上げられる最大ポジション数(デフォルト 10)。
  • MacdFastPeriod — MACD の高速 EMA 期間(デフォルト 12)。
  • MacdSlowPeriod — MACD の低速 EMA 期間(デフォルト 26)。
  • MacdSignalPeriod — MACD のシグナル平滑化期間(デフォルト 9)。
  • SarStep — パラボリック SAR の加速ステップ(デフォルト 0.02)。
  • SarMaximum — パラボリック SAR の最大加速度(デフォルト 0.2)。
  • BuyMacdGreaterSignaltrue の場合、ロングには MACD メイン > シグナルが必要;そうでなければ逆を期待(デフォルト true)。
  • BuySignalPositivetrue の場合、ロングには MACD シグナル > 0 が必要;そうでなければシグナル < 0 を期待(デフォルト false)。
  • BuySarAbovePricetrue の場合、ロングには SAR が価格を上回ることが必要;そうでなければ価格が SAR を上回ることを期待(デフォルト false)。
  • SellMacdGreaterSignaltrue の場合、ショートには MACD メイン > シグナルが必要;そうでなければ MACD メイン < シグナルを期待(デフォルト false)。
  • SellSignalPositivetrue の場合、ショートには MACD シグナル > 0 が必要;そうでなければシグナル < 0 を期待(デフォルト true)。
  • SellSarAbovePricetrue の場合、ショートには SAR が価格を上回ることが必要;そうでなければ価格が SAR を上回ることを期待(デフォルト true)。
  • CandleType — データ処理に使用するローソク足タイプ/タイムフレーム(デフォルト 15 分)。

追加メモ

  • この戦略はインジケーターのクロスのみに依存しており、保護ストップや利益目標はありません。
  • ポジションの積み上げは、絶対ポジション数量を MaxPositions * TradeVolume と小さな許容差で比較することにより実装されています(丸め処理のため)。
  • すべてのトレードは成行注文で実行されます。ポートフォリオの数量設定が取引予定の商品と一致していることを確認してください。
  • ドローダウン制限やトレーリングストップが必要な場合は、オプションのポートフォリオ保護ルールを追加してください;デフォルトでは含まれていません。
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>
/// MACD and Parabolic SAR trend-following strategy (simplified).
/// Uses EMA crossover as MACD proxy and ParabolicSar for trend confirmation.
/// </summary>
public class MacdAndSarStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

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

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

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

	public MacdAndSarStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Indicators");

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

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candles used for analysis", "General");
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

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

		decimal prevFast = 0, prevSlow = 0;
		bool hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevFast = fastValue;
					prevSlow = slowValue;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevFast = fastValue;
					prevSlow = slowValue;
					return;
				}

				// Crossover detection (MACD-like)
				if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
				{
					BuyMarket();
				}
				else if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
				{
					SellMarket();
				}

				prevFast = fastValue;
				prevSlow = slowValue;
			})
			.Start();

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