Ver no GitHub

Estratégia JBrainUltraRSI

Esta estratégia de exemplo combina o Índice de Força Relativa (RSI) e o oscilador Estocástico para gerar sinais de negociação. A ideia é derivada do Consultor Especialista original do MetaTrader que usava os indicadores JBrainTrendSig1 e UltraRSI. Nesta adaptação, o oscilador Estocástico atua como filtro de tendência enquanto o RSI fornece sinais de entrada.

Como funciona

  1. Indicadores
    • RSI: Mede o momentum comparando ganhos e perdas recentes. Um cruzamento acima do nível 50 indica momentum de alta, enquanto um cruzamento abaixo de 50 indica momentum de baixa.
    • Oscilador Estocástico: Avalia a posição do fechamento em relação ao intervalo recente. Os cruzamentos das linhas %K e %D confirmam a direção da tendência.
  2. Modos
    • JBrainSig1Filter – O RSI gera sinais e o oscilador Estocástico confirma a direção.
    • UltraRsiFilter – O oscilador Estocástico fornece sinais filtrados pelo RSI.
    • Composition – Os sinais são tomados apenas quando ambos os indicadores concordam na direção.
  3. Regras de negociação
    • Uma posição comprada é aberta quando um sinal de compra aparece e a posição vendida está ausente ou fechada.
    • Uma posição vendida é aberta quando um sinal de venda aparece e a posição comprada está ausente ou fechada.
    • Sinais reversos fecham posições existentes se permitido.

Parâmetros

Parâmetro Descrição
RsiPeriod Período de cálculo do RSI.
StochLength Período %K para o oscilador Estocástico.
SignalLength Período %D para o oscilador Estocástico.
Mode Modo de combinação de indicadores.
AllowLongEntry / AllowShortEntry Permissões para abrir posições compradas ou vendidas.
AllowLongExit / AllowShortExit Permissões para fechar posições compradas ou vendidas.
CandleType Período de velas utilizado pela estratégia.

Notas

  • A estratégia usa a API de alto nível do StockSharp com Bind / BindEx para o processamento de indicadores.
  • Stops e alvos podem ser configurados com o mecanismo de proteção integrado StartProtection().
  • A visualização de exemplo desenha velas, indicadores e operações próprias se uma área de gráfico estiver disponível.

using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy combining RSI and Stochastic oscillator signals.
/// </summary>
public class JBrainUltraRsiStrategy : Strategy
{
        /// <summary>
        /// Combination modes for indicators.
        /// </summary>
        public enum AlgorithmModes
        {
                JBrainSig1Filter,
                UltraRsiFilter,
                Composition
        }

	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _stochLength;
	private readonly StrategyParam<int> _signalLength;
	private readonly StrategyParam<AlgorithmModes> _mode;
	private readonly StrategyParam<bool> _allowLongEntry;
	private readonly StrategyParam<bool> _allowShortEntry;
	private readonly StrategyParam<bool> _allowLongExit;
	private readonly StrategyParam<bool> _allowShortExit;
	private readonly StrategyParam<DataType> _candleType;
	
	private RelativeStrengthIndex _rsi;
	private StochasticOscillator _stochastic;
	private decimal? _prevRsi;
	private decimal? _prevK;
	private decimal? _prevD;
	
