三重 RVI 策略
该策略在三个不同时间框架上使用 相对活力指数 (RVI) 进行交易。较长周期的 RVI 趋势用作过滤器,最短周期用于生成入场信号。当短周期 RVI 向下穿越其信号线且两个较长期框架保持看涨时开多;当短周期 RVI 向上穿越其信号线且两个较长期框架保持看空时开空。当任一时间框架出现与当前持仓相反的趋势时,平掉持仓。
参数
- RviPeriod – RVI 计算周期。
- CandleType1 – 最高级别过滤器的时间框架。
- CandleType2 – 中间级别过滤器的时间框架。
- CandleType3 – 生成交易信号的时间框架。
- Volume – 市价单使用的下单数量。
说明
- 仅处理已经完成的 K 线。
- 策略使用 StockSharp 高级 API 编写。
- 默认时间框架分别为 30、15 和 5 分钟。
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 that trades using Relative Vigor Index with multiple period confirmations.
/// Uses a long-period RVI for trend, mid-period for confirmation, and short for entry.
/// </summary>
public class TripleRviStrategy : Strategy
{
private readonly StrategyParam<int> _rviPeriod;
private readonly StrategyParam<DataType> _candleType;
private int _trend1;
private int _trend2;
private decimal _prevSignal = decimal.MinValue;
public int RviPeriod { get => _rviPeriod.Value; set => _rviPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TripleRviStrategy()
{
_rviPeriod = Param(nameof(RviPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("RVI Period", "Base period of RVI", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Trading timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_trend1 = 0;
_trend2 = 0;
_prevSignal = decimal.MinValue;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_trend1 = 0;
_trend2 = 0;
_prevSignal = decimal.MinValue;
var trendRsi = new RelativeStrengthIndex { Length = RviPeriod * 3 };
var midRsi = new RelativeStrengthIndex { Length = RviPeriod * 2 };
var signalRsi = new RelativeStrengthIndex { Length = RviPeriod };
var sub = SubscribeCandles(CandleType);
sub.Bind(trendRsi, midRsi, signalRsi, ProcessCandle).Start();
StartProtection(
new Unit(2000m, UnitTypes.Absolute),
new Unit(1000m, UnitTypes.Absolute));
}
private void ProcessCandle(ICandleMessage candle, decimal trendValue, decimal midValue, decimal signalValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
_trend1 = trendValue > 55m ? 1 : trendValue < 45m ? -1 : 0;
_trend2 = midValue > 55m ? 1 : midValue < 45m ? -1 : 0;
if (_prevSignal == decimal.MinValue)
{
_prevSignal = signalValue;
return;
}
var crossUp = _prevSignal <= 50m && signalValue > 50m;
var crossDown = _prevSignal >= 50m && signalValue < 50m;
if (crossUp && _trend1 > 0 && _trend2 > 0 && Position <= 0)
BuyMarket();
else if (crossDown && _trend1 < 0 && _trend2 < 0 && Position >= 0)
SellMarket();
if (Position > 0 && (_trend1 < 0 || _trend2 < 0))
SellMarket();
else if (Position < 0 && (_trend1 > 0 || _trend2 > 0))
BuyMarket();
_prevSignal = signalValue;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class triple_rvi_strategy(Strategy):
def __init__(self):
super(triple_rvi_strategy, self).__init__()
self._rvi_period = self.Param("RviPeriod", 10)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._trend1 = 0
self._trend2 = 0
self._prev_signal = None
@property
def RviPeriod(self): return self._rvi_period.Value
@RviPeriod.setter
def RviPeriod(self, v): self._rvi_period.Value = v
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
def OnStarted2(self, time):
super(triple_rvi_strategy, self).OnStarted2(time)
self._trend1 = 0
self._trend2 = 0
self._prev_signal = None
trend_rsi = RelativeStrengthIndex()
trend_rsi.Length = self.RviPeriod * 3
mid_rsi = RelativeStrengthIndex()
mid_rsi.Length = self.RviPeriod * 2
signal_rsi = RelativeStrengthIndex()
signal_rsi.Length = self.RviPeriod
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(trend_rsi, mid_rsi, signal_rsi, self.ProcessCandle).Start()
self.StartProtection(Unit(2000, UnitTypes.Absolute), Unit(1000, UnitTypes.Absolute))
def ProcessCandle(self, candle, trend_value, mid_value, signal_value):
if candle.State != CandleStates.Finished: return
if not self.IsFormedAndOnlineAndAllowTrading(): return
tv = float(trend_value)
mv = float(mid_value)
sv = float(signal_value)
self._trend1 = 1 if tv > 55.0 else (-1 if tv < 45.0 else 0)
self._trend2 = 1 if mv > 55.0 else (-1 if mv < 45.0 else 0)
if self._prev_signal is None:
self._prev_signal = sv
return
cross_up = self._prev_signal <= 50.0 and sv > 50.0
cross_down = self._prev_signal >= 50.0 and sv < 50.0
if cross_up and self._trend1 > 0 and self._trend2 > 0 and self.Position <= 0:
self.BuyMarket()
elif cross_down and self._trend1 < 0 and self._trend2 < 0 and self.Position >= 0:
self.SellMarket()
if self.Position > 0 and (self._trend1 < 0 or self._trend2 < 0):
self.SellMarket()
elif self.Position < 0 and (self._trend1 > 0 or self._trend2 > 0):
self.BuyMarket()
self._prev_signal = sv
def OnReseted(self):
super(triple_rvi_strategy, self).OnReseted()
self._trend1 = 0
self._trend2 = 0
self._prev_signal = None
def CreateClone(self):
return triple_rvi_strategy()