RSI 随机指标 均线 策略
该策略把简单移动平均线(SMA)作为趋势过滤器,并结合RSI与随机指标。 当价格在SMA之上时仅考虑做多;在SMA之下时仅考虑做空。RSI与随机指标的上下限 用于判断超买和超卖的入场时机。
当任一振荡指标离开极端区间时平仓,使交易始终跟随主要趋势,同时避免指标反向延伸。
参数
RsiPeriod– RSI 计算周期。RsiUpperLevel– RSI 超买水平。RsiLowerLevel– RSI 超卖水平。MaPeriod– 趋势移动平均线周期。StochKPeriod– 随机指标 %K 周期。StochDPeriod– 随机指标 %D 平滑周期。StochUpperLevel– 随机指标超买水平。StochLowerLevel– 随机指标超卖水平。Volume– 交易量。CandleType– 计算所使用的K线类型。
指标
- 简单移动平均线
- 相对强弱指数
- 随机指标
交易规则
- 买入:价格高于SMA,RSI低于
RsiLowerLevel,并且随机指标两条线都低于StochLowerLevel。 - 卖出:价格低于SMA,RSI高于
RsiUpperLevel,并且随机指标两条线都高于StochUpperLevel。 - 多头平仓:当RSI或随机指标突破其上限时。
- 空头平仓:当RSI或随机指标跌破其下限时。
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>
/// Combined RSI, Stochastic, and Moving Average strategy.
/// The MA defines the trend. Entries on RSI+Stochastic oversold/overbought in trend direction.
/// </summary>
public class RsiStochasticMaStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiUpperLevel;
private readonly StrategyParam<decimal> _rsiLowerLevel;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<decimal> _stochUpperLevel;
private readonly StrategyParam<decimal> _stochLowerLevel;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<decimal> _takeProfitPct;
private readonly StrategyParam<DataType> _candleType;
private StochasticOscillator _stochastic;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal RsiUpperLevel { get => _rsiUpperLevel.Value; set => _rsiUpperLevel.Value = value; }
public decimal RsiLowerLevel { get => _rsiLowerLevel.Value; set => _rsiLowerLevel.Value = value; }
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
public decimal StochUpperLevel { get => _stochUpperLevel.Value; set => _stochUpperLevel.Value = value; }
public decimal StochLowerLevel { get => _stochLowerLevel.Value; set => _stochLowerLevel.Value = value; }
public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
public decimal TakeProfitPct { get => _takeProfitPct.Value; set => _takeProfitPct.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public RsiStochasticMaStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 3)
.SetDisplay("RSI Period", "RSI calculation period", "RSI");
_rsiUpperLevel = Param(nameof(RsiUpperLevel), 65m)
.SetDisplay("RSI Upper Level", "RSI overbought level", "RSI");
_rsiLowerLevel = Param(nameof(RsiLowerLevel), 35m)
.SetDisplay("RSI Lower Level", "RSI oversold level", "RSI");
_maPeriod = Param(nameof(MaPeriod), 20)
.SetDisplay("MA Period", "Moving average period", "Trend");
_stochUpperLevel = Param(nameof(StochUpperLevel), 60m)
.SetDisplay("Stochastic Upper", "Stochastic overbought level", "Stochastic");
_stochLowerLevel = Param(nameof(StochLowerLevel), 40m)
.SetDisplay("Stochastic Lower", "Stochastic oversold level", "Stochastic");
_stopLossPct = Param(nameof(StopLossPct), 2m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_stochastic = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var ma = new ExponentialMovingAverage { Length = MaPeriod };
_stochastic = new StochasticOscillator();
Indicators.Add(_stochastic);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ma, rsi, (candle, maValue, rsiValue) =>
{
if (candle.State != CandleStates.Finished)
return;
var stochResult = _stochastic.Process(candle);
if (!_stochastic.IsFormed)
return;
var stochVal = (StochasticOscillatorValue)stochResult;
if (stochVal.K is not decimal k || stochVal.D is not decimal d)
return;
var price = candle.ClosePrice;
var isUpTrend = price > maValue;
var isDownTrend = price < maValue;
if (isUpTrend && rsiValue < RsiLowerLevel && k < StochLowerLevel && Position == 0)
{
BuyMarket();
}
else if (isDownTrend && rsiValue > RsiUpperLevel && k > StochUpperLevel && Position == 0)
{
SellMarket();
}
})
.Start();
StartProtection(
takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ma);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex, ExponentialMovingAverage, StochasticOscillator, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class rsi_stochastic_ma_strategy(Strategy):
def __init__(self):
super(rsi_stochastic_ma_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 3) \
.SetDisplay("RSI Period", "RSI calculation period", "RSI")
self._rsi_upper_level = self.Param("RsiUpperLevel", 65.0) \
.SetDisplay("RSI Upper Level", "RSI overbought level", "RSI")
self._rsi_lower_level = self.Param("RsiLowerLevel", 35.0) \
.SetDisplay("RSI Lower Level", "RSI oversold level", "RSI")
self._ma_period = self.Param("MaPeriod", 20) \
.SetDisplay("MA Period", "Moving average period", "Trend")
self._stoch_upper_level = self.Param("StochUpperLevel", 60.0) \
.SetDisplay("Stochastic Upper", "Stochastic overbought level", "Stochastic")
self._stoch_lower_level = self.Param("StochLowerLevel", 40.0) \
.SetDisplay("Stochastic Lower", "Stochastic oversold level", "Stochastic")
self._stop_loss_pct = self.Param("StopLossPct", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._take_profit_pct = self.Param("TakeProfitPct", 3.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._stochastic = None
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def rsi_upper_level(self):
return self._rsi_upper_level.Value
@property
def rsi_lower_level(self):
return self._rsi_lower_level.Value
@property
def ma_period(self):
return self._ma_period.Value
@property
def stoch_upper_level(self):
return self._stoch_upper_level.Value
@property
def stoch_lower_level(self):
return self._stoch_lower_level.Value
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def take_profit_pct(self):
return self._take_profit_pct.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(rsi_stochastic_ma_strategy, self).OnReseted()
self._stochastic = None
def OnStarted2(self, time):
super(rsi_stochastic_ma_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
ma = ExponentialMovingAverage()
ma.Length = self.ma_period
self._stochastic = StochasticOscillator()
self.Indicators.Add(self._stochastic)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ma, rsi, self.on_candle).Start()
self.StartProtection(
takeProfit=Unit(self.take_profit_pct, UnitTypes.Percent),
stopLoss=Unit(self.stop_loss_pct, UnitTypes.Percent),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ma)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def on_candle(self, candle, ma_value, rsi_value):
if candle.State != CandleStates.Finished:
return
cv = CandleIndicatorValue(self._stochastic, candle)
stoch_result = self._stochastic.Process(cv)
if not self._stochastic.IsFormed:
return
k = stoch_result.K
d = stoch_result.D
if k is None or d is None:
return
k = float(k)
ma_value = float(ma_value)
rsi_value = float(rsi_value)
price = float(candle.ClosePrice)
is_up_trend = price > ma_value
is_down_trend = price < ma_value
if is_up_trend and rsi_value < float(self.rsi_lower_level) and k < float(self.stoch_lower_level) and self.Position == 0:
self.BuyMarket()
elif is_down_trend and rsi_value > float(self.rsi_upper_level) and k > float(self.stoch_upper_level) and self.Position == 0:
self.SellMarket()
def CreateClone(self):
return rsi_stochastic_ma_strategy()