	/// <summary>
	/// RSI calculation period.
	/// </summary>
	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}
	
	/// <summary>
	/// Stochastic %K period.
	/// </summary>
	public int StochLength
	{
		get => _stochLength.Value;
		set => _stochLength.Value = value;
	}
	
	/// <summary>
	/// Stochastic %D period.
	/// </summary>
	public int SignalLength
	{
		get => _signalLength.Value;
		set => _signalLength.Value = value;
	}
	
	/// <summary>
	/// Mode combining indicators.
	/// </summary>
	public AlgorithmModes Mode
	{
		get => _mode.Value;
		set => _mode.Value = value;
	}
	
	/// <summary>
	/// Permission to open long positions.
	/// </summary>
	public bool AllowLongEntry
	{
		get => _allowLongEntry.Value;
		set => _allowLongEntry.Value = value;
	}
	
	/// <summary>
	/// Permission to open short positions.
	/// </summary>
	public bool AllowShortEntry
	{
		get => _allowShortEntry.Value;
		set => _allowShortEntry.Value = value;
	}
	
	/// <summary>
	/// Permission to close long positions.
	/// </summary>
	public bool AllowLongExit
	{
		get => _allowLongExit.Value;
		set => _allowLongExit.Value = value;
	}
	
	/// <summary>
	/// Permission to close short positions.
	/// </summary>
	public bool AllowShortExit
	{
		get => _allowShortExit.Value;
		set => _allowShortExit.Value = value;
	}
	
	/// <summary>
	/// Candle type to process.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}
	
	/// <summary>
	/// Initializes a new instance of <see cref="JBrainUltraRsiStrategy"/>.
	/// </summary>
	public JBrainUltraRsiStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 13)
		.SetGreaterThanZero()
		.SetDisplay("RSI Period", "RSI calculation period", "Indicators")
		;
		
		_stochLength = Param(nameof(StochLength), 9)
		.SetGreaterThanZero()
		.SetDisplay("Stochastic %K", "Period for %K line", "Indicators")
		;
		
		_signalLength = Param(nameof(SignalLength), 3)
		.SetGreaterThanZero()
		.SetDisplay("Stochastic %D", "Period for %D line", "Indicators")
		;
		
		_mode = Param(nameof(Mode), AlgorithmModes.Composition)
		.SetDisplay("Mode", "Algorithm to enter the market", "General");
		
		_allowLongEntry = Param(nameof(AllowLongEntry), true)
		.SetDisplay("Allow Long Entry", "Permission to open long positions", "Trading");
		
		_allowShortEntry = Param(nameof(AllowShortEntry), true)
		.SetDisplay("Allow Short Entry", "Permission to open short positions", "Trading");
		
		_allowLongExit = Param(nameof(AllowLongExit), true)
		.SetDisplay("Allow Long Exit", "Permission to close long positions", "Trading");
		
		_allowShortExit = Param(nameof(AllowShortExit), true)
		.SetDisplay("Allow Short Exit", "Permission to close short positions", "Trading");
		
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
		.SetDisplay("Candle Type", "Type of candles", "General");
	}
	
	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}
	
	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		
		_rsi = default;
		_stochastic = default;
		_prevRsi = default;
		_prevK = default;
		_prevD = default;
	}
	
	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		
		StartProtection(null, null);
		
		_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		_stochastic = new StochasticOscillator
		{
			K = { Length = StochLength },
			D = { Length = SignalLength },
		};
		
		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(_stochastic, ProcessCandle)
			.Start();

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

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

		// process RSI manually
		var rsiResult = _rsi.Process(candle.ClosePrice, candle.OpenTime, true);
		if (!rsiResult.IsFormed)
			return;

		var rsi = rsiResult.ToDecimal();

		var stoch = (StochasticOscillatorValue)stochValue;
		if (stoch.K is not decimal k || stoch.D is not decimal d)
		{
			_prevRsi = rsi;
			return;
		}

		var rsiUp = _prevRsi is decimal pr && pr <= 50m && rsi > 50m;
		var rsiDown = _prevRsi is decimal pr2 && pr2 >= 50m && rsi < 50m;
		var stochUp = _prevK is decimal pk && _prevD is decimal pd && pk <= pd && k > d;
		var stochDown = _prevK is decimal pk2 && _prevD is decimal pd2 && pk2 >= pd2 && k < d;

		var buySignal = false;
		var sellSignal = false;

		switch (Mode)
		{
			case AlgorithmModes.JBrainSig1Filter:
				buySignal = rsiUp && k > d;
				sellSignal = rsiDown && k < d;
				break;
			case AlgorithmModes.UltraRsiFilter:
				buySignal = stochUp && rsi > 50m;
				sellSignal = stochDown && rsi < 50m;
				break;
			case AlgorithmModes.Composition:
				buySignal = rsiUp && stochUp;
				sellSignal = rsiDown && stochDown;
				break;
		}

		if (buySignal)
		{
			if (Position < 0 && AllowShortExit)
				BuyMarket();
			if (AllowLongEntry && Position <= 0)
				BuyMarket();
		}
		else if (sellSignal)
		{
			if (Position > 0 && AllowLongExit)
				SellMarket();
			if (AllowShortEntry && Position >= 0)
				SellMarket();
		}

		_prevRsi = rsi;
		_prevK = k;
		_prevD = d;
	}
}