GitHub で見る

三つのインジケーター戦略

概要

この戦略は、元のMQL5エキスパート "Three indicators" をStockSharpに変換したものです。選択した時間軸の確定した各ローソク足で、3つのクラシックなオシレーター(MACD、ストキャスティクスオシレーター、RSI)を評価します。すべてのフィルターが一致した場合にのみ戦略がポジションに参入し、各トレードが一貫したマルチインジケーター確認に従うことを保証します。

トレードロジック

  1. ローソク足方向フィルター – 現在の確定ローソク足の始値と前のローソク足の始値を比較します。より高い始値はロングトレードに有利、より低い始値はショートに有利です。
  2. MACD傾きフィルター – MACD主線の傾き(現在のMACD主値と前のMACD主値の差)を観察します。下落するMACDはロングポジションに有利、上昇するMACDはショートに有利で、元のエキスパートとまったく同様です。
  3. ストキャスティクスバイアスフィルター – %D値が50の中点の下か上かを確認します。50未満の値はロングをサポート、50超の値はショートをサポートします。
  4. RSIバイアスフィルター – RSI値を50と比較して使用します。50未満の値はロングを許可、50超の値はショートを許可します。

4つのフィルターすべてが同じ方向をサポートした場合にのみ、戦略は新しいトレードを開きます。ポジションが開いている間に反対のシグナルが現れた場合、戦略は既存のエクスポージャーを閉じ新しい方向を開く単一の市場注文を送ることで即座に転換し、元のMQLロジックの動作を反映します。

パラメーター

パラメーター 説明
CandleType 戦略に供給されるローソク足の時間軸。デフォルト:1分。
TradeVolume ポジションを開くか反対側に転換するときに使用するボリューム。
MacdFastPeriod MACD計算内の高速EMAの長さ。
MacdSlowPeriod MACD計算内の低速EMAの長さ。
MacdSignalPeriod MACDシグナルラインのEMA長。
MacdPriceType MACDインジケーターに供給される適用価格(Close、Open、High、Low、Median、Typical、Weighted)。
StochasticKPeriod %Kラインのルックバック期間。
StochasticDPeriod %Dラインの平滑化期間。
StochasticSlowing %D計算前に%Kに適用される追加平滑化。
RsiPeriod RSIフィルターが使用する平均化期間。
RsiPriceType RSIインジケーターに供給するときに使用される適用価格。

インジケーター

  • MACD(移動平均収束発散) – ユーザーが指定した高速、低速、シグナルの長さで設定されます。
  • ストキャスティクスオシレーター – 設定可能な%K/%D長と平滑化でStockSharpの実装を使用します。
  • 相対力指数(RSI) – 最終的なモメンタム確認を提供します。

動作上の注意

  • 戦略は確定したローソク足のみを処理し、元のエキスパートのティックベースのトリガーと比較して安定性を向上させます。
  • MQLバージョンにある30秒の一時停止が削除されます;転換は組み合わせた市場注文で即座に発行されます。
  • ストキャスティクスの平滑化はStockSharpのデフォルト移動平均実装を使用し、元のスクリプトの標準SMAベースの平滑化に対応します。
  • MACDとRSIの価格ソース選択は IndicatorAppliedPrice enumを通じて提供され、MetaTraderで利用可能なオプション(Close、Open、High、Low、Median、Typical、Weighted)と一致します。

リスク管理

ストップロスまたはテイクプロフィット注文は自動的に配置されません。ポジション管理はマルチインジケーター転換ロジックのみによって駆動されます。必要に応じて外部のリスクコントロールを追加してください。

使用上のヒント

  1. CandleType で目的の銘柄と時間軸を選択します。
  2. 市場のボラティリティとシグナル頻度に合わせてインジケーターパラメーターを調整します。
  3. 戦略によって追加されたチャートオブジェクト(ローソク足と3つのインジケーター)を監視して、シグナルの整合性を検証します。
  4. 固定ストップや利益目標が必要な場合は、外部の資金管理と組み合わせます。
namespace StockSharp.Samples.Strategies;

using System;

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

