GitHub で見る

スロープ RSI 機動部隊戦略

概要

スロープ RSI MTF 戦略 は、MetaTrader 4 エキスパート アドバイザー SLOPE_RSI_MTF_LBranjord.mq4 をそのコンパニオン インジケーター Slope_Direction_Line_Alert.mq4 とともに移植します。元の設定では、複数の時間枠にわたって複数のハル移動平均 (「傾斜方向ライン」という名前) を積み上げ、4 層の RSI フィルターで勢いを確認しながら、すべての移動平均が同じ方向を向いた場合にのみ取引を開始しました。 StockSharp バージョンは、高レベルのサブスクリプションを使用してこのマルチタイムフレームの確認ロジックを再現し、ATR ベースの終了ターゲットを維持し、戦略パラメーターによる広範な構成サポートを追加します。

取引ロジック

  1. 同じ商品に対して 4 つのローソク足シリーズ (取引時間枠 (BaseTimeframe)、1 時間ごとの確認シリーズ、4 時間足シリーズ、および日足シリーズ) を購読します。
  2. 各シリーズを独自の HullMovingAverage (勾配方向線の StockSharp 置換) および RelativeStrengthIndex インスタンスにフィードします。基本シリーズは SlopeTriggerLength (デフォルト 60) を使用し、確認シリーズは SlopeTrendLength (デフォルト 200) を使用します。
  3. タイムフレームごとに最後の 2 つのハル値を追跡します。現在のハル値が前のハル値を厳密に上回っている場合、タイムフレームは強気とみなされます。ハル値が前の値を厳密に下回っている場合、それは弱気です。
  4. すべての時間枠で RSI を同時に監視します。
    • 長いセットアップ: RSI は、4 つのシリーズすべてで RsiMiddleLevel (デフォルトでは 50) を超え、RsiUpperBound (90) 未満である必要があります。
    • 簡単な設定: RSI は、4 つのシリーズすべてで、RsiMiddleLevel よりも下、かつ RsiLowerBound (10) よりも大きい必要があります。
  5. 基本タイムフレームが終了し、すべての確認が強気になったら、ロングシグナルをトリガーします。すべての確認が弱気の場合は、ショートシグナルをトリガーします。すべてのインジケーターが少なくとも 1 つの履歴値を生成するまで、シグナルは無視されます。
  6. 新しい位置を追加する前に、ATR の値から保護距離を計算します。
    • 時間単位のシリーズはストップロス距離を提供します。
    • 日次シリーズはテイクプロフィット距離を提供します。
  7. マーケットエントリーは、MaxOrders を尊重しながらシグナル方向にエクスポージャを追加します。ネッティング環境では、新しい取引が追加される前に反対エクスポージャが平坦化されます。
  8. プロテクションレベルはスケールインごとに再計算され、その後の基本タイムフレームのローソク足で評価されます。ローソク足の高値/安値が保存されているストップロスまたはテイクプロフィットのレベルを横切る場合、戦略は成行注文でフルポジションを終了します。

リスク管理とポジションサイジング

  • UseCompounding は、MQL エキスパートからの複合ルールを有効にします: volume = PortfolioValue / BalanceDivider。無効にすると、代わりに BaseVolume が使用されます。
  • ヘルパー AdjustVolume は、要求されたボリュームを証券の VolumeStep に丸め、MinVolume/MaxVolume を適用します。調整された値は Strategy.Volume にも書き込まれるため、手動アクションも同じサイズに従います。
  • ATR 期間 (AtrPeriod、デフォルトは 21) は、ストップロスとテイクプロフィットの両方の計算の元の設定を反映しています。ストップでは時間単位の ATR が使用され、利益目標では日単位の ATR が使用されます。
  • 位置カウンター (_longEntries_shortEntries) は、一度にどの方向でも MaxOrders を超えるスケールインがアクティブにならないようにします。

マルチタイムフレームデータの処理

  • すべてのサブスクリプションは SubscribeCandles(...) で作成され、Bind を通じて処理されます。この戦略では、過去のローソク足を手動でキャッシュしません。インジケーターはストリーミング データに反応し、Bind コールバックを通じて最終値を公開します。
  • TimeframeState ヘルパーは、ハル値と RSI 値を以前のハル読み取り値と一緒に保存し、履歴インジケーター バッファーを要求せずに傾きの比較を可能にします。
  • ATR の値は、対応するインジケーターが IsFormed をレポートする場合にのみ取得され、ストップとターゲットが完全なバーから計算されることが保証されます。

パラメーター

