在 GitHub 上查看

RSI Dual Cloud 策略

概览

RSI Dual Cloud 策略 是 MetaTrader 专家顾问 “RSI Dual Cloud EA” 的 StockSharp 移植版本。 策略在可配置的 K 线序列上运行,同时分析快慢两条 RSI 线。当快线进入、停留或离开设定的超买/超卖区间, 或者快线与慢线发生交叉时产生交易信号。策略可以选择反转信号方向,也可以限制仅做多或仅做空。

策略只使用市价单。当出现新的反向信号时,先平掉已有反向头寸,再建立新的仓位。仓位大小由单一的交易量参数控制。

信号逻辑

  1. 进入信号:快 RSI 穿入阈值区间。
    • 做多:上一值高于下限,本次值低于下限。
    • 做空:上一值低于上限,本次值高于上限。
  2. 停留信号:快 RSI 持续位于阈值区间。
    • 做多:快 RSI 低于下限。
    • 做空:快 RSI 高于上限。
  3. 离开信号:快 RSI 离开阈值区间。
    • 做多:上一值低于下限,本次值高于下限。
    • 做空:上一值高于上限,本次值低于上限。
  4. 交叉信号:利用 RSI 双云结构。
    • 做多:快 RSI 向上穿越慢 RSI。
    • 做空:快 RSI 向下穿越慢 RSI。

可以任意组合启用上述条件,至少启用一个条件才会产生入场信号。启用 Reverse 后,多空信号互换。

参数

名称 说明
Candle Type 计算所使用的 K 线序列(默认 1 小时)。
Fast RSI / Slow RSI 快、慢 RSI 的周期。
Upper Level / Lower Level 超买、超卖阈值。
Order Volume 市价单的交易量。
Use Entrance / Being / Leaving / Crossing 各类信号的开关。
Closed Candles 启用后仅在收盘 K 线计算信号。
Reverse 反转多空方向。
Trade Mode 限制为仅多、仅空或双向。

使用提示

  • 策略订阅单一的 K 线序列,并通过高阶 API 绑定两条 RSI 指标。
  • 仅使用市价单;如果存在反向仓位,会先平仓再开新仓。
  • 默认参数与原版 EA 保持一致(快 RSI=5,慢 RSI=15,阈值 25/75)。
  • 可通过信号开关组合,重现原始 EA 的多种提示模式。
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();
	}
}