RSI MA em RSI Estratégia de Etapas de Preenchimento
Visão geral
O RSI MA em RSI Filling Step Strategy é uma versão StockSharp do MetaTrader consultor especialista RSI_MAonRSI_Filling Step EA.mq5. O sistema original mede o impulso com um Índice de Força Relativa (RSI) e suaviza esse oscilador com uma média móvel. As negociações são iniciadas quando RSI cruza sua média móvel, enquanto ambos os valores permanecem no mesmo lado do nível 50 intermediário. A conversão mantém os filtros de direção de negociação configuráveis, o temporizador de sessão opcional e a capacidade de reverter os sinais enquanto aproveita as ligações de indicadores de alto nível de StockSharp.
Lógica de negociação
Assine a série de velas selecionada e calcule dois indicadores em cada barra finalizada: RelativeStrengthIndex com comprimento RsiPeriod e MovingAverage (MaType, MaPeriod) aplicados ao fluxo RSI.
Aguarde as velas completas antes de agir, replicando a salvaguarda da "nova barra" do EA para que cada barra produza no máximo uma decisão de negociação.
Uma configuração de alta ocorre quando o valor anterior de RSI estava abaixo de sua média móvel e o valor mais recente fecha acima da média enquanto ambas as leituras permanecem abaixo de MiddleLevel (padrão 50). Uma configuração baixa é o caso espelhado acima do nível médio.
Quando ReverseSignals está ativado, a condição de alta gera uma negociação curta e a condição de baixa gera uma negociação longa, imitando a sinalização reversa de EA.
O parâmetro Mode limita a negociação apenas para compra, venda ou ambas as direções. Guardas adicionais opcionalmente fecham a exposição oposta e bloqueiam novas entradas quando uma posição já está aberta.
Uma janela de tempo diária idêntica à implementação MetaTrader pode desativar sinais fora do intervalo SessionStart → SessionEnd configurado, incluindo sessões que terminam à meia-noite.
Parâmetros
CandleType – série de dados processados pela estratégia. O padrão são velas com intervalo de uma hora.
RsiPeriod – duração média de RSI (padrão 14).
MaPeriod – duração da média móvel aplicada a RSI (padrão 21).
MaType – tipo de média móvel usado para suavização RSI (padrão Simple).
MiddleLevel – nível central RSI usado por ambos os indicadores para validar negociações (padrão 50).
ReverseSignals – inverte a interpretação do cruzamento de alta/baixa (padrão false).
Modo – filtro de direção comercial (BuyOnly, SellOnly, Both).
CloseOppositePositions – se deve nivelar a posição oposta antes de entrar em uma nova negociação (padrão false).
OnlyOnePosition – evita novas ordens enquanto uma posição já estiver aberta (padrão false).
UseTimeWindow – habilita o filtro diário da sessão de negociação (padrão false).
SessionStart / SessionEnd – horários de início e término do pregão permitido. Funciona com sessões noturnas encerrando depois da meia-noite.
Notas de implementação
Os valores do indicador são entregues por meio de Bind, eliminando a necessidade de gerenciamento manual de buffer que o EA original exigia com CopyBuffer.
Os valores anteriores de RSI e de média móvel são armazenados em cache para espelhar o padrão de acesso RSI[m_bar_current+1] de MQL. O campo _lastSignalBarTime garante apenas uma negociação por barra, assim como os carimbos de data e hora m_last_deal_buy_in / m_last_deal_sell_in do EA.
O gerenciamento comercial usa BuyMarket() e SellMarket() para espelhar a execução imediata de mercado do EA. O fechamento opcional da exposição oposta é feito com ClosePosition() antes de fazer o novo pedido.
O filtro de tempo replica a função TimeControlHourMinute do EA, incluindo a lógica da janela noturna em que o horário de início é maior que o horário de término.
Os ajudantes de gráficos desenham velas de preços com marcadores comerciais, além de um painel RSI dedicado para que os cruzamentos possam ser inspecionados visualmente durante os backtests.
Diferenças em comparação com o Expert Advisor
As opções de gerenciamento de dinheiro (ENUM_LOT_OR_RISK, trailing stops, verificações de nível de congelamento) não são reproduzidas. Os usuários do StockSharp podem anexar sua própria lógica de proteção ou módulos de risco.
Confirmações de negociação, verificações de números mágicos e filas manuais de pedidos do EA são desnecessárias porque o StockSharp gerencia os ciclos de vida dos pedidos de maneira diferente. A estratégia pressupõe disponibilidade imediata de ordens de mercado.
As ordens stop-loss e take-profit não são anexadas automaticamente. Use StartProtection ou módulos externos se esse comportamento for necessário.
Dicas de uso
Mantenha MiddleLevel próximo de 50 para permanecer fiel ao comportamento original de reversão à média. Desviar-se desse valor empurra o sistema para uma negociação de ruptura.
Ative OnlyOnePosition se preferir transições rigorosas de horizontal para posição. Desative-o para permitir a pirâmide com lógica de volume personalizada.
Combine o filtro de tempo com o horário de negociação da bolsa ao operar futuros ou ações para evitar ruídos noturnos.
Otimize MaPeriod, RsiPeriod e MiddleLevel juntos ao adaptar a estratégia a novos instrumentos.
Com essas notas, você pode executar, personalizar e estender com segurança a estratégia RSI MA em RSI Filling Step dentro do ambiente 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()