GitHub で見る

RSI デュアル戦略の RSI MA

概要

RSI デュアル戦略の RSI MA は、StockSharp 内に MetaTrader エキスパート アドバイザー「RSI_MAonRSI_Dual」を再作成します。ルックバック期間が異なる 2 つの相対強度インデックスを監視し、各 RSI ストリームに共通の移動平均を適用します。平滑化された RSI ラインが構成可能な中立レベルの同じ側に留まりながら互いに交差するときに、取引の決定が下されます。

変換では、時間フィルタリングや取引方向を制限したり信号ロジックを反転したりする機能など、元のロボットの動作が維持されます。

インジケーター

  • Fast RSI – 設定可能な期間を持つ相対強度インデックス。
  • Slow RSI – 独自の周期を持つ相対強度指数。
  • RSI の移動平均 – 各 RSI 値ストリームに基づいて計算された単純移動平均。どちらの RSI も同じスムージング長を使用します。

3 つのインジケーターはすべて同じ適用価格 (デフォルトでは終値) を共有します。 2 本の平滑化された RSI 線が、監視用の専用チャート パネルに描画されます。

エントリールール

  1. 両方の平滑化された RSI 値が現在の完成バーに形成されるまで待ちます。
  2. 長いセットアップ
    • 高速平滑化された RSI は、低速平滑化された RSI の と交差しています (上が現在の値、下が前の値)。
    • 平滑化された RSI は両方ともニュートラル レベル (デフォルトでは 50) を にしています。
  3. 簡単なセットアップ
    • 高速平滑化された RSI は、低速平滑化された RSI をで交差します (現在値が下、前回の値が上)。
    • 平滑化された RSI は両方ともニュートラル レベルを にあります。
  4. 必要に応じて、ReverseSignals パラメータを使用して信号の方向を反転します。
  5. 同じバーで生成された信号は無視されます (バーごとに 1 つのエントリ)。

ポジション管理

  • AllowLongAllowShort は、戦略が各方向にポジションをオープンできるかどうかを制御します。
  • CloseOpposite は、反対側に入る前に既存のポジションを決済し、元の EA ロジックを複製します。
  • OnlyOnePosition は、ポジションがすでにアクティブな場合に新しいポジションを開くことを禁止します。
  • 成行注文は戦略 Volume で発行されます。

時間フィルター

UseTimeFilter を使用して取引セッション フィルターを有効または無効にします。有効にすると、SessionStartSessionEnd の間でのみ取引が許可されます。真夜中を超えるセッションはサポートされています。タイムスタンプは、受信キャンドル メッセージによって提供される交換タイム ゾーンで評価されます。

パラメーター

名前 説明
CandleType 戦略別に分析したキャンドルシリーズ。
FastRsiPeriod 高速の RSI の期間。
SlowRsiPeriod 遅い RSI の期間。
MaPeriod 両方の RSI ストリームを平滑化するために使用される移動平均の長さ。
AppliedPrice RSI の計算に転送される価格タイプ。
NeutralLevel RSI は強気ゾーンと弱気ゾーンを分けるしきい値です。
AllowLong / AllowShort 取引方向を有効または無効にします。
ReverseSignals 長い信号と短い信号を交換します。
CloseOpposite 新しいポジションに入る前に、反対のポジションを閉じます。
OnlyOnePosition オープンポジションは最大 1 つまで許可します。
UseTimeFilter 取引セッションフィルターを有効にします。
SessionStart / SessionEnd 取引ウィンドウの境界。

オリジナルの EA との違い

  • 元の MQL5 コードの資金管理、ストップロス、トレーリングストップのブロックは再現されません。 StockSharp 戦略は、戦略に設定された固定の Volume を使用して成行注文を出します。
  • すべてのログ記録と診断アラートが削除されました。必要に応じて、代わりに StockSharp ログを使用する必要があります。
  • プラットフォーム固有のトランザクション追跡は、StockSharp 注文状態イベントに置き換えられます。