/// <summary>
/// Combines MACD, Stochastic Oscillator, and RSI filters.
/// All three indicators must agree on direction to enter a trade.
/// </summary>
public class ThreeIndicatorsStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _macdFastPeriod;
	private readonly StrategyParam<int> _macdSlowPeriod;
	private readonly StrategyParam<int> _macdSignalPeriod;
	private readonly StrategyParam<int> _stochasticKPeriod;
	private readonly StrategyParam<int> _stochasticDPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _signalCooldownBars;

	private decimal? _previousOpen;
	private decimal? _previousMacdMain;
	private int _previousCompositeSignal;
	private int _cooldownRemaining;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int MacdFastPeriod { get => _macdFastPeriod.Value; set => _macdFastPeriod.Value = value; }
	public int MacdSlowPeriod { get => _macdSlowPeriod.Value; set => _macdSlowPeriod.Value = value; }
	public int MacdSignalPeriod { get => _macdSignalPeriod.Value; set => _macdSignalPeriod.Value = value; }
	public int StochasticKPeriod { get => _stochasticKPeriod.Value; set => _stochasticKPeriod.Value = value; }
	public int StochasticDPeriod { get => _stochasticDPeriod.Value; set => _stochasticDPeriod.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int SignalCooldownBars { get => _signalCooldownBars.Value; set => _signalCooldownBars.Value = value; }

	public ThreeIndicatorsStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle type", "Primary timeframe", "General");

		_macdFastPeriod = Param(nameof(MacdFastPeriod), 11)
			.SetDisplay("MACD fast", "Fast EMA length", "MACD");

		_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 53)
			.SetDisplay("MACD slow", "Slow EMA length", "MACD");

		_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 26)
			.SetDisplay("MACD signal", "Signal smoothing", "MACD");

		_stochasticKPeriod = Param(nameof(StochasticKPeriod), 40)
			.SetDisplay("Stochastic %K", "%K length", "Stochastic");

		_stochasticDPeriod = Param(nameof(StochasticDPeriod), 23)
			.SetDisplay("Stochastic %D", "%D smoothing", "Stochastic");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetDisplay("RSI period", "RSI length", "RSI");

		_signalCooldownBars = Param(nameof(SignalCooldownBars), 2)
			.SetNotNegative()
			.SetDisplay("Signal Cooldown Bars", "Closed candles to wait before a new entry", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_previousOpen = null;
		_previousMacdMain = null;
		_previousCompositeSignal = 0;
		_cooldownRemaining = 0;
	}

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

		_previousOpen = null;
		_previousMacdMain = null;
		_previousCompositeSignal = 0;
		_cooldownRemaining = 0;

		var macd = new MovingAverageConvergenceDivergenceSignal();
		macd.Macd.ShortMa.Length = MacdFastPeriod;
		macd.Macd.LongMa.Length = MacdSlowPeriod;
		macd.SignalMa.Length = MacdSignalPeriod;

		var stochastic = new StochasticOscillator();
		stochastic.K.Length = StochasticKPeriod;
		stochastic.D.Length = StochasticDPeriod;

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		var subscription = SubscribeCandles(CandleType);

		subscription
			.BindEx(macd, stochastic, rsi, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue stochValue, IIndicatorValue rsiValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!macdValue.IsFinal || !stochValue.IsFinal || !rsiValue.IsFinal)
			return;

		if (_cooldownRemaining > 0)
			_cooldownRemaining--;

		if (!macdValue.IsFormed || !stochValue.IsFormed || !rsiValue.IsFormed)
			return;

		var macdVal = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
		var macdMain = macdVal.Macd ?? 0m;

		var stoch = (StochasticOscillatorValue)stochValue;
		var stochasticD = stoch.D ?? 50m;

		var rsi = rsiValue.GetValue<decimal>();

		if (_previousOpen == null || _previousMacdMain == null)
		{
			_previousOpen = candle.OpenPrice;
			_previousMacdMain = macdMain;
			return;
		}

		// Candle direction
		var candleSignal = candle.OpenPrice > _previousOpen.Value ? 1 : candle.OpenPrice < _previousOpen.Value ? -1 : 0;

		// MACD direction (difference decreasing = bullish momentum)
		var macdDelta = macdMain - _previousMacdMain.Value;
		var macdSignal = macdDelta < 0m ? 1 : macdDelta > 0m ? -1 : 0;

		// Stochastic direction
		var stochSignal = stochasticD < 50m ? 1 : stochasticD > 50m ? -1 : 0;

		// RSI direction
		var rsiSignal = rsi < 50m ? 1 : rsi > 50m ? -1 : 0;

		var longSignal = candleSignal >= 0 && macdSignal >= 0 && stochSignal >= 0 && rsiSignal >= 0;
		var shortSignal = candleSignal <= 0 && macdSignal <= 0 && stochSignal <= 0 && rsiSignal <= 0;

		var compositeSignal = longSignal ? 1 : shortSignal ? -1 : 0;

		if (_cooldownRemaining == 0 && compositeSignal != 0 && compositeSignal != _previousCompositeSignal)
		{
			if (compositeSignal > 0 && Position <= 0)
			{
				BuyMarket(Volume + (Position < 0 ? -Position : 0m));
				_cooldownRemaining = SignalCooldownBars;
			}
			else if (compositeSignal < 0 && Position >= 0)
			{
				SellMarket(Volume + (Position > 0 ? Position : 0m));
				_cooldownRemaining = SignalCooldownBars;
			}
		}

		_previousOpen = candle.OpenPrice;
		_previousMacdMain = macdMain;
		_previousCompositeSignal = compositeSignal;
	}
}