Стратегия использует индикатор RSI для поиска разворотов после краткосрочных экстремумов. Сигнал на покупку возникает, когда RSI пересекает уровень перепроданности снизу после двух свечей ниже этого уровня. Сигнал на продажу появляется при пересечении уровня перекупленности сверху после двух свечей выше него. Стратегия по желанию закрывает противоположную позицию и торгует только в заданном часовом диапазоне.
Детали
Критерии входа:
Лонг: RSI > BuyPoint и значения RSI двух предыдущих свечей < BuyPoint.
Шорт: RSI < SellPoint и значения RSI двух предыдущих свечей > SellPoint.
Критерии выхода: Противоположный сигнал или защитные уровни take-profit/stop-loss.
Фильтр по времени: Торги ведутся только, если час открытия свечи находится между StartHour и EndHour.
Стопы: Фиксированные уровни take-profit и stop-loss в единицах цены.
Параметры:
RsiPeriod – период расчёта RSI.
BuyPoint – уровень перепроданности для входа в лонг.
SellPoint – уровень перекупленности для входа в шорт.
CloseOnOpposite – закрывать текущую позицию при противоположном сигнале.
StartHour / EndHour – торговые часы.
TakeProfit / StopLoss – защитные уровни в цене.
Пример демонстрирует простую систему на основе RSI и может служить шаблоном для дальнейших экспериментов с API StockSharp.
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>
/// RSI-based trading strategy.
/// Buys when RSI crosses above BuyPoint, sells when RSI crosses below SellPoint.
/// </summary>
public class RsiTraderV1Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _buyPoint;
private readonly StrategyParam<decimal> _sellPoint;
private decimal _prevRsi;
private decimal _prevPrevRsi;
private bool _hasPrev;
private bool _hasPrevPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal BuyPoint { get => _buyPoint.Value; set => _buyPoint.Value = value; }
public decimal SellPoint { get => _sellPoint.Value; set => _sellPoint.Value = value; }
public RsiTraderV1Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Calculation period", "RSI");
_buyPoint = Param(nameof(BuyPoint), 30m)
.SetDisplay("Buy Threshold", "RSI level for long entry", "RSI");
_sellPoint = Param(nameof(SellPoint), 70m)
.SetDisplay("Sell Threshold", "RSI level for short entry", "RSI");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0;
_prevPrevRsi = 0;
_hasPrev = false;
_hasPrevPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
SubscribeCandles(CandleType)
.Bind(rsi, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevRsi = rsiValue;
_hasPrev = true;
return;
}
if (!_hasPrevPrev)
{
_prevPrevRsi = _prevRsi;
_prevRsi = rsiValue;
_hasPrevPrev = true;
return;
}
var longSignal = rsiValue > BuyPoint && _prevRsi < BuyPoint && _prevPrevRsi < BuyPoint;
var shortSignal = rsiValue < SellPoint && _prevRsi > SellPoint && _prevPrevRsi > SellPoint;
if (longSignal && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (shortSignal && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevPrevRsi = _prevRsi;
_prevRsi = rsiValue;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class rsi_trader_v1_strategy(Strategy):
def __init__(self):
super(rsi_trader_v1_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Calculation period", "RSI")
self._buy_point = self.Param("BuyPoint", 30.0) \
.SetDisplay("Buy Threshold", "RSI level for long entry", "RSI")
self._sell_point = self.Param("SellPoint", 70.0) \
.SetDisplay("Sell Threshold", "RSI level for short entry", "RSI")
self._prev_rsi = 0.0
self._prev_prev_rsi = 0.0
self._has_prev = False
self._has_prev_prev = False
@property
def candle_type(self):
return self._candle_type.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def buy_point(self):
return self._buy_point.Value
@property
def sell_point(self):
return self._sell_point.Value
def OnReseted(self):
super(rsi_trader_v1_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._prev_prev_rsi = 0.0
self._has_prev = False
self._has_prev_prev = False
def OnStarted2(self, time):
super(rsi_trader_v1_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
self.SubscribeCandles(self.candle_type).Bind(rsi, self.process_candle).Start()
def process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_value)
if not self._has_prev:
self._prev_rsi = rv
self._has_prev = True
return
if not self._has_prev_prev:
self._prev_prev_rsi = self._prev_rsi
self._prev_rsi = rv
self._has_prev_prev = True
return
bp = float(self.buy_point)
sp = float(self.sell_point)
long_signal = rv > bp and self._prev_rsi < bp and self._prev_prev_rsi < bp
short_signal = rv < sp and self._prev_rsi > sp and self._prev_prev_rsi > sp
if long_signal and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif short_signal and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_prev_rsi = self._prev_rsi
self._prev_rsi = rv
def CreateClone(self):
return rsi_trader_v1_strategy()