在 GitHub 上查看

CBC_WS_RSI 策略

概述

CBC_WS_RSI 策略 是对原始 MQL5 专家顾问的 StockSharp 高级 API 版本。该策略将 "三白兵" 与 "三只乌鸦" 烛形组合与 RSI 指标结合,旨在识别强烈的多根 K 线反转,并在动量得到确认后才入场。策略只处理完全收盘的 K 线,所有逻辑均通过 SubscribeCandles().Bind(...) 高级接口完成,无需直接访问指标缓冲区。

交易逻辑

多头条件

  1. 识别 三白兵 形态:
    • 连续三根阳线并且每根 K 线收盘价高于开盘价;
    • 每根收盘价都高于上一根收盘价;
    • 第二、第三根 K 线的开盘价位于前一根 K 线实体内部。
  2. 当前 RSI 值 小于或等于多头确认阈值(默认 40)。
  3. 若当前为空仓,则按 Volume 市价买入;若存在空头仓位,则先回补再建立多头。

空头条件

  1. 识别 三只乌鸦 形态:
    • 连续三根阴线并且每根 K 线收盘价低于开盘价;
    • 每根收盘价都低于上一根收盘价;
    • 第二、第三根 K 线的开盘价位于前一根 K 线实体内部。
  2. 当前 RSI 值 大于或等于空头确认阈值(默认 60)。
  3. 若当前为空仓,则按 Volume 市价卖出;若存在多头仓位,则先平仓再建立空头。

平仓规则

  • 多头平仓: 当 RSI 自上而下跌破上轨(默认 70)或下轨(默认 30)时平掉全部多头。
  • 空头平仓: 当 RSI 自下而上突破下轨(默认 30)或上轨(默认 70)时回补全部空头。
  • 风控保护: 可选的止损和止盈参数以百分比表示,若大于 0,则通过 StartProtection 自动管理。

策略使用最近两个 RSI 数值来判断穿越行为,从而在动量发生反转时迅速退出当前仓位。

参数

名称 描述 默认值
CandleType 订阅的 K 线类型与周期。 1 小时
RsiPeriod RSI 计算周期。 37
LongConfirmationLevel 允许做多的最大 RSI 值。 40
ShortConfirmationLevel 允许做空的最小 RSI 值。 60
LowerExitLevel 用于判断超卖区反转的 RSI 下阈值。 30
UpperExitLevel 用于判断超买区反转的 RSI 上阈值。 70
StopLossPercent 百分比止损,0 表示禁用。 1
TakeProfitPercent 百分比止盈,0 表示禁用。 2

所有数值型参数都启用了 SetCanOptimize(true),可直接用于优化。

可视化

在有可用图表区域的情况下,策略会绘制:

  • 订阅的 K 线序列;
  • RSI 指标曲线;
  • 实际成交记录,方便回溯形态与出入场。

使用提示

  • 启动前请设置合适的 Volume
  • 适用于任何提供 OHLC K 线数据的交易品种;
  • 通过排除实体为零的 K 线,减少十字星等噪音信号;
  • RSI 确认有助于在动量不足时避免进入假信号。
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// CBC WS RSI strategy: 3 Black Crows / 3 White Soldiers with RSI confirmation.
/// Buys after 3 bullish candles with RSI below 60, sells after 3 bearish with RSI above 40.
/// </summary>
public class CbcWsRsiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private int _bullCount;
	private int _bearCount;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public CbcWsRsiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period for confirmation", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_bullCount = 0;
		_bearCount = 0;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_bullCount = 0;
		_bearCount = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (candle.ClosePrice > candle.OpenPrice)
		{
			_bullCount++;
			_bearCount = 0;
		}
		else if (candle.ClosePrice < candle.OpenPrice)
		{
			_bearCount++;
			_bullCount = 0;
		}
		else
		{
			_bullCount = 0;
			_bearCount = 0;
		}

		// Exit on RSI extremes
		if (Position > 0 && rsi > 75 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			SellMarket();
			_candlesSinceTrade = 0;
		}
		else if (Position < 0 && rsi < 25 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			BuyMarket();
			_candlesSinceTrade = 0;
		}

		// Entry on pattern
		if (_bullCount >= 3 && rsi < 60 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			BuyMarket();
			_bullCount = 0;
			_candlesSinceTrade = 0;
		}
		else if (_bearCount >= 3 && rsi > 40 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			SellMarket();
			_bearCount = 0;
			_candlesSinceTrade = 0;
		}
	}
}