La RSI MA en la RSI estrategia de paso de llenado es una adaptación StockSharp del MetaTrader asesor experto RSI_MAonRSI_Filling Step EA.mq5. El sistema original mide el impulso con un índice de fuerza relativa (RSI) y suaviza ese oscilador con una media móvil. Las operaciones se inician cuando RSI cruza su media móvil mientras ambos valores permanecen en el mismo lado del nivel medio 50. La conversión mantiene los filtros de dirección comercial configurables, el temporizador de sesión opcional y la capacidad de revertir las señales mientras aprovecha los enlaces de indicadores de alto nivel de StockSharp.
Lógica de trading
Suscríbase a la serie de velas seleccionada y calcule dos indicadores en cada barra terminada: RelativeStrengthIndex con longitud RsiPeriod y MovingAverage (MaType, MaPeriod) aplicados a la secuencia RSI.
Espere a que se completen las velas antes de actuar, replicando la protección de "nueva barra" de EA para que cada barra produzca como máximo una decisión comercial.
Se produce una configuración alcista cuando el valor RSI anterior estaba por debajo de su promedio móvil y el último valor cierra por encima del promedio mientras ambas lecturas permanecen por debajo de MiddleLevel (predeterminado 50). Una configuración bajista es el caso reflejado por encima del nivel medio.
Cuando ReverseSignals está habilitado, la condición alcista genera una operación corta y la condición bajista genera una operación larga, imitando la bandera inversa de EA.
El parámetro Mode limita el comercio solo a largo plazo, solo a corto plazo o en ambas direcciones. Opcionalmente, guardias adicionales cierran la exposición opuesta y bloquean nuevas entradas cuando una posición ya está abierta.
Una ventana de tiempo diaria idéntica a la implementación de MetaTrader puede deshabilitar señales fuera del intervalo configurado SessionStart → SessionEnd, incluidas las sesiones que finalizan hasta la medianoche.
Parámetros
CandleType – serie de datos procesada por la estrategia. El valor predeterminado son velas con un marco de tiempo de una hora.
RsiPeriod – RSI longitud promedio (predeterminado 14).
MaPeriod: duración de la media móvil aplicada a RSI (predeterminado 21).
MaType: tipo de media móvil utilizado para el suavizado RSI (predeterminado Simple).
MiddleLevel: nivel central RSI utilizado por ambos indicadores para validar operaciones (predeterminado 50).
ReverseSignals: invierte la interpretación del cruce alcista/bajista (predeterminado false).
Modo: filtro de dirección comercial (BuyOnly, SellOnly, Both).
CloseOppositePositions: si se debe aplanar la posición opuesta antes de ingresar a una nueva operación (predeterminado false).
OnlyOnePosition: evita nuevas órdenes mientras una posición ya está abierta (predeterminado false).
UseTimeWindow: habilita el filtro de sesión de negociación diaria (predeterminado false).
SessionStart / SessionEnd: horas de inicio y finalización de la sesión comercial permitida. Funciona con sesiones nocturnas terminando después de la medianoche.
Notas de implementación
Los valores del indicador se entregan a través de Bind, lo que elimina la necesidad de administración manual del búfer que el EA original requería con CopyBuffer.
Los valores anteriores de RSI y de media móvil se almacenan en caché para reflejar el patrón de acceso RSI[m_bar_current+1] de MQL. El campo _lastSignalBarTime garantiza solo una operación por barra, al igual que las marcas de tiempo m_last_deal_buy_in / m_last_deal_sell_in de EA.
La gestión comercial utiliza BuyMarket() y SellMarket() para reflejar la ejecución inmediata del mercado de EA. El cierre opcional de la exposición opuesta se gestiona con ClosePosition() antes de realizar la nueva orden.
El filtro de tiempo replica la función TimeControlHourMinute de EA, incluida la lógica de la ventana nocturna donde la hora de inicio es mayor que la hora de finalización.
Los ayudantes de gráficos dibujan velas de precios con marcadores comerciales más un panel RSI dedicado para que los cruces puedan inspeccionarse visualmente durante las pruebas retrospectivas.
Diferencias respecto al Asesor Experto
Las opciones de administración de dinero (ENUM_LOT_OR_RISK, paradas dinámicas, comprobaciones de nivel de congelación) no se reproducen. Los usuarios de StockSharp pueden adjuntar su propia lógica de protección o módulos de riesgo.
Las confirmaciones comerciales, las verificaciones de números mágicos y las colas de pedidos manuales de EA son innecesarias porque StockSharp administra los ciclos de vida de los pedidos de manera diferente. La estrategia supone la disponibilidad inmediata de órdenes de mercado.
Las órdenes de stop-loss y take-profit no se adjuntan automáticamente. Utilice StartProtection o módulos externos si ese comportamiento es necesario.
Consejos de uso
Mantenga MiddleLevel cerca de 50 para permanecer fiel al comportamiento original de reversión a la media. Desviarse de este valor empuja al sistema hacia operaciones de ruptura.
Habilite OnlyOnePosition si prefiere transiciones estrictas de plano a posición. Deshabilítelo para permitir la pirámide con lógica de volumen personalizada.
Combine el filtro de tiempo con el horario de operaciones de bolsa cuando trabaje con futuros o acciones para evitar el ruido nocturno.
Optimice MaPeriod, RsiPeriod y MiddleLevel juntos al adaptar la estrategia a nuevos instrumentos.
Con estas notas puede ejecutar, personalizar y ampliar con confianza la estrategia RSI MA en RSI Paso de llenado dentro del entorno StockSharp.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// RSI crossing its own moving average with trade signals.
/// Converted from the MetaTrader expert advisor "RSI_MAonRSI_Filling Step EA.mq5".
/// </summary>
public class RsiMaOnRsiFillingStepStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _maPeriod;
private RelativeStrengthIndex _rsi;
private readonly Queue<decimal> _rsiHistory = new();
private decimal? _previousRsi;
private decimal? _previousSignal;
/// <summary>
/// Initializes a new instance of <see cref="RsiMaOnRsiFillingStepStrategy"/>.
/// </summary>
public RsiMaOnRsiFillingStepStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for RSI calculations.", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Number of bars for the RSI smoothing window.", "Indicators");
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Length of the moving average applied to the RSI.", "Indicators");
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// RSI averaging period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// Moving average period applied to the RSI output.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousRsi = null;
_previousSignal = null;
_rsiHistory.Clear();
_rsi = null!;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previousRsi = null;
_previousSignal = null;
_rsiHistory.Clear();
_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_rsi, ProcessCandle)
.Start();
var priceArea = CreateChartArea();
if (priceArea != null)
{
DrawCandles(priceArea, subscription);
DrawOwnTrades(priceArea);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
// Accumulate RSI values for moving average calculation
_rsiHistory.Enqueue(rsiValue);
while (_rsiHistory.Count > MaPeriod)
_rsiHistory.Dequeue();
if (!_rsi.IsFormed)
return;
// Need enough RSI values to compute the MA
if (_rsiHistory.Count < MaPeriod)
{
_previousRsi = rsiValue;
return;
}
// Calculate simple moving average of RSI
var sum = 0m;
var history = _rsiHistory.ToArray();
foreach (var v in history)
sum += v;
var signalValue = sum / MaPeriod;
if (_previousRsi is null || _previousSignal is null)
{
_previousRsi = rsiValue;
_previousSignal = signalValue;
return;
}
var crossUp = _previousRsi < _previousSignal && rsiValue > signalValue;
var crossDown = _previousRsi > _previousSignal && rsiValue < signalValue;
var volume = Volume;
if (volume <= 0)
volume = 1;
if (crossUp)
{
if (Position <= 0)
BuyMarket(volume);
}
else if (crossDown)
{
if (Position >= 0)
SellMarket(volume);
}
_previousRsi = rsiValue;
_previousSignal = signalValue;
}
}
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_ma_on_rsi_filling_step_strategy(Strategy):
def __init__(self):
super(rsi_ma_on_rsi_filling_step_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._ma_period = self.Param("MaPeriod", 20)
self._rsi_history = []
self._prev_rsi = 0.0
self._prev_signal = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
def OnReseted(self):
super(rsi_ma_on_rsi_filling_step_strategy, self).OnReseted()
self._rsi_history = []
self._prev_rsi = 0.0
self._prev_signal = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(rsi_ma_on_rsi_filling_step_strategy, self).OnStarted2(time)
self._rsi_history = []
self._prev_rsi = 0.0
self._prev_signal = 0.0
self._has_prev = False
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._process_candle).Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
# Accumulate RSI values for moving average
self._rsi_history.append(rsi_val)
ma_len = self.MaPeriod
while len(self._rsi_history) > ma_len:
self._rsi_history.pop(0)
# Need enough RSI values to compute the MA
if len(self._rsi_history) < ma_len:
self._prev_rsi = rsi_val
return
# Calculate SMA of RSI
signal_val = sum(self._rsi_history) / ma_len
if self._has_prev:
cross_up = self._prev_rsi < self._prev_signal and rsi_val > signal_val
cross_down = self._prev_rsi > self._prev_signal and rsi_val < signal_val
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_rsi = rsi_val
self._prev_signal = signal_val
self._has_prev = True
def CreateClone(self):
return rsi_ma_on_rsi_filling_step_strategy()