GitHub で見る

MACD Stochastic 2戦略

この戦略はMetaTraderの「MACD Stochastic 2」エキスパートロジックをStockSharpの高レベルAPIで再現しています。3バーMACDスイングフィルターとストキャスティクスオシレーターを組み合わせ、売られすぎと買われすぎの領域付近でのモメンタム転換を探します。リスクは方向別のストップ、テイクプロフィット、およびpip単位で動作するオプションのトレーリングストップによって管理されます。

概要

  • CandleTypeパラメーターで指定された任意の銘柄と時間軸で動作します。
  • MACDメインラインを使用してローカルの谷/峰を確認し、MACDヒストグラムとシグナルラインは可視化に使用できます。
  • ロングのストキャスティクス%K読み値が20未満、ショートの80超でエントリーを確認します。
  • MetaTraderのpip処理を適応:銘柄の価格ステップからpipサイズを導出し、シンボルが3または5桁の場合は10を掛けます。

取引ロジック

ロングエントリー

  1. 現在と過去2本の完成したローソク足のMACDメインライン値がすべてゼロ未満。
  2. 現在のMACD値が前の値より大きく、前の値が2バー前の値より小さい(ローカルの谷)。
  3. ストキャスティクス%Kが20未満(売られすぎ)。
  4. 既存のロングポジションが開いていない(Position <= 0)。新しいロングに入る前にショートポジションがあれば手仕舞い。

ショートエントリー

  1. 現在と過去2本の完成したローソク足のMACDメインライン値がすべてゼロ超。
  2. 現在のMACD値が前の値より小さく、前の値が2バー前の値より大きい(ローカルの峰)。
  3. ストキャスティクス%Kが80超(買われすぎ)。
  4. 既存のショートポジションが開いていない(Position >= 0)。新しいショートに入る前にロングポジションがあれば決済。

リスク管理と出口

  • ハードストップ / テイクプロフィット: 各方向に独立したpipベースのストップロスとテイクプロフィット距離があります。Pipは計算されたpipサイズを使用して絶対価格オフセットに変換されます。
  • トレーリングストップ: 有効な場合、価格がトレーリング距離を超えて進んだ後にトレーリングストップが起動します。過剰な注文の入れ替えを避けるため、動きが設定されたトレーリングステップを超えた場合のみストップが上昇/下降します。
  • 逆シグナル: 逆シグナルに入る際は、まず既存ポジションを手仕舞いし、その後設定された取引量で新しいポジションを開きます。

パラメーター

パラメーター デフォルト 説明
TradeVolume 1 新規取引ごとに送られる注文量。
StopLossBuyPips 50 ロングストップロスのpip距離。0で無効化。
StopLossSellPips 50 ショートストップロスのpip距離。0で無効化。
TakeProfitBuyPips 50 ロングテイクプロフィットのpip距離。0で無効化。
TakeProfitSellPips 50 ショートテイクプロフィットのpip距離。0で無効化。
TrailingStopPips 0 トレーリングストップ距離(pip)。0でトレーリング無効。
TrailingStepPips 5 トレーリングストップ更新前の最小pip獲得量。トレーリング有効時は正数必須。
MacdFastPeriod 12 MACDの高速EMA長。
MacdSlowPeriod 26 MACDの低速EMA長。
MacdSignalPeriod 9 MACDのシグナル平滑化長。
StochasticKPeriod 5 ストキャスティクス%Kのルックバック期間。
StochasticDPeriod 3 ストキャスティクス%Dの平滑化期間。
StochasticSlowing 3 ストキャスティクス%Kに適用される追加平滑化。
CandleType 1h時間軸 インジケーター計算に使用するローソク足タイプ(時間軸)。

注意事項

  • pip計算は元のMetaTraderエキスパートを反映:pip = PriceStepで、3または5桁で表示される銘柄の場合は10を掛けます。
  • ストキャスティクスのしきい値(20/80)は元のスクリプトと同様に定数のままです。カスタムレベルが必要な場合はコード内で直接調整してください。
  • 戦略は完全に完成したローソク足のみで動作し、MetaTraderのバークローズ実行との一貫性を確保します。

