Esta estrategia promedia los últimos valores de RSI para generar señales de trading. Calcula un Índice de Fuerza Relativa (RSI) estándar sobre un período configurable y luego aplica una media móvil simple al propio RSI. Las operaciones se abren cuando el RSI promediado cruza umbrales predefinidos y se cierran cuando se alcanza el umbral opuesto.
Lógica de trading
Cálculo del RSI
El indicador utiliza RsiPeriod para calcular el RSI basado en precios de cierre de velas.
Promediado del RSI
Los últimos AveragePeriod valores de RSI se suavizan con una media móvil simple.
Reglas de entrada
Si BuyEnabled es true y no hay posición abierta, se envía una orden de compra cuando el RSI promediado supera BuyThreshold (por defecto 55).
Si SellEnabled es true y no hay posición abierta, se envía una orden de venta cuando el RSI promediado cae por debajo de SellThreshold (por defecto 45).
Reglas de salida
Cuando CloseBySignal es true, las posiciones abiertas se cierran en señales opuestas:
Las posiciones largas se cierran cuando el RSI promediado cae por debajo de CloseBuyThreshold (por defecto 47).
Las posiciones cortas se cierran cuando el RSI promediado sube por encima de CloseSellThreshold (por defecto 52).
Parámetros
BuyEnabled – habilitar o deshabilitar entradas largas.
SellEnabled – habilitar o deshabilitar entradas cortas.
CloseBySignal – permitir salidas en señales RSI opuestas.
RsiPeriod – longitud del cálculo del RSI.
AveragePeriod – número de valores de RSI usados para el promediado.
BuyThreshold – valor del RSI promediado por encima del cual se abre una posición larga.
SellThreshold – valor del RSI promediado por debajo del cual se abre una posición corta.
CloseBuyThreshold – valor del RSI promediado por debajo del cual se cierra una posición larga.
CloseSellThreshold – valor del RSI promediado por encima del cual se cierra una posición corta.
CandleType – tipo de vela para las suscripciones.
Notas
Esta estrategia demuestra cómo los valores de indicadores pueden combinarse mediante vinculación en la API de alto nivel de StockSharp. Las funciones de trailing stop y gestión del dinero de la versión MQL original se omiten por simplicidad.
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 that trades based on averaged RSI values.
/// Uses RSI smoothed by SMA to generate signals.
/// </summary>
public class AutoTradeWithRsiStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _averagePeriod;
private readonly StrategyParam<decimal> _buyThreshold;
private readonly StrategyParam<decimal> _sellThreshold;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _rsiAvg;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int AveragePeriod { get => _averagePeriod.Value; set => _averagePeriod.Value = value; }
public decimal BuyThreshold { get => _buyThreshold.Value; set => _buyThreshold.Value = value; }
public decimal SellThreshold { get => _sellThreshold.Value; set => _sellThreshold.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AutoTradeWithRsiStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation period", "Indicator");
_averagePeriod = Param(nameof(AveragePeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Average Period", "SMA period to smooth RSI", "Indicator");
_buyThreshold = Param(nameof(BuyThreshold), 55m)
.SetDisplay("Buy Threshold", "Averaged RSI above which to buy", "Rules");
_sellThreshold = Param(nameof(SellThreshold), 45m)
.SetDisplay("Sell Threshold", "Averaged RSI below which to sell", "Rules");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle data type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_rsiAvg = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_rsiAvg = new ExponentialMovingAverage { Length = AveragePeriod };
Indicators.Add(_rsiAvg);
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var area2 = CreateChartArea();
if (area2 != null)
DrawIndicator(area2, rsi);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!rsiValue.IsFormed)
return;
var avgResult = _rsiAvg.Process(rsiValue);
if (!avgResult.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var avgRsi = avgResult.GetValue<decimal>();
if (avgRsi > BuyThreshold && Position <= 0)
BuyMarket();
else if (avgRsi < SellThreshold && Position >= 0)
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 auto_trade_with_rsi_strategy(Strategy):
def __init__(self):
super(auto_trade_with_rsi_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation period", "Indicator")
self._average_period = self.Param("AveragePeriod", 21) \
.SetDisplay("Average Period", "SMA period to smooth RSI", "Indicator")
self._buy_threshold = self.Param("BuyThreshold", 55.0) \
.SetDisplay("Buy Threshold", "Averaged RSI above which to buy", "Rules")
self._sell_threshold = self.Param("SellThreshold", 45.0) \
.SetDisplay("Sell Threshold", "Averaged RSI below which to sell", "Rules")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle data type", "General")
self._rsi_avg = None
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def average_period(self):
return self._average_period.Value
@property
def buy_threshold(self):
return self._buy_threshold.Value
@property
def sell_threshold(self):
return self._sell_threshold.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(auto_trade_with_rsi_strategy, self).OnReseted()
self._rsi_avg = None
def OnStarted2(self, time):
super(auto_trade_with_rsi_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
self._rsi_avg = ExponentialMovingAverage()
self._rsi_avg.Length = self.average_period
self.Indicators.Add(self._rsi_avg)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(rsi, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not rsi_value.IsFormed:
return
avg_result = self._rsi_avg.Process(rsi_value)
if not avg_result.IsFormed:
return
avg_rsi = float(avg_result)
if avg_rsi > float(self.buy_threshold) and self.Position <= 0:
self.BuyMarket()
elif avg_rsi < float(self.sell_threshold) and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return auto_trade_with_rsi_strategy()