Ver no GitHub

Estratégia de Reversão do Histograma RVI

Visão geral

Esta estratégia opera contra valores extremos do RVI. Opera com o Índice de Vigor Relativo (RVI) e abre posições quando o indicador abandona zonas de sobrecompra ou sobrevenda, ou quando o RVI cruza a sua linha de sinal. Dois modos de sinal são suportados:

  • Levels – reage quando o RVI cruza limiares superiores ou inferiores predefinidos.
  • Cross – reage quando o RVI cruza a sua linha de sinal.

A lógica é contrária: se o RVI estava acima do nível alto e depois desce, abre-se uma posição comprada. Se o RVI estava abaixo do nível baixo e depois sobe, abre-se uma posição vendida.

Parâmetros

Nome Descrição
RviPeriod Período de cálculo do RVI.
HighLevel Limiar superior do RVI.
LowLevel Limiar inferior do RVI.
Mode Modo de geração de sinal (Levels ou Cross).
EnableBuyOpen Permitir abertura de posições compradas.
EnableSellOpen Permitir abertura de posições vendidas.
EnableBuyClose Permitir fecho de posições compradas.
EnableSellClose Permitir fecho de posições vendidas.
CandleType Período do ローソク足.

Como funciona

  1. O RVI e a sua média móvel simples são calculados em cada vela concluída.
  2. Dependendo do modo selecionado, a estratégia verifica:
    • se o RVI abandona um nível extremo, ou
    • se o RVI cruza a sua linha de sinal.
  3. Com um sinal comprado, a estratégia fecha posições vendidas e abre uma posição comprada. Com um sinal vendido, fecha posições compradas e abre uma posição vendida.

O período padrão é de quatro horas.

Notas

  • As ordens são executadas com ordens de mercado.
  • A gestão de stop-loss e take-profit pode ser adicionada separadamente se necessário.
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>
/// RVI histogram reversal strategy.
/// Opens long when RVI Average crosses above Signal.
/// Opens short when RVI Average crosses below Signal.
/// </summary>
public class RviHistogramReversalStrategy : Strategy
{
	private readonly StrategyParam<int> _rviPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevAvg;
	private decimal? _prevSig;

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

	public RviHistogramReversalStrategy()
	{
		_rviPeriod = Param(nameof(RviPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RVI Period", "Period of RVI indicator", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevAvg = null;
		_prevSig = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var rvi = new RelativeVigorIndex();
		rvi.Average.Length = RviPeriod;
		rvi.Signal.Length = RviPeriod;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(rvi, ProcessCandle)
			.Start();

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

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

		var rviVal = value as IRelativeVigorIndexValue;
		if (rviVal?.Average is not decimal avg || rviVal?.Signal is not decimal sig)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevAvg = avg;
			_prevSig = sig;
			return;
		}

		if (_prevAvg is decimal pa && _prevSig is decimal ps)
		{
			// Average crosses above Signal - buy
			if (pa <= ps && avg > sig && Position <= 0)
				BuyMarket();
			// Average crosses below Signal - sell
			else if (pa >= ps && avg < sig && Position >= 0)
				SellMarket();
		}

		_prevAvg = avg;
		_prevSig = sig;
	}
}