基于RSI自动交易策略
该策略对最近的RSI值进行平均以生成交易信号。它首先按照可配置的RsiPeriod计算相对强弱指数(RSI),随后对RSI本身应用简单移动平均线。平均后的RSI超过或跌破设定阈值时开仓,并在出现相反信号时平仓。
交易逻辑
- RSI计算
- 使用
RsiPeriod参数根据蜡烛的收盘价计算RSI。
- 使用
- RSI平均
- 通过简单移动平均对最近
AveragePeriod个RSI值进行平滑。
- 通过简单移动平均对最近
- 入场规则
- 当
BuyEnabled为true且当前无持仓时,若平均RSI高于BuyThreshold(默认55),则开多单。 - 当
SellEnabled为true且当前无持仓时,若平均RSI低于SellThreshold(默认45),则开空单。
- 当
- 出场规则
- 当
CloseBySignal为true时,根据相反信号平仓:- 多头持仓在平均RSI跌破
CloseBuyThreshold(默认47)时平仓。 - 空头持仓在平均RSI升破
CloseSellThreshold(默认52)时平仓。
- 多头持仓在平均RSI跌破
- 当
参数
BuyEnabled– 是否允许做多。SellEnabled– 是否允许做空。CloseBySignal– 是否在相反RSI信号出现时平仓。RsiPeriod– RSI计算周期。AveragePeriod– 用于平均的RSI数量。BuyThreshold– 平均RSI高于该值时开多。SellThreshold– 平均RSI低于该值时开空。CloseBuyThreshold– 平均RSI低于该值时平多。CloseSellThreshold– 平均RSI高于该值时平空。CandleType– 订阅的蜡烛类型。
注意
本策略展示了如何在StockSharp高级API中通过绑定组合多个指标。为了简化,原MQL版本中的跟踪止损和资金管理功能未被实现。
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that trades based on averaged RSI values.
/// Uses RSI smoothed by SMA to generate signals.
/// </summary>
public class AutoTradeWithRsiStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _averagePeriod;
private readonly StrategyParam<decimal> _buyThreshold;
private readonly StrategyParam<decimal> _sellThreshold;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _rsiAvg;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int AveragePeriod { get => _averagePeriod.Value; set => _averagePeriod.Value = value; }
public decimal BuyThreshold { get => _buyThreshold.Value; set => _buyThreshold.Value = value; }
public decimal SellThreshold { get => _sellThreshold.Value; set => _sellThreshold.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AutoTradeWithRsiStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation period", "Indicator");
_averagePeriod = Param(nameof(AveragePeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Average Period", "SMA period to smooth RSI", "Indicator");
_buyThreshold = Param(nameof(BuyThreshold), 55m)
.SetDisplay("Buy Threshold", "Averaged RSI above which to buy", "Rules");
_sellThreshold = Param(nameof(SellThreshold), 45m)
.SetDisplay("Sell Threshold", "Averaged RSI below which to sell", "Rules");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle data type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_rsiAvg = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_rsiAvg = new ExponentialMovingAverage { Length = AveragePeriod };
Indicators.Add(_rsiAvg);
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var area2 = CreateChartArea();
if (area2 != null)
DrawIndicator(area2, rsi);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!rsiValue.IsFormed)
return;
var avgResult = _rsiAvg.Process(rsiValue);
if (!avgResult.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var avgRsi = avgResult.GetValue<decimal>();
if (avgRsi > BuyThreshold && Position <= 0)
BuyMarket();
else if (avgRsi < SellThreshold && Position >= 0)
SellMarket();
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class auto_trade_with_rsi_strategy(Strategy):
def __init__(self):
super(auto_trade_with_rsi_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation period", "Indicator")
self._average_period = self.Param("AveragePeriod", 21) \
.SetDisplay("Average Period", "SMA period to smooth RSI", "Indicator")
self._buy_threshold = self.Param("BuyThreshold", 55.0) \
.SetDisplay("Buy Threshold", "Averaged RSI above which to buy", "Rules")
self._sell_threshold = self.Param("SellThreshold", 45.0) \
.SetDisplay("Sell Threshold", "Averaged RSI below which to sell", "Rules")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle data type", "General")
self._rsi_avg = None
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def average_period(self):
return self._average_period.Value
@property
def buy_threshold(self):
return self._buy_threshold.Value
@property
def sell_threshold(self):
return self._sell_threshold.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(auto_trade_with_rsi_strategy, self).OnReseted()
self._rsi_avg = None
def OnStarted2(self, time):
super(auto_trade_with_rsi_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
self._rsi_avg = ExponentialMovingAverage()
self._rsi_avg.Length = self.average_period
self.Indicators.Add(self._rsi_avg)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(rsi, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not rsi_value.IsFormed:
return
avg_result = self._rsi_avg.Process(rsi_value)
if not avg_result.IsFormed:
return
avg_rsi = float(avg_result)
if avg_rsi > float(self.buy_threshold) and self.Position <= 0:
self.BuyMarket()
elif avg_rsi < float(self.sell_threshold) and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return auto_trade_with_rsi_strategy()