Esta estrategia opera contra valores extremos del RVI. Opera con el Índice de Vigor Relativo (RVI) y abre posiciones cuando el indicador abandona zonas de sobrecompra o sobreventa, o cuando el RVI cruza su línea de señal. Se admiten dos modos de señal:
Levels – reacciona cuando el RVI cruza umbrales superiores o inferiores predefinidos.
Cross – reacciona cuando el RVI cruza su línea de señal.
La lógica es contraria a la tendencia: si el RVI estaba por encima del nivel alto y luego cae, se abre una posición larga. Si el RVI estaba por debajo del nivel bajo y luego sube, se abre una posición corta.
Parámetros
Nombre
Descripción
RviPeriod
Período de cálculo del RVI.
HighLevel
Umbral superior del RVI.
LowLevel
Umbral inferior del RVI.
Mode
Modo de generación de señales (Levels o Cross).
EnableBuyOpen
Permitir abrir posiciones largas.
EnableSellOpen
Permitir abrir posiciones cortas.
EnableBuyClose
Permitir cerrar posiciones largas.
EnableSellClose
Permitir cerrar posiciones cortas.
CandleType
Marco temporal de las velas.
Cómo funciona
El RVI y su media móvil simple se calculan en cada vela completada.
Dependiendo del modo seleccionado, la estrategia verifica:
si el RVI abandona un nivel extremo, o
si el RVI cruza su línea de señal.
Con una señal larga, la estrategia cierra posiciones cortas y abre una posición larga. Con una señal corta, cierra posiciones largas y abre una posición corta.
El marco temporal por defecto es de cuatro horas.
Notas
Las órdenes se ejecutan con órdenes de mercado.
La gestión de stop-loss y take-profit puede añadirse por separado si es necesario.
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()