La estrategia dual RSI en RSI recrea el asesor experto MetaTrader "RSI_MAonRSI_Dual" dentro de StockSharp. Observa dos índices de fuerza relativa con diferentes períodos retrospectivos y aplica un promedio móvil común encima de cada secuencia RSI. Las decisiones comerciales se toman cuando las líneas RSI suavizadas se cruzan mientras permanecen en el mismo lado de un nivel neutral configurable.
La conversión mantiene el comportamiento del robot original, incluido el filtrado de tiempo y la capacidad de restringir la dirección comercial o invertir la lógica de la señal.
Indicadores
Rápido RSI – Índice de fuerza relativa con período configurable.
Lento RSI – Índice de fuerza relativa con su propio período.
Promedio móvil en RSI: promedio móvil simple calculado sobre cada flujo de valor de RSI. Ambos RSI utilizan la misma longitud de suavizado.
Los tres indicadores comparten el mismo precio aplicado (precio de cierre por defecto). Las dos líneas RSI suavizadas se dibujan en un panel de gráfico dedicado para el seguimiento.
Reglas de entrada
Espere a que se formen ambos valores RSI suavizados en la barra completada actualmente.
Configuración larga
El RSI de suavizado rápido cruza arriba el RSI de suavizado lento (valor actual arriba, valor anterior abajo).
Ambos RSI suavizados están por debajo del nivel neutral (50 por defecto).
Configuración corta
El RSI de suavizado rápido cruza abajo el RSI de suavizado lento (valor actual debajo, valor anterior arriba).
Ambos RSI suavizados están por encima del nivel neutral.
Opcionalmente, invierta las direcciones de la señal utilizando el parámetro ReverseSignals.
Las señales generadas en la misma barra se ignoran (una entrada por barra).
Gestión de posiciones
AllowLong y AllowShort controlan si la estrategia puede abrir posiciones en cada dirección.
CloseOpposite cierra una posición existente antes de ingresar al lado opuesto, replicando la lógica EA original.
OnlyOnePosition prohíbe abrir una nueva posición cuando alguna posición ya está activa.
Las órdenes de mercado se emiten con la estrategia Volume.
Filtro de tiempo
Habilite o deshabilite el filtro de sesión comercial con UseTimeFilter. Cuando está habilitado, los intercambios solo se permiten entre SessionStart y SessionEnd. Se admiten sesiones que cruzan la medianoche. Las marcas de tiempo se evalúan en la zona horaria de intercambio proporcionada por los mensajes de vela entrantes.
Parámetros
Nombre
Descripción
CandleType
Serie de velas analizadas por la estrategia.
FastRsiPeriod
Período del ayuno RSI.
SlowRsiPeriod
Periodo de la lentitud RSI.
MaPeriod
Longitud de media móvil utilizada para suavizar ambas secuencias RSI.
AppliedPrice
Tipo de precio reenviado a los cálculos de RSI.
NeutralLevel
RSI umbral que separa zonas alcistas y bajistas.
AllowLong / AllowShort
Habilite o deshabilite la dirección comercial.
ReverseSignals
Intercambia señales largas y cortas.
CloseOpposite
Cierre la posición opuesta antes de ingresar a una nueva.
OnlyOnePosition
Permitir como máximo una posición abierta.
UseTimeFilter
Active el filtro de sesión de negociación.
SessionStart / SessionEnd
Límites de la ventana de negociación.
Diferencias con el EA original
Los bloques de gestión de dinero, stop-loss y trailing-stop del código original MQL5 no se reproducen. La estrategia StockSharp coloca órdenes de mercado utilizando el Volume fijo configurado en la estrategia.
Se eliminaron todas las alertas de registro y diagnóstico; En su lugar, se debe utilizar el registro StockSharp si es necesario.
El seguimiento de transacciones específico de la plataforma se reemplaza con StockSharp eventos de estado de pedido.
A pesar de estas diferencias, la lógica de entrada central y los filtros direccionales coinciden con el asesor experto fuente.
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>
/// Dual moving averages calculated on top of RSI values.
/// Fast RSI MA crossing slow RSI MA generates entry signals.
/// </summary>
public class RsiMaOnRsiDualStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastRsiPeriod;
private readonly StrategyParam<int> _slowRsiPeriod;
private readonly StrategyParam<int> _maPeriod;
private RelativeStrengthIndex _fastRsi;
private RelativeStrengthIndex _slowRsi;
private readonly Queue<decimal> _fastRsiHistory = new();
private readonly Queue<decimal> _slowRsiHistory = new();
private decimal? _previousFastMa;
private decimal? _previousSlowMa;
public RsiMaOnRsiDualStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle type", "Candles processed by the strategy.", "General");
_fastRsiPeriod = Param(nameof(FastRsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Fast RSI period", "Length of the fast RSI smoothing window.", "Indicators");
_slowRsiPeriod = Param(nameof(SlowRsiPeriod), 28)
.SetGreaterThanZero()
.SetDisplay("Slow RSI period", "Length of the slow RSI smoothing window.", "Indicators");
_maPeriod = Param(nameof(MaPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("MA period", "Number of RSI values averaged by the smoothing moving average.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastRsiPeriod
{
get => _fastRsiPeriod.Value;
set => _fastRsiPeriod.Value = value;
}
public int SlowRsiPeriod
{
get => _slowRsiPeriod.Value;
set => _slowRsiPeriod.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousFastMa = null;
_previousSlowMa = null;
_fastRsiHistory.Clear();
_slowRsiHistory.Clear();
_fastRsi = null!;
_slowRsi = null!;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previousFastMa = null;
_previousSlowMa = null;
_fastRsiHistory.Clear();
_slowRsiHistory.Clear();
_fastRsi = new RelativeStrengthIndex { Length = FastRsiPeriod };
_slowRsi = new RelativeStrengthIndex { Length = SlowRsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastRsi, _slowRsi, ProcessCandle)
.Start();
var priceArea = CreateChartArea();
if (priceArea != null)
{
DrawCandles(priceArea, subscription);
DrawOwnTrades(priceArea);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastRsiValue, decimal slowRsiValue)
{
if (candle.State != CandleStates.Finished)
return;
_fastRsiHistory.Enqueue(fastRsiValue);
_slowRsiHistory.Enqueue(slowRsiValue);
while (_fastRsiHistory.Count > MaPeriod)
_fastRsiHistory.Dequeue();
while (_slowRsiHistory.Count > MaPeriod)
_slowRsiHistory.Dequeue();
if (!_fastRsi.IsFormed || !_slowRsi.IsFormed)
return;
if (_fastRsiHistory.Count < MaPeriod || _slowRsiHistory.Count < MaPeriod)
return;
// Calculate SMA of each RSI
var fastSum = 0m;
var fastHistory = _fastRsiHistory.ToArray();
foreach (var v in fastHistory)
fastSum += v;
var fastMa = fastSum / MaPeriod;
var slowSum = 0m;
var slowHistory = _slowRsiHistory.ToArray();
foreach (var v in slowHistory)
slowSum += v;
var slowMa = slowSum / MaPeriod;
if (_previousFastMa is null || _previousSlowMa is null)
{
_previousFastMa = fastMa;
_previousSlowMa = slowMa;
return;
}
var crossUp = _previousFastMa < _previousSlowMa && fastMa > slowMa;
var crossDown = _previousFastMa > _previousSlowMa && fastMa < slowMa;
var volume = Volume;
if (volume <= 0)
volume = 1;
if (crossUp)
{
if (Position <= 0)
BuyMarket(volume);
}
else if (crossDown)
{
if (Position >= 0)
SellMarket(volume);
}
_previousFastMa = fastMa;
_previousSlowMa = slowMa;
}
}