Стратегия RSI Stochastic MA
Стратегия использует простую скользящую среднюю для определения направления тренда и комбинирует её с индикаторами RSI и Stochastic. Когда цена выше SMA, ищутся только покупки; когда ниже – только продажи. Уровни RSI и Stochastic помогают находить моменты перекупленности и перепроданности.
Сделки закрываются, когда осцилляторы выходят из экстремальных зон, что позволяет оставаться в тренде и избегать затяжных противодвижений.
Параметры
RsiPeriod– период расчёта RSI.RsiUpperLevel– уровень перекупленности RSI.RsiLowerLevel– уровень перепроданности RSI.MaPeriod– период скользящей средней тренда.StochKPeriod– период %K стохастика.StochDPeriod– период сглаживания %D стохастика.StochUpperLevel– уровень перекупленности стохастика.StochLowerLevel– уровень перепроданности стохастика.Volume– объём заявки.CandleType– тип свечей для расчёта.
Индикаторы
- Простая скользящая средняя
- Индекс относительной силы
- Стохастический осциллятор
Правила торговли
- Покупка: цена выше 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()