Color Zerolag RVI Strategy
This strategy uses the Relative Vigor Index and its signal line. It buys when the main RVI line crosses below the signal line and sells when the main line crosses above the signal line.
Details
- Entry Criteria: Cross of RVI and signal line
- Long/Short: Both
- Exit Criteria: Opposite signal
- Stops: No
- Default Values:
RviLength= 14SignalLength= 9BuyOpen= trueSellOpen= trueBuyClose= trueSellClose= trueCandleType= 4 hours
- Filters:
- Category: Oscillator
- Direction: Both
- Indicators: RVI, SMA
- Stops: No
- Complexity: Basic
- Timeframe: Intraday (H4)
- Seasonality: No
- Neural networks: No
- Divergence: No
- Risk level: Medium
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>
/// Strategy based on crossing of RVI and its signal line.
/// Buys on RVI crossing above signal, sells on crossing below.
/// </summary>
public class ColorZerolagRviStrategy : Strategy
{
private readonly StrategyParam<int> _rviLength;
private readonly StrategyParam<int> _signalLength;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevRvi;
private decimal? _prevSignal;
public int RviLength { get => _rviLength.Value; set => _rviLength.Value = value; }
public int SignalLength { get => _signalLength.Value; set => _signalLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorZerolagRviStrategy()
{
_rviLength = Param(nameof(RviLength), 14)
.SetGreaterThanZero()
.SetDisplay("RVI Length", "RVI calculation period", "Indicator");
_signalLength = Param(nameof(SignalLength), 9)
.SetGreaterThanZero()
.SetDisplay("Signal Length", "RVI signal line period", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRvi = null;
_prevSignal = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rvi = new RelativeVigorIndex();
rvi.Average.Length = RviLength;
rvi.Signal.Length = SignalLength;
SubscribeCandles(CandleType)
.BindEx(rvi, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue rviValue)
{
if (candle.State != CandleStates.Finished)
return;
var value = (IRelativeVigorIndexValue)rviValue;
if (value.Average is not decimal rvi || value.Signal is not decimal signal)
return;
if (_prevRvi is null || _prevSignal is null)
{
_prevRvi = rvi;
_prevSignal = signal;
return;
}
var crossUp = _prevRvi < _prevSignal && rvi > signal;
var crossDown = _prevRvi > _prevSignal && rvi < signal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevRvi = rvi;
_prevSignal = signal;
}
}
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 color_zerolag_rvi_strategy(Strategy):
def __init__(self):
super(color_zerolag_rvi_strategy, self).__init__()
self._rvi_length = self.Param("RviLength", 14) \
.SetDisplay("RVI Length", "RVI calculation period", "Indicator")
self._signal_length = self.Param("SignalLength", 9) \
.SetDisplay("Signal Length", "RVI signal line period", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_rvi = None
self._prev_signal = None
@property
def RviLength(self):
return self._rvi_length.Value
@RviLength.setter
def RviLength(self, value):
self._rvi_length.Value = value
@property
def SignalLength(self):
return self._signal_length.Value
@SignalLength.setter
def SignalLength(self, value):
self._signal_length.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(color_zerolag_rvi_strategy, self).OnStarted2(time)
rvi = RelativeVigorIndex()
rvi.Average.Length = self.RviLength
rvi.Signal.Length = self.SignalLength
self.SubscribeCandles(self.CandleType) \
.BindEx(rvi, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, rvi_value):
if candle.State != CandleStates.Finished:
return
avg_raw = rvi_value.Average
sig_raw = rvi_value.Signal
if avg_raw is None or sig_raw is None:
return
rvi_val = float(avg_raw)
signal_val = float(sig_raw)
if self._prev_rvi is None or self._prev_signal is None:
self._prev_rvi = rvi_val
self._prev_signal = signal_val
return
cross_up = self._prev_rvi < self._prev_signal and rvi_val > signal_val
cross_down = self._prev_rvi > self._prev_signal and rvi_val < signal_val
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_rvi = rvi_val
self._prev_signal = signal_val
def OnReseted(self):
super(color_zerolag_rvi_strategy, self).OnReseted()
self._prev_rvi = None
self._prev_signal = None
def CreateClone(self):
return color_zerolag_rvi_strategy()