Ver no GitHub

RSI MA em RSI Estratégia Dupla

Visão geral

O RSI MA em RSI estratégia dupla recria o MetaTrader consultor especialista "RSI_MAonRSI_Dual" dentro de StockSharp. Ele observa dois índices de força relativa com diferentes períodos de lookback e aplica uma média móvel comum no topo de cada fluxo RSI. As decisões de negociação são tomadas quando as linhas RSI suavizadas se cruzam enquanto permanecem no mesmo lado de um nível neutro configurável.

A conversão mantém o comportamento do robô original, incluindo filtragem de tempo e a capacidade de restringir a direção de negociação ou reverter a lógica do sinal.

Indicadores

  • Rápido RSI – Índice de Força Relativa com período configurável.
  • Lento RSI – Índice de Força Relativa com período próprio.
  • Média móvel em RSI – Média móvel simples calculada sobre cada fluxo de valor RSI. Ambos os RSIs usam o mesmo comprimento de suavização.

Todos os três indicadores compartilham o mesmo preço aplicado (preço de fechamento por padrão). As duas linhas RSI suavizadas são desenhadas em um painel gráfico dedicado para monitoramento.

Regras de entrada

  1. Aguarde até que ambos os valores RSI suavizados se formem na barra atualmente concluída.
  2. Configuração longa
    • O RSI suavizado rápido cruza acima o RSI suavizado lentamente (valor atual acima, valor anterior abaixo).
    • Ambos os RSIs suavizados estão abaixo do nível neutro (50 por padrão).
  3. Configuração curta
    • O RSI suavizado rápido cruza abaixo o RSI suavizado lentamente (valor atual abaixo, valor anterior acima).
    • Ambos os RSIs suavizados estão acima do nível neutro.
  4. Opcionalmente, inverta as direções do sinal usando o parâmetro ReverseSignals.
  5. Os sinais gerados na mesma barra são ignorados (uma entrada por barra).

Gestão de posição

  • AllowLong e AllowShort controlam se a estratégia pode abrir posições em cada direção.
  • CloseOpposite fecha uma posição existente antes de entrar no lado oposto, replicando a lógica original EA.
  • OnlyOnePosition proíbe a abertura de uma nova posição quando qualquer posição já estiver ativa.
  • As ordens de mercado são emitidas com a estratégia Volume.

Filtro de tempo

Ative ou desative o filtro da sessão de negociação com UseTimeFilter. Quando ativado, as negociações são permitidas apenas entre SessionStart e SessionEnd. Sessões que ultrapassam a meia-noite são suportadas. Os carimbos de data/hora são avaliados no fuso horário de troca fornecido pelas mensagens de vela recebidas.

Parâmetros

Nome Descrição
CandleType Série de velas analisada pela estratégia.
FastRsiPeriod Período do jejum RSI.
SlowRsiPeriod Período da lentidão RSI.
MaPeriod Comprimento médio móvel usado para suavizar ambos os fluxos RSI.
AppliedPrice Tipo de preço encaminhado para os cálculos de RSI.
NeutralLevel RSI limite que separa as zonas de alta e de baixa.
AllowLong / AllowShort Ative ou desative a direção de negociação.
ReverseSignals Troque sinais longos e curtos.
CloseOpposite Feche a posição oposta antes de inserir uma nova.
OnlyOnePosition Permitir no máximo uma posição aberta.
UseTimeFilter Ative o filtro da sessão de negociação.
SessionStart / SessionEnd Limites da janela de negociação.

Diferenças do original EA

  • Os blocos de gerenciamento de dinheiro, stop-loss e trailing-stop do código MQL5 original não são reproduzidos. A estratégia StockSharp coloca ordens de mercado usando o Volume fixo configurado na estratégia.
  • Todos os alertas de registro e diagnóstico foram removidos; O registro StockSharp deve ser usado, se necessário.
  • O rastreamento de transações específico da plataforma é substituído por StockSharp eventos de estado de pedido.

Apesar dessas diferenças, a lógica de entrada principal e os filtros direcionais correspondem ao consultor especialista de origem.

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;
	}
}