これらの違いにもかかわらず、コアのエントリ ロジックと方向フィルターはソースの Expert Advisor と一致します。

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>
/// Dual moving averages calculated on top of RSI values.
/// Fast RSI MA crossing slow RSI MA generates entry signals.
/// </summary>
public class RsiMaOnRsiDualStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastRsiPeriod;
	private readonly StrategyParam<int> _slowRsiPeriod;
	private readonly StrategyParam<int> _maPeriod;

	private RelativeStrengthIndex _fastRsi;
	private RelativeStrengthIndex _slowRsi;
	private readonly Queue<decimal> _fastRsiHistory = new();
	private readonly Queue<decimal> _slowRsiHistory = new();

	private decimal? _previousFastMa;
	private decimal? _previousSlowMa;

	public RsiMaOnRsiDualStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle type", "Candles processed by the strategy.", "General");

		_fastRsiPeriod = Param(nameof(FastRsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("Fast RSI period", "Length of the fast RSI smoothing window.", "Indicators");

		_slowRsiPeriod = Param(nameof(SlowRsiPeriod), 28)
			.SetGreaterThanZero()
			.SetDisplay("Slow RSI period", "Length of the slow RSI smoothing window.", "Indicators");

		_maPeriod = Param(nameof(MaPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("MA period", "Number of RSI values averaged by the smoothing moving average.", "Indicators");
	}

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

	public int FastRsiPeriod
	{
		get => _fastRsiPeriod.Value;
		set => _fastRsiPeriod.Value = value;
	}

	public int SlowRsiPeriod
	{
		get => _slowRsiPeriod.Value;
		set => _slowRsiPeriod.Value = value;
	}

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_previousFastMa = null;
		_previousSlowMa = null;
		_fastRsiHistory.Clear();
		_slowRsiHistory.Clear();
		_fastRsi = null!;
		_slowRsi = null!;
	}

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

		_previousFastMa = null;
		_previousSlowMa = null;
		_fastRsiHistory.Clear();
		_slowRsiHistory.Clear();

		_fastRsi = new RelativeStrengthIndex { Length = FastRsiPeriod };
		_slowRsi = new RelativeStrengthIndex { Length = SlowRsiPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_fastRsi, _slowRsi, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fastRsiValue, decimal slowRsiValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		_fastRsiHistory.Enqueue(fastRsiValue);
		_slowRsiHistory.Enqueue(slowRsiValue);
		while (_fastRsiHistory.Count > MaPeriod)
			_fastRsiHistory.Dequeue();
		while (_slowRsiHistory.Count > MaPeriod)
			_slowRsiHistory.Dequeue();

		if (!_fastRsi.IsFormed || !_slowRsi.IsFormed)
			return;

		if (_fastRsiHistory.Count < MaPeriod || _slowRsiHistory.Count < MaPeriod)
			return;

		// Calculate SMA of each RSI
		var fastSum = 0m;
		var fastHistory = _fastRsiHistory.ToArray();
		foreach (var v in fastHistory)
			fastSum += v;
		var fastMa = fastSum / MaPeriod;

		var slowSum = 0m;
		var slowHistory = _slowRsiHistory.ToArray();
		foreach (var v in slowHistory)
			slowSum += v;
		var slowMa = slowSum / MaPeriod;

		if (_previousFastMa is null || _previousSlowMa is null)
		{
			_previousFastMa = fastMa;
			_previousSlowMa = slowMa;
			return;
		}

		var crossUp = _previousFastMa < _previousSlowMa && fastMa > slowMa;
		var crossDown = _previousFastMa > _previousSlowMa && fastMa < slowMa;

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		if (crossUp)
		{
			if (Position <= 0)
				BuyMarket(volume);
		}
		else if (crossDown)
		{
			if (Position >= 0)
				SellMarket(volume);
		}

		_previousFastMa = fastMa;
		_previousSlowMa = slowMa;
	}
}