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
O RVI e a sua média móvel simples são calculados em cada vela concluída.
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.
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;
}
}
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 RelativeVigorIndex
from StockSharp.Algo.Strategies import Strategy
class rvi_histogram_reversal_strategy(Strategy):
def __init__(self):
super(rvi_histogram_reversal_strategy, self).__init__()
self._rvi_period = self.Param("RviPeriod", 14).SetDisplay("RVI Period", "Period of RVI indicator", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Type of candles", "General")
self._prev_avg = None
self._prev_sig = None
@property
def rvi_period(self): return self._rvi_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(rvi_histogram_reversal_strategy, self).OnReseted()
self._prev_avg = None
self._prev_sig = None
def OnStarted2(self, time):
super(rvi_histogram_reversal_strategy, self).OnStarted2(time)
rvi = RelativeVigorIndex()
rvi.Average.Length = self.rvi_period
rvi.Signal.Length = self.rvi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(rvi, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rvi)
self.DrawOwnTrades(area)
def process_candle(self, candle, value):
if candle.State != CandleStates.Finished: return
avg = value.Average
sig = value.Signal
if avg is None or sig is None: return
avg = float(avg)
sig = float(sig)
if self._prev_avg is not None and self._prev_sig is not None:
if self._prev_avg <= self._prev_sig and avg > sig and self.Position <= 0:
self.BuyMarket()
elif self._prev_avg >= self._prev_sig and avg < sig and self.Position >= 0:
self.SellMarket()
self._prev_avg = avg
self._prev_sig = sig
def CreateClone(self): return rvi_histogram_reversal_strategy()