GitHub で見る

RSI デュアル クラウド戦略

概要

RSI デュアル クラウド戦略 は、MetaTrader エキスパート アドバイザー「RSI デュアル クラウド EA」の StockSharp 移植です。 設定可能なローソク足シリーズで取引し、2 つの相対強度指数 (RSI) の計算を高速に分析します。 そして遅い回線。シグナルは、高速の RSI が定義された売られすぎ/買われすぎに入る、その範囲内にとどまる、またはそこから出るときに生成されます。 ゾーン、または高速ラインが低速ラインを横切るとき。戦略はオプションで信号を反転したり、制限したりできます。 ロングのみまたはショートのみの操作に切り替えます。

この戦略は成行注文のみで機能します。新しい信号を受信すると、反対側の既存の位置が表示されます。 新しいポジションを開く前に方向が閉じられます。ポジションのサイジングは単一のボリュームパラメータを通じて制御されます。

信号ロジック

  1. 入場信号 – 高速の RSI がゾーンに入るときにトリガーされます。
    • Long: 以前の RSI は下位レベルより上、現在の RSI はその下位です。
    • 短い: 以前の RSI は上位レベルの下にあり、現在の RSI はその上にあります。
  2. シグナル中 – 高速の RSI がゾーン内に留まる限りトリガーされます。
    • ロング: 下のレベルより速く RSI します。
    • 短い: 上のレベルを高速で RSI 上回ります。
  3. 離脱信号 – 高速の RSI がゾーンから離脱するとトリガーされます。
    • Long: 以前の RSI は下位レベルの下にあり、現在の RSI はその上にあります。
    • 短い: 以前の RSI は上位レベルの上にあり、現在の RSI はその下にあります。
  4. 交差点信号 – デュアルクラウド動作を使用します。
    • ロング: 高速の RSI が低速の RSI の上を通過します。
    • 短い: 速い RSI が遅い RSI の下を通過します。

4 つの条件を任意に組み合わせて有効にすることができます。エントリが発生するには、少なくとも 1 つの条件がアクティブである必要があります。 リバース オプションを有効にすると、長い信号と短い信号が交換されます。

パラメーター

名前 説明
キャンドルタイプ 計算に使用されるローソク足の系列 (デフォルト: 1 時間)。
速い RSI / 遅い RSI RSI の高速計算と低速計算の期間。
上位レベル/下位レベル RSI の買われすぎゾーンと売られすぎゾーンのしきい値。
注文量 成行注文のボリューム。
入口/存在/出発/交差点を使用する 信号ファミリーごとに切り替えます。
閉じたキャンドル 有効にすると、シグナルは完成したローソク足でのみ評価されます。
リバース 長い信号と短い信号を交換します。
トレードモード 取引をロング、ショート、または両方向に制限します。

使用上の注意

  • この戦略は 1 つのローソク足シリーズをサブスクライブし、高レベルの API を通じてバインドされた 2 つの RSI インジケーターを実行します。
  • 成行注文のみが使用されます。反対方向のオープンエクスポージャーは、新しい取引が行われる前にクローズされます。
  • デフォルトの構成は、元の Expert Advisor と一致します (高速 RSI 5、低速 RSI 15、レベル 25/75)。
  • シグナルトグルを組み合わせて、MetaTrader バージョンのインジケーターの組み合わせを再現します。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Uses fast and slow RSI crossovers to detect entry signals.
/// Simplified from the "RSI Dual Cloud EA" MetaTrader strategy.
/// </summary>
public class RsiDualCloudStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;

	private RelativeStrengthIndex _fastRsi;
	private RelativeStrengthIndex _slowRsi;
	private decimal? _prevFast;
	private decimal? _prevSlow;

	/// <summary>
	/// Candle type used for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Fast RSI period.
	/// </summary>
	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	/// <summary>
	/// Slow RSI period.
	/// </summary>
	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

	public RsiDualCloudStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for RSI calculations", "General");

		_fastLength = Param(nameof(FastLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("Fast RSI", "Fast RSI period", "Indicators");

		_slowLength = Param(nameof(SlowLength), 42)
			.SetGreaterThanZero()
			.SetDisplay("Slow RSI", "Slow RSI period", "Indicators");
	}

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

		_prevFast = null;
		_prevSlow = null;

		_fastRsi = new RelativeStrengthIndex { Length = FastLength };
		_slowRsi = new RelativeStrengthIndex { Length = SlowLength };

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

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

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

		if (!_fastRsi.IsFormed || !_slowRsi.IsFormed)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		if (_prevFast is null || _prevSlow is null)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		var crossUp = _prevFast < _prevSlow && fastValue > slowValue;
		var crossDown = _prevFast > _prevSlow && fastValue < slowValue;

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

		var minSpread = 5m;

		if (crossUp && Math.Abs(fastValue - slowValue) >= minSpread)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (crossDown && Math.Abs(fastValue - slowValue) >= minSpread)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_fastRsi = null;
		_slowRsi = null;
		_prevFast = null;
		_prevSlow = null;

		base.OnReseted();
	}
}