在 GitHub 上查看

MTF RSI SAR 策略

该策略结合四个周期的 RSIParabolic SAR布林带,用于在短期回调后捕捉趋势延续。信号基于 5 分钟K线,更高周期仅用于过滤和确认。

概念

  1. RSI 过滤 – 5、15、30、60 分钟 RSI 全部高于 50 时做多,全部低于 50 时做空,以保证交易方向与更大级别趋势一致。
  2. Parabolic SAR 过滤 – 5、15、30 分钟 SAR 点位在当前K线下方做多,在上方做空,确认价格运行方向。
  3. 布林带触发 – 5 分钟K线收盘价突破上轨触发做多,跌破下轨触发做空,提供超买/超卖信号。
  4. 入场与出场 – 当所有启用的过滤器同向时开仓,反向信号出现时平仓。

三个过滤器均可通过参数单独关闭,可实现仅用 RSI、仅用布林带或仅用 SAR 的模式。

参数

  • UseRsi – 启用 RSI 过滤(默认:true)
  • UseBollinger – 启用布林带触发(默认:true)
  • UseSar – 启用 Parabolic SAR 过滤(默认:true)
  • RsiPeriod – RSI 计算周期(默认:14)
  • BollingerPeriod – 布林带周期(默认:20)
  • BollingerWidth – 布林带宽度(标准差倍数,默认:2)
  • SarStep – Parabolic SAR 加速因子(默认:0.02)
  • SarMax – Parabolic SAR 最大加速(默认:0.2)
  • CandleType – 基础K线周期,默认 5 分钟

交易规则

  • 多头:所有启用过滤器给出看涨信号。
  • 空头:所有启用过滤器给出看跌信号。
  • 退出:出现反向信号时平仓。

说明

  • 策略对单一品种同时订阅 5、15、30、60 分钟四个周期。
  • 用于展示如何利用 StockSharp 高级 API 实现多周期确认。
  • 策略未设置固定止损和止盈,如需风险控制请另行添加。
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>
/// RSI and Parabolic SAR strategy.
/// Buys when RSI below oversold and SAR below price; sells on opposite.
/// </summary>
public class MtfRsiSarStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiOversold;
	private readonly StrategyParam<decimal> _rsiOverbought;
	private readonly StrategyParam<DataType> _candleType;

	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public decimal RsiOversold { get => _rsiOversold.Value; set => _rsiOversold.Value = value; }
	public decimal RsiOverbought { get => _rsiOverbought.Value; set => _rsiOverbought.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

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

		_rsiOversold = Param(nameof(RsiOversold), 35m)
			.SetDisplay("RSI Oversold", "RSI oversold level", "Indicators");

		_rsiOverbought = Param(nameof(RsiOverbought), 65m)
			.SetDisplay("RSI Overbought", "RSI overbought level", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

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

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var sar = new ParabolicSar();

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

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

		var close = candle.ClosePrice;

		// Buy: RSI oversold + SAR below price
		if (rsi < RsiOversold && sar < close)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		// Sell: RSI overbought + SAR above price
		else if (rsi > RsiOverbought && sar > close)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
		// Exit long when RSI overbought
		else if (Position > 0 && rsi > RsiOverbought)
		{
			SellMarket();
		}
		// Exit short when RSI oversold
		else if (Position < 0 && rsi < RsiOversold)
		{
			BuyMarket();
		}
	}
}