Esta estrategia convierte el asesor experto original iRSISign de MQL5 en la API de alto nivel de StockSharp. Combina el Índice de Fuerza Relativa (RSI) con el Rango Verdadero Promedio (ATR) para generar señales de entrada y salida.
El sistema escucha velas finalizadas de un marco temporal definido por el usuario. Cuando el RSI cruza por encima del umbral inferior, señala una posible reversión alcista y abre una posición larga o cierra un corto existente. Por el contrario, cuando el RSI cae por debajo del umbral superior, entra en una posición corta o cierra un largo activo. El ATR se calcula pero se usa solo como contexto adicional, reflejando el indicador original que mostraba flechas de señal desplazadas por ATR.
Detalles
Criterios de entrada:
Largo: El valor anterior del RSI estaba por debajo de DownLevel y el RSI actual cruza por encima.
Corto: El valor anterior del RSI estaba por encima de UpLevel y el RSI actual cruza por debajo.
Largo/Corto: Ambas direcciones están permitidas y pueden habilitarse de forma independiente.
Criterios de salida:
La señal opuesta cierra la posición actual si el indicador de cierre correspondiente está habilitado.
Stops: No implementados. La gestión del riesgo puede añadirse externamente si es necesario.
Valores predeterminados:
RsiPeriod = 14
AtrPeriod = 14
UpLevel = 70
DownLevel = 30
CandleType = velas de 1 hora
Filtros:
Categoría: Momentum
Dirección: Ambos
Indicadores: RSI, ATR
Stops: No
Complejidad: Básico
Marco temporal: Flexible
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Medio
Parámetros
Nombre
Descripción
RsiPeriod
Longitud del RSI.
AtrPeriod
Longitud del ATR.
UpLevel
Umbral superior del RSI que genera señales de venta.
DownLevel
Umbral inferior del RSI que genera señales de compra.
CandleType
Marco temporal de velas usado para los cálculos.
BuyOpen
Habilitar apertura de posiciones largas.
SellOpen
Habilitar apertura de posiciones cortas.
BuyClose
Permitir cierre de largos existentes con señal opuesta.
SellClose
Permitir cierre de cortos existentes con señal opuesta.
La estrategia está pensada como ejemplo educativo que demuestra cómo traducir la lógica simple de MQL5 al marco de estrategias de alto nivel de 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 signal strategy.
/// Opens long when RSI crosses above the down level.
/// Opens short when RSI crosses below the up level.
/// </summary>
public class RsiSignStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _upLevel;
private readonly StrategyParam<decimal> _downLevel;
private readonly StrategyParam<DataType> _candleType;
private decimal? _previousRsi;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal UpLevel { get => _upLevel.Value; set => _upLevel.Value = value; }
public decimal DownLevel { get => _downLevel.Value; set => _downLevel.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public RsiSignStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Length of RSI indicator", "Indicator");
_upLevel = Param(nameof(UpLevel), 70m)
.SetDisplay("RSI Upper Level", "Sell when RSI falls below this value", "Indicator");
_downLevel = Param(nameof(DownLevel), 30m)
.SetDisplay("RSI Lower Level", "Buy when RSI rises above this value", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for indicator calculations", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousRsi = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previousRsi = null;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var prevRsi = _previousRsi;
_previousRsi = rsiValue;
if (prevRsi is null)
return;
// RSI crosses above lower level -> buy signal
if (prevRsi <= DownLevel && rsiValue > DownLevel && Position <= 0)
BuyMarket();
// RSI crosses below upper level -> sell signal
else if (prevRsi >= UpLevel && rsiValue < UpLevel && 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
from StockSharp.Algo.Strategies import Strategy
class rsi_sign_strategy(Strategy):
def __init__(self):
super(rsi_sign_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Length of RSI indicator", "Indicator")
self._up_level = self.Param("UpLevel", 70.0) \
.SetDisplay("RSI Upper Level", "Sell when RSI falls below this value", "Indicator")
self._down_level = self.Param("DownLevel", 30.0) \
.SetDisplay("RSI Lower Level", "Buy when RSI rises above this value", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe used for indicator calculations", "General")
self._previous_rsi = None
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def up_level(self):
return self._up_level.Value
@property
def down_level(self):
return self._down_level.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(rsi_sign_strategy, self).OnReseted()
self._previous_rsi = None
def OnStarted2(self, time):
super(rsi_sign_strategy, self).OnStarted2(time)
self._previous_rsi = None
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi_value = float(rsi_value)
prev_rsi = self._previous_rsi
self._previous_rsi = rsi_value
if prev_rsi is None:
return
down_lvl = float(self.down_level)
up_lvl = float(self.up_level)
if prev_rsi <= down_lvl and rsi_value > down_lvl and self.Position <= 0:
self.BuyMarket()
elif prev_rsi >= up_lvl and rsi_value < up_lvl and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return rsi_sign_strategy()