RSI 趋势交易策略
摘要
该策略移植自 MetaTrader 的“RSI trader”专家顾问,通过价格移动均线与 RSI 平滑均线的双重趋势过滤来寻找方向一致的行情。当两个过滤器给出相反信号时视为盘整,并平掉现有仓位。默认使用与原策略相同的 1 小时 K 线,也可选择其他任意烛图数据。
工作流程
- 按 RSI Period(默认 14)计算 RSI。
- 使用两个简单移动平均线对 RSI 值进行平滑,分别对应 Short RSI MA 与 Long RSI MA。
- 对收盘价分别应用简单移动平均(Short Price MA)和线性加权平均(Long Price MA)。
- 仅在 K 线收盘后生成交易信号:
- 做多:价格短均线和 RSI 短均线同时位于各自长均线上方。
- 做空:价格短均线和 RSI 短均线同时位于各自长均线下方。
- 盘整:两个模块的方向相互矛盾,此时若存在持仓则立即市价平仓。
- 通过
BuyMarket/SellMarket下单。在建立新方向之前,策略会先平掉相反头寸。
参数
| 名称 | 说明 | 默认值 | 可优化范围 |
|---|---|---|---|
RSI Period |
RSI 的计算周期。 | 14 | 是(7~28,步长 1) |
Short Price MA |
价格短期简单移动平均长度。 | 9 | 是(5~20,步长 1) |
Long Price MA |
价格长期线性加权平均长度。 | 45 | 是(30~90,步长 5) |
Short RSI MA |
RSI 短期平滑均线长度。 | 9 | 是(5~20,步长 1) |
Long RSI MA |
RSI 长期平滑均线长度。 | 45 | 是(30~90,步长 5) |
Candle Type |
使用的烛图数据类型,默认为 1 小时。 | H1 | 否 |
备注
- 仅在所有指标准备就绪时才会发出交易指令。
- 原始 EA 使用手数与滑点参数;在 StockSharp 中,订单数量来自策略的
Volume属性,滑点由交易适配器处理。 - 策略本身不设置固定止损/止盈,离场完全依赖盘整检测,可结合外部风险控制。
- 如果连接了图表服务,界面会绘制价格及 RSI 的均线以便观察信号。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// RSI Trader strategy combining price SMA crossover with RSI trend confirmation.
/// Buy when short SMA crosses above long SMA with RSI above 50.
/// Sell when short SMA crosses below long SMA with RSI below 50.
/// </summary>
public class RsiTraderAlignedAveragesStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _shortMaPeriod;
private readonly StrategyParam<int> _longMaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevShort;
private decimal _prevLong;
private bool _hasPrev;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int ShortMaPeriod { get => _shortMaPeriod.Value; set => _shortMaPeriod.Value = value; }
public int LongMaPeriod { get => _longMaPeriod.Value; set => _longMaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public RsiTraderAlignedAveragesStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "RSI calculation period", "Indicators");
_shortMaPeriod = Param(nameof(ShortMaPeriod), 9)
.SetDisplay("Short MA", "Short moving average period", "Indicators");
_longMaPeriod = Param(nameof(LongMaPeriod), 26)
.SetDisplay("Long MA", "Long moving average period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevShort = 0m;
_prevLong = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var shortMa = new SimpleMovingAverage { Length = ShortMaPeriod };
var longMa = new SimpleMovingAverage { Length = LongMaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, shortMa, longMa, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal shortMa, decimal longMa)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevShort = shortMa;
_prevLong = longMa;
_hasPrev = true;
return;
}
var bullCross = _prevShort <= _prevLong && shortMa > longMa;
var bearCross = _prevShort >= _prevLong && shortMa < longMa;
if (Position <= 0 && bullCross && rsiValue > 50)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (Position >= 0 && bearCross && rsiValue < 50)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevShort = shortMa;
_prevLong = longMa;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class rsi_trader_aligned_averages_strategy(Strategy):
"""RSI Trader combining SMA crossover with RSI trend confirmation.
Buy when short SMA crosses above long SMA with RSI above 50.
Sell when short SMA crosses below long SMA with RSI below 50."""
def __init__(self):
super(rsi_trader_aligned_averages_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation period", "Indicators")
self._short_ma_period = self.Param("ShortMaPeriod", 9) \
.SetDisplay("Short MA", "Short moving average period", "Indicators")
self._long_ma_period = self.Param("LongMaPeriod", 26) \
.SetDisplay("Long MA", "Long moving average period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_short = 0.0
self._prev_long = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def ShortMaPeriod(self):
return self._short_ma_period.Value
@property
def LongMaPeriod(self):
return self._long_ma_period.Value
def OnReseted(self):
super(rsi_trader_aligned_averages_strategy, self).OnReseted()
self._prev_short = 0.0
self._prev_long = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(rsi_trader_aligned_averages_strategy, self).OnStarted2(time)
self._has_prev = False
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
short_ma = SimpleMovingAverage()
short_ma.Length = self.ShortMaPeriod
long_ma = SimpleMovingAverage()
long_ma.Length = self.LongMaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, short_ma, long_ma, self._process_candle).Start()
def _process_candle(self, candle, rsi_value, short_ma, long_ma):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
short_val = float(short_ma)
long_val = float(long_ma)
if not self._has_prev:
self._prev_short = short_val
self._prev_long = long_val
self._has_prev = True
return
bull_cross = self._prev_short <= self._prev_long and short_val > long_val
bear_cross = self._prev_short >= self._prev_long and short_val < long_val
if self.Position <= 0 and bull_cross and rsi_val > 50:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self.Position >= 0 and bear_cross and rsi_val < 50:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_short = short_val
self._prev_long = long_val
def CreateClone(self):
return rsi_trader_aligned_averages_strategy()