Стратегия RSI MA Trend
Стратегия сочетает индикатор относительной силы (RSI) и фильтр тренда на основе скользящих средних. Длинная позиция открывается, когда RSI опускается ниже заданного уровня покупки и быстрая скользящая средняя находится выше медленной. Короткая позиция открывается, когда RSI поднимается выше уровня продажи и быстрая скользящая средняя находится ниже медленной.
Параметры
RSI Period– период индикатора RSI.RSI Buy Level– значение RSI, ниже которого открывается длинная позиция.RSI Sell Level– значение RSI, выше которого открывается короткая позиция.Fast MA Period– период быстрой скользящей средней.Slow MA Period– период медленной скользящей средней.Candle Type– тип свечей, используемый в расчётах.
Логика
- Подписка на выбранную серию свечей.
- Для каждой завершённой свечи рассчитываются RSI, быстрая и медленная SMA.
- Если быстрая SMA выше медленной, считается восходящий тренд, иначе – нисходящий.
- Открытие длинной позиции при RSI < уровня покупки и восходящем тренде, при необходимости закрывая короткую.
- Открытие короткой позиции при RSI > уровня продажи и нисходящем тренде, при необходимости закрывая длинную.
Примечания
- Для входа используются рыночные заявки.
- Сигналы обрабатываются только по завершённым свечам.
- Параметры доступны для оптимизации в интерфейсе.
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 combining RSI with moving average trend filter.
/// Buys when RSI is below the buy level and fast MA is above slow MA.
/// Sells when RSI is above the sell level and fast MA is below slow MA.
/// </summary>
public class RsiMaTrendStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiBuyLevel;
private readonly StrategyParam<decimal> _rsiSellLevel;
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<int> _slowMaPeriod;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// RSI period length.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI level to trigger buy.
/// </summary>
public decimal RsiBuyLevel
{
get => _rsiBuyLevel.Value;
set => _rsiBuyLevel.Value = value;
}
/// <summary>
/// RSI level to trigger sell.
/// </summary>
public decimal RsiSellLevel
{
get => _rsiSellLevel.Value;
set => _rsiSellLevel.Value = value;
}
/// <summary>
/// Fast moving average period.
/// </summary>
public int FastMaPeriod
{
get => _fastMaPeriod.Value;
set => _fastMaPeriod.Value = value;
}
/// <summary>
/// Slow moving average period.
/// </summary>
public int SlowMaPeriod
{
get => _slowMaPeriod.Value;
set => _slowMaPeriod.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public RsiMaTrendStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Length of RSI indicator", "Indicators")
.SetOptimize(10, 30, 5);
_rsiBuyLevel = Param(nameof(RsiBuyLevel), 45m)
.SetDisplay("RSI Buy Level", "Value below which long is opened", "Indicators")
.SetOptimize(20m, 40m, 5m);
_rsiSellLevel = Param(nameof(RsiSellLevel), 55m)
.SetDisplay("RSI Sell Level", "Value above which short is opened", "Indicators")
.SetOptimize(60m, 80m, 5m);
_fastMaPeriod = Param(nameof(FastMaPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast MA Period", "Length of fast moving average", "Indicators")
.SetOptimize(20, 80, 10);
_slowMaPeriod = Param(nameof(SlowMaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow MA Period", "Length of slow moving average", "Indicators")
.SetOptimize(100, 300, 20);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var fastMa = new ExponentialMovingAverage { Length = FastMaPeriod };
var slowMa = new ExponentialMovingAverage { Length = SlowMaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, fastMa, slowMa, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawIndicator(area, fastMa);
DrawIndicator(area, slowMa);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal fastMaValue, decimal slowMaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var isUpTrend = fastMaValue > slowMaValue;
if (rsiValue < RsiBuyLevel && isUpTrend && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (rsiValue > RsiSellLevel && !isUpTrend && Position >= 0)
{
if (Position > 0)
SellMarket();
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 rsi_ma_trend_strategy(Strategy):
def __init__(self):
super(rsi_ma_trend_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 21) \
.SetDisplay("RSI Period", "Length of RSI indicator", "Indicators")
self._rsi_buy_level = self.Param("RsiBuyLevel", 45.0) \
.SetDisplay("RSI Buy Level", "Value below which long is opened", "Indicators")
self._rsi_sell_level = self.Param("RsiSellLevel", 55.0) \
.SetDisplay("RSI Sell Level", "Value above which short is opened", "Indicators")
self._fast_ma_period = self.Param("FastMaPeriod", 10) \
.SetDisplay("Fast MA Period", "Length of fast moving average", "Indicators")
self._slow_ma_period = self.Param("SlowMaPeriod", 50) \
.SetDisplay("Slow MA Period", "Length of slow moving average", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def rsi_buy_level(self):
return self._rsi_buy_level.Value
@property
def rsi_sell_level(self):
return self._rsi_sell_level.Value
@property
def fast_ma_period(self):
return self._fast_ma_period.Value
@property
def slow_ma_period(self):
return self._slow_ma_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(rsi_ma_trend_strategy, self).OnReseted()
def OnStarted2(self, time):
super(rsi_ma_trend_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.fast_ma_period
slow_ma = ExponentialMovingAverage()
slow_ma.Length = self.slow_ma_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, fast_ma, slow_ma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawIndicator(area, fast_ma)
self.DrawIndicator(area, slow_ma)
self.DrawOwnTrades(area)
def process_candle(self, candle, rsi_value, fast_ma_value, slow_ma_value):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
fast_val = float(fast_ma_value)
slow_val = float(slow_ma_value)
is_up_trend = fast_val > slow_val
if rsi_val < float(self.rsi_buy_level) and is_up_trend and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif rsi_val > float(self.rsi_sell_level) and not is_up_trend and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return rsi_ma_trend_strategy()