Ver no GitHub

Estratégia Especialista RSI Stochastic MA

Visão geral

A Estratégia Especialista RSI Stochastic MA é uma conversão do consultor especialista MetaTrader 5 Expert_RSI_Stochastic_MA.mq5. A implementação em C# aproveita a API de estratégias de alto nível do StockSharp enquanto reproduz a lógica original: um filtro de tendência baseado em uma média móvel configurável, confirmação de momentum do RSI, e um oscilador Stochastic de linha dupla para timing preciso. O comportamento de proteção replica o algoritmo fonte com um limite de perda fixo opcional e uma saída trailing orientada por Stochastic.

Indicadores e Parâmetros

A estratégia expõe as mesmas entradas que a versão MetaTrader e mantém seus valores padrão. Todos os parâmetros estão disponíveis para otimização através da UI do StockSharp.

Categoria Parâmetro Padrão Descrição
Geral CandleType Período de 15 minutos Agregação de velas usada para cálculos de indicadores.
Trading TradeVolume 0.01 Tamanho base do pedido em lotes/contratos.
RSI RsiPeriod 3 Número de barras usadas para calcular o RSI.
RSI RsiPriceType Fechamento Preço aplicado para RSI (fechamento, abertura, máximo, mínimo, mediano, típico, ponderado).
RSI RsiUpperLevel 80 Limite de sobrecompra que aciona condições vendidas.
RSI RsiLowerLevel 20 Limite de sobrevenda que aciona condições compradas.
Stochastic StochKPeriod 6 Período da linha %K.
Stochastic StochDPeriod 3 Período da linha de suavização %D.
Stochastic StochSlowing 3 Fator de desaceleração adicional aplicado a %K.
Stochastic StochUpperLevel 70 Nível de sobrecompra compartilhado por ambas as linhas Stochastic.
Stochastic StochLowerLevel 30 Nível de sobrevenda compartilhado por ambas as linhas Stochastic.
Média Móvel MaMethod Simples Tipo de média móvel (simples, exponencial, suavizada, ponderada).
Média Móvel MaPriceType Fechamento Preço aplicado para a média móvel.
Média Móvel MaPeriod 150 Comprimento da média móvel.
Média Móvel MaShift 0 Número de barras completadas usadas para deslocar o valor da média móvel para trás.
Risco AllowLossPoints 30 Máxima excursão adversa em pontos antes de sair de uma operação perdedora (0 desabilita).
Risco TrailingStopPoints 30 Distância em pontos para o stop trailing baseado em Stochastic (0 fecha no Stochastic sem trailing).

Cálculo de pontos – A implementação converte os parâmetros AllowLoss e TrailingStop em preços absolutos usando Security.PriceStep. Quando o instrumento tem 3 ou 5 casas decimais, o valor é multiplicado por 10 para emular o tratamento de pips do MetaTrader.

Lógica de Trading

Configuração Comprado

  1. Filtro de tendência – O fechamento da vela deve permanecer acima da média móvel deslocada.
  2. Confirmação de momentum – RSI deve estar abaixo de RsiLowerLevel.
  3. Timing – Ambas as linhas Stochastic (%K e %D) devem estar abaixo de StochLowerLevel.
  4. Filtro de posição – Ordens compradas só são colocadas quando não existe exposição comprada (Position <= 0). O tamanho do pedido é TradeVolume mais qualquer quantidade necessária para fechar uma posição vendida existente.

Configuração Vendido

  1. Filtro de tendência – O fechamento da vela deve estar abaixo da média móvel deslocada.
  2. Confirmação de momentum – RSI deve exceder RsiUpperLevel.
  3. Timing – Ambas as linhas Stochastic devem estar acima de StochUpperLevel.
  4. Filtro de posição – Novas posições vendidas requerem Position >= 0. A estratégia compensa comprados existentes automaticamente se necessário.

Gestão de Saídas

  • Operações perdedoras
    • Quando AllowLossPoints é zero, a estratégia aguarda que a linha principal do Stochastic se mova para o extremo oposto (StochUpperLevel para comprados, StochLowerLevel para vendidos) antes de fechar operações negativas.
    • Quando AllowLossPoints é positivo, a estratégia converte o valor em um deslocamento de preço e fecha a operação assim que a perda exceder este limite e o Stochastic retornar à zona neutra (stochMain > StochLowerLevel para comprados, < StochUpperLevel para vendidos).
  • Saída trailing
    • Com TrailingStopPoints > 0, uma vez que uma operação é lucrativa e o Stochastic atinge sua zona extrema, um stop trailing é definido em cada vela finalizada. Para operações compradas, o stop segue abaixo do preço; para vendidas, segue acima.
    • Com TrailingStopPoints = 0, operações lucrativas são fechadas imediatamente quando o Stochastic atinge o nível extremo (correspondendo ao comportamento do EA original).
  • Gatilho de trailing – As atualizações de trailing ocorrem apenas em velas completadas, espelhando a implementação MQL que restringia atualizações a uma por barra.

Notas de Implementação

  • O deslocamento da média móvel é tratado armazenando valores recentes e lendo o valor MaShift barras atrás, reproduzindo o parâmetro shift do MetaTrader.
  • As entradas de RSI e média móvel suportam múltiplos preços aplicados para corresponder às opções do MetaTrader. Os cálculos do Stochastic dependem do oscilador integrado do StockSharp (modo Low/High) e respeitam os comprimentos de suavização configurados.
  • Os limites de trailing e perda são medidos em pontos. O auxiliar escala automaticamente o valor para tamanhos de tick típicos de FX (3 ou 5 decimais) e por padrão usa um PriceStep.
  • A saída do gráfico inclui velas, a média móvel, RSI e indicadores Stochastic, permitindo validação visual semelhante ao modelo original.
  • Não há versão Python adjunta por solicitação; apenas a implementação em C# é fornecida.