名前 種類 デフォルト MetaTraderの相手方 説明
SlopeTriggerLength int 60 SDL1_trigger 取引時間枠における船体の長さ。
SlopeTrendLength int 200 SDL1_period 時間ごと、4 時間ごと、毎日の確認での船体長。
RsiPeriod int 14 RSI期間 RSI ルックバックはすべての時間枠に適用されます。
RsiLowerBound decimal 10 RSI 下限 短い信号用の下位 RSI フィルター。
RsiMiddleLevel decimal 50 RSI 中間レベル (暗黙的) 長期政権と短期政権を分ける中立的な RSI レベル。
RsiUpperBound decimal 90 RSI の上限 長い信号用の上部 RSI フィルター。
AtrPeriod int 21 ATR_Period ストップとテイクプロフィットの計算には ATR の長さ。
MaxOrders int 5 MaxOrders 方向ごとのスケールイン エントリの最大数。
UseCompounding bool true compounding ポートフォリオベースのポジションサイジングを可能にします。
BaseVolume decimal 0.1 Lots 配合が無効になっている場合の固定ロット。
BalanceDivider decimal 100000 暗黙的 (AccountBalance()/100000) 配合式の除算器。
BaseTimeframe DataType 5m チャートの時間枠 取引執行を促進するキャンドルシリーズ。
HourTimeframe DataType 1h PERIOD_H1 初めての確認シリーズ。
FourHourTimeframe DataType 4h PERIOD_H4 確認シリーズ第二弾。
DayTimeframe DataType 1d PERIOD_D1 最上級の確認シリーズ。

元のエキスパートアドバイザーとの違い

  • StockSharp はネッティング モードで動作するため、新しい取引が開始される前に反対のポジションがクローズされます。 MetaTrader 4 では、両方向で複数のチケットをヘッジできました。
  • プロテクティブストップとターゲットは、ブローカー側の注文変更ではなく、ローソクベースのモニタリングを通じて実行されます。これにより、元の EA の ATR 距離を再現しながら、ロジック内のロジックが維持されます。
  • インジケーター値は、StockSharp の組み込み HullMovingAverageRelativeStrengthIndex、および AverageTrueRange によって提供されます。カスタム インジケーター バッファーには直接アクセスせず、高レベルの API のベスト プラクティスに従っています。
  • パラメータのメタデータ、ローカリゼーションに適した名前、範囲のヒントが Param(...).SetDisplay(...) を通じて公開されるため、戦略の構成と最適化が容易になります。

使用上の注意

  • 確認時間枠は取引時間枠以上に厳密に設定してください。より短い期間を混合すると、矛盾するシグナルが生成される可能性があり、マルチタイムフレームの傾き確認の目的が無効になります。
  • セキュリティ メタデータ (PriceStepVolumeStepMinVolumeMaxVolume) が入力されていることを確認して、ストップ/ターゲットの丸めとボリューム調整が正しく動作するようにします。
  • ストップロスとテイクプロフィットの監視は完了したベースキャンドルごとに 1 回発生するため、バー内のエグジットは次のバーの終了時に発生します。より厳密なバー内管理が必要な場合は、取引時間枠を短縮するか、ティックレベルの監視を使用して戦略を拡張します。
  • 船体傾斜テストでは、連続する値が異なる必要があります。フラット ハル シーケンス (値が等しい) は、RSI フィルターが通過した場合でも新しい取引をブロックし、MetaTrader スクリプトの「SDL > SDL[1]」条件を反映します。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Slope RSI MTF: EMA crossover with RSI filter and ATR stops.
/// </summary>
public class SlopeRsiMtfStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastEmaLength;
	private readonly StrategyParam<int> _slowEmaLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;

	public SlopeRsiMtfStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_fastEmaLength = Param(nameof(FastEmaLength), 12)
			.SetDisplay("Fast EMA Length", "Fast EMA period.", "Indicators");
		_slowEmaLength = Param(nameof(SlowEmaLength), 26)
			.SetDisplay("Slow EMA Length", "Slow EMA period.", "Indicators");
		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");
		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastEmaLength { get => _fastEmaLength.Value; set => _fastEmaLength.Value = value; }
	public int SlowEmaLength { get => _slowEmaLength.Value; set => _slowEmaLength.Value = value; }
	public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

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

		_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
		var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fastEma, slowEma, rsi, atr, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fastEma); DrawIndicator(area, slowEma); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal rsiVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0) { _prevFast = fastVal; _prevSlow = slowVal; return; }
		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if ((fastVal < slowVal && _prevFast >= _prevSlow) || close <= _entryPrice - atrVal * 2m) { SellMarket(); _entryPrice = 0; }
		}
		else if (Position < 0)
		{
			if ((fastVal > slowVal && _prevFast <= _prevSlow) || close >= _entryPrice + atrVal * 2m) { BuyMarket(); _entryPrice = 0; }
		}

		if (Position == 0)
		{
			if (fastVal > slowVal && _prevFast <= _prevSlow && rsiVal > 50) { _entryPrice = close; BuyMarket(); }
			else if (fastVal < slowVal && _prevFast >= _prevSlow && rsiVal < 50) { _entryPrice = close; SellMarket(); }
		}
		_prevFast = fastVal; _prevSlow = slowVal;
	}
}