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")
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()