Dicas de Uso

  • Ao implantar em ativos com tamanhos de tick não convencionais, verifique se Security.PriceStep está preenchido; caso contrário, a conversão padrão será usada (1 ponto = 1 unidade de preço).
  • Combine o StartProtection integrado ou módulos de risco adicionais se for necessário mais gerenciamento de stop-loss ou take-profit.
  • Otimize os comprimentos dos indicadores e os limites de risco juntos — a estratégia expõe intencionalmente todos os controles primários do especialista MetaTrader.
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>
/// Combines an SMA trend filter with RSI and Stochastic oscillators.
/// Enters long when price is above SMA, RSI is oversold and Stochastic is oversold.
/// Enters short when price is below SMA, RSI is overbought and Stochastic is overbought.
/// </summary>
public class ExpertRsiStochasticMaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiUpperLevel;
	private readonly StrategyParam<decimal> _rsiLowerLevel;
	private readonly StrategyParam<int> _stochKPeriod;
	private readonly StrategyParam<int> _stochDPeriod;
	private readonly StrategyParam<decimal> _stochUpperLevel;
	private readonly StrategyParam<decimal> _stochLowerLevel;
	private readonly StrategyParam<int> _maPeriod;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public decimal RsiUpperLevel
	{
		get => _rsiUpperLevel.Value;
		set => _rsiUpperLevel.Value = value;
	}

	public decimal RsiLowerLevel
	{
		get => _rsiLowerLevel.Value;
		set => _rsiLowerLevel.Value = value;
	}

	public int StochKPeriod
	{
		get => _stochKPeriod.Value;
		set => _stochKPeriod.Value = value;
	}

	public int StochDPeriod
	{
		get => _stochDPeriod.Value;
		set => _stochDPeriod.Value = value;
	}

	public decimal StochUpperLevel
	{
		get => _stochUpperLevel.Value;
		set => _stochUpperLevel.Value = value;
	}

	public decimal StochLowerLevel
	{
		get => _stochLowerLevel.Value;
		set => _stochLowerLevel.Value = value;
	}

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	public ExpertRsiStochasticMaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Time frame used for calculations", "General");

		_rsiPeriod = Param(nameof(RsiPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "Number of bars for RSI", "RSI");

		_rsiUpperLevel = Param(nameof(RsiUpperLevel), 80m)
			.SetDisplay("RSI Overbought", "Upper RSI threshold", "RSI");

		_rsiLowerLevel = Param(nameof(RsiLowerLevel), 20m)
			.SetDisplay("RSI Oversold", "Lower RSI threshold", "RSI");

		_stochKPeriod = Param(nameof(StochKPeriod), 6)
			.SetGreaterThanZero()
			.SetDisplay("%K Period", "Length of Stochastic %K", "Stochastic");

		_stochDPeriod = Param(nameof(StochDPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("%D Period", "Length of Stochastic %D", "Stochastic");

		_stochUpperLevel = Param(nameof(StochUpperLevel), 70m)
			.SetDisplay("Stoch Overbought", "Upper Stochastic threshold", "Stochastic");

		_stochLowerLevel = Param(nameof(StochLowerLevel), 30m)
			.SetDisplay("Stoch Oversold", "Lower Stochastic threshold", "Stochastic");

		_maPeriod = Param(nameof(MaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Length of moving average", "Moving Average");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var sma = new SMA { Length = MaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var stoch = new StochasticOscillator();
		stoch.K.Length = StochKPeriod;
		stoch.D.Length = StochDPeriod;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(sma, rsi, stoch, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, sma);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue smaValue, IIndicatorValue rsiValue, IIndicatorValue stochValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!smaValue.IsFinal || !rsiValue.IsFinal || !stochValue.IsFinal)
			return;

		var sma = smaValue.IsEmpty ? (decimal?)null : smaValue.GetValue<decimal>();
		var rsiVal = rsiValue.IsEmpty ? (decimal?)null : rsiValue.GetValue<decimal>();

		if (sma is not decimal smaDecimal || rsiVal is not decimal rsiDecimal)
			return;

		var stoch = (StochasticOscillatorValue)stochValue;
		if (stoch.K is not decimal stochK || stoch.D is not decimal stochD)
			return;

		var price = candle.ClosePrice;

		// Long entry: price above SMA, RSI oversold, Stochastic oversold
		if (price > smaDecimal && rsiDecimal < RsiLowerLevel && stochK < StochLowerLevel && stochD < StochLowerLevel)
		{
			if (Position <= 0)
				BuyMarket();
		}
		// Short entry: price below SMA, RSI overbought, Stochastic overbought
		else if (price < smaDecimal && rsiDecimal > RsiUpperLevel && stochK > StochUpperLevel && stochD > StochUpperLevel)
		{
			if (Position >= 0)
				SellMarket();
		}
		// Exit long: Stochastic overbought
		else if (Position > 0 && stochK > StochUpperLevel)
		{
			SellMarket();
		}
		// Exit short: Stochastic oversold
		else if (Position < 0 && stochK < StochLowerLevel)
		{
			BuyMarket();
		}
	}
}