在 GitHub 上查看

RSI水平策略

概述

RSI水平策略 是 MetaTrader 5 "RSI Levels" 智能交易顾问的直接移植版本。策略在指定周期上监控单一品种,当相对强弱指数(RSI)穿越可配置的超买和超卖阈值时采取行动。系统假设当RSI进入极值区域后价格会回归均值:当指标跌破超卖水平时开多,当指标升破超买水平时开空。任意时刻只允许持有一个方向的仓位,新的信号会先平掉相反持仓再入场。

交易逻辑

  1. RSI计算 – 使用可配置周期在工作时间框上计算RSI,只在K线收盘后评估信号。
  2. 做多条件 – 当前RSI收在超卖线以下、上一笔RSI在超卖线上方时触发。如果存在空单则立即平仓,否则按风险模型开多。
  3. 做空条件 – 当前RSI收在超买线上方、上一笔RSI在超买线下方时触发。如持有多单则先平仓,再按风险模型开空。
  4. 止损 – 按配置的点数距离在入场价附近设置固定止损;当该参数为零时表示禁用止损。
  5. 止盈 – 按配置的点数距离在入场价附近设置固定止盈;为零时表示禁用止盈。
  6. 仓位管理 – 任何仓位平仓后都会重置内部状态,确保下一次信号在干净环境下执行。

仓位管理

仓位大小由“单笔风险百分比”参数决定。算法取组合权益乘以风险百分比得到风险资金,再除以止损距离的货币价值(止损点数 × 最小价格变动价值)。结果向下取整到可交易的手数步长,并受到品种最小/最大手数限制。如果缺少 PriceStepStepPrice 等关键信息,策略会记录警告并退回到最小手数。

参数

参数 默认值 说明
CandleType 1小时周期 用于订阅K线并计算RSI的时间框。
RsiPeriod 14 RSI指标的周期长度。
OverboughtLevel 70 定义超买区域的RSI阈值。
OversoldLevel 30 定义超卖区域的RSI阈值。
RiskPercent 2 每笔交易风险占权益的百分比。
StopLossPoints 500 以点数表示的止损距离,设为0可禁用。
TakeProfitPoints 1000 以点数表示的止盈距离,设为0可禁用。

实践提示

  • 请确保品种已经配置 PriceStepStepPriceMinVolumeVolumeStep,否则风险头寸计算会退回到保守的最小手数。
  • 策略通过 SubscribeCandlesBind 获取指标数值,无需手动访问历史数据,符合高阶API规范。
  • 止损与止盈基于收盘K线判断,跳空或滑点可能导致实际成交价偏离设定价。
  • 建议在M15、H1或H4等较稳定周期上运行。如使用更低周期,需额外过滤噪声。

使用方法

  1. 将策略附加到目标证券和组合。
  2. 根据品种波动性调整RSI阈值及风险参数。
  3. 启动策略,并关注日志中关于缺失品种信息的警告。
  4. 根据回测或实盘结果微调止损、止盈或阈值设置。

该StockSharp实现完整复现了原始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>
/// RSI Levels strategy: RSI oversold/overbought mean reversion.
/// Buys when RSI < 35. Sells when RSI > 65.
/// </summary>
public class RsiLevelsStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;

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

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public RsiLevelsStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (rsi < 30m && Position <= 0)
		{
			BuyMarket();
		}
		else if (rsi > 70m && Position >= 0)
		{
			SellMarket();
		}
	}
}