使用方法

  1. 戦略を開始する前に希望の銘柄、CandleType、ボリュームを設定します。
  2. 銘柄のボラティリティに合わせてストップ、テイクプロフィット、トレーリングパラメーターを調整します。
  3. 公開されたパラメーターを使用してStockSharpのオプティマイザーでMACDとストキャスティクスの長さをオプションで最適化します。
  4. チャートエリアが利用可能な場合に自動的に追加されるチャートオブジェクト(ローソク足、MACD、ストキャスティクス、自己取引)を監視します。
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// MACD and stochastic based swing strategy.
/// Buys when MACD turns up in negative zone + stochastic is oversold.
/// Sells when MACD turns down in positive zone + stochastic is overbought.
/// </summary>
public class MacdStochastic2Strategy : Strategy
{
	private readonly StrategyParam<decimal> _oversoldThreshold;
	private readonly StrategyParam<decimal> _overboughtThreshold;
	private readonly StrategyParam<int> _macdFastPeriod;
	private readonly StrategyParam<int> _macdSlowPeriod;
	private readonly StrategyParam<int> _stochasticKPeriod;
	private readonly StrategyParam<int> _stochasticDPeriod;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _macdPrev1;
	private decimal _macdPrev2;
	private int _macdCount;

	public decimal OversoldThreshold { get => _oversoldThreshold.Value; set => _oversoldThreshold.Value = value; }
	public decimal OverboughtThreshold { get => _overboughtThreshold.Value; set => _overboughtThreshold.Value = value; }
	public int MacdFastPeriod { get => _macdFastPeriod.Value; set => _macdFastPeriod.Value = value; }
	public int MacdSlowPeriod { get => _macdSlowPeriod.Value; set => _macdSlowPeriod.Value = value; }
	public int StochasticKPeriod { get => _stochasticKPeriod.Value; set => _stochasticKPeriod.Value = value; }
	public int StochasticDPeriod { get => _stochasticDPeriod.Value; set => _stochasticDPeriod.Value = value; }
	public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
	public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MacdStochastic2Strategy()
	{
		_oversoldThreshold = Param(nameof(OversoldThreshold), 20m)
			.SetDisplay("Oversold", "Stochastic oversold threshold", "Stochastic");

		_overboughtThreshold = Param(nameof(OverboughtThreshold), 80m)
			.SetDisplay("Overbought", "Stochastic overbought threshold", "Stochastic");

		_macdFastPeriod = Param(nameof(MacdFastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("MACD Fast", "Fast EMA length for MACD", "MACD");

		_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("MACD Slow", "Slow EMA length for MACD", "MACD");

		_stochasticKPeriod = Param(nameof(StochasticKPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Stochastic K", "Lookback for %K", "Stochastic");

		_stochasticDPeriod = Param(nameof(StochasticDPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("Stochastic D", "Smoothing for %D", "Stochastic");

		_stopLoss = Param(nameof(StopLoss), 1000m)
			.SetGreaterThanZero()
			.SetDisplay("Stop Loss", "Stop loss in price units", "Risk");

		_takeProfit = Param(nameof(TakeProfit), 2000m)
			.SetGreaterThanZero()
			.SetDisplay("Take Profit", "Take profit in price units", "Risk");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle type for calculations", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_macdPrev1 = 0m;
		_macdPrev2 = 0m;
		_macdCount = 0;
	}

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

		var macd = new MovingAverageConvergenceDivergence(
			new ExponentialMovingAverage { Length = MacdSlowPeriod },
			new ExponentialMovingAverage { Length = MacdFastPeriod });

		var rsi = new RelativeStrengthIndex { Length = StochasticKPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, (candle, rsiValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				// Process MACD manually
				var macdResult = macd.Process(candle.ClosePrice, candle.CloseTime, true);
				if (!macd.IsFormed)
					return;

				var macdValue = macdResult.ToDecimal();

				_macdCount++;
				if (_macdCount < 3)
				{
					_macdPrev2 = _macdPrev1;
					_macdPrev1 = macdValue;
					return;
				}

				var macd0 = macdValue;
				var macd1 = _macdPrev1;
				var macd2 = _macdPrev2;

				// Buy: MACD in negative zone turning up + stochastic oversold
				var longSignal = macd0 < 0m && macd1 < 0m && macd2 < 0m &&
					macd0 > macd1 && macd1 < macd2 &&
					rsiValue < OversoldThreshold;

				// Sell: MACD in positive zone turning down + stochastic overbought
				var shortSignal = macd0 > 0m && macd1 > 0m && macd2 > 0m &&
					macd0 < macd1 && macd1 > macd2 &&
					rsiValue > OverboughtThreshold;

				if (longSignal && Position <= 0)
					BuyMarket();
				else if (shortSignal && Position >= 0)
					SellMarket();

				_macdPrev2 = _macdPrev1;
				_macdPrev1 = macdValue;
			})
			.Start();

		StartProtection(
			new Unit(TakeProfit, UnitTypes.Absolute),
			new Unit(StopLoss, UnitTypes.Absolute));

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