Modelo de Oscilador de Spread de Arbitraje de Volatilidad (VASOM)
Toma una posición larga en el futuro VIX del mes frontal cuando el RSI del spread entre los contratos del primer y segundo mes cae por debajo de un umbral. La posición se cierra cuando el RSI sube por encima de un nivel de salida.
Detalles
- Criterios de entrada: RSI del spread <
LongThreshold. - Largo/Corto: Solo largos.
- Criterios de salida: RSI del spread >
ExitThreshold. - Stops: No.
- Valores predeterminados:
RsiPeriod= 2LongThreshold= 46ExitThreshold= 76CandleType= TimeSpan.FromMinutes(5)SecondSecurity= "CBOE:VX2!"
- Filtros:
- Categoría: Volatilidad
- Dirección: Solo largos
- Indicadores: RSI
- Stops: No
- Complejidad: Principiante
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Volatility Arbitrage Spread Oscillator Model (VASOM).
/// Uses RSI on the spread between two securities to detect mean reversion opportunities.
/// </summary>
public class VolatilityArbitrageSpreadOscillatorModelStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _longThreshold;
private readonly StrategyParam<int> _exitThreshold;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<Security> _secondSecurity;
private decimal _frontClose;
private decimal _secondClose;
private decimal _rsiVal;
private decimal _prevRsi;
private int _cooldown;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int LongThreshold { get => _longThreshold.Value; set => _longThreshold.Value = value; }
public int ExitThreshold { get => _exitThreshold.Value; set => _exitThreshold.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Security SecondSecurity { get => _secondSecurity.Value; set => _secondSecurity.Value = value; }
public VolatilityArbitrageSpreadOscillatorModelStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Length of RSI", "Parameters");
_longThreshold = Param(nameof(LongThreshold), 35)
.SetRange(0, 100)
.SetDisplay("Long Threshold", "RSI level to enter long", "Parameters");
_exitThreshold = Param(nameof(ExitThreshold), 65)
.SetRange(0, 100)
.SetDisplay("Exit Threshold", "RSI level to exit", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "Parameters");
_secondSecurity = Param<Security>(nameof(SecondSecurity))
.SetDisplay("Second Security", "Second security for spread", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
var list = new List<(Security sec, DataType dt)> { (Security, CandleType) };
if (SecondSecurity != null)
list.Add((SecondSecurity, CandleType));
return list;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_frontClose = 0;
_secondClose = 0;
_rsiVal = 0;
_prevRsi = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_frontClose = 0;
_secondClose = 0;
_rsiVal = 0;
_prevRsi = 0;
_cooldown = 0;
var frontSub = SubscribeCandles(CandleType);
frontSub
.Bind(rsi, ProcessFront)
.Start();
if (SecondSecurity != null)
{
var secondSub = SubscribeCandles(CandleType, security: SecondSecurity);
secondSub.Bind(ProcessSecond).Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, frontSub);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessSecond(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_secondClose = candle.ClosePrice;
}
private void ProcessFront(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
_frontClose = candle.ClosePrice;
_prevRsi = _rsiVal;
_rsiVal = rsiValue;
if (_cooldown > 0)
{
_cooldown--;
return;
}
if (_prevRsi == 0)
return;
// Long entry when RSI crosses below threshold
if (_rsiVal < LongThreshold && Position <= 0)
{
BuyMarket();
_cooldown = 45;
}
// Exit long / short entry when RSI crosses above threshold
else if (_rsiVal > ExitThreshold && Position >= 0)
{
SellMarket();
_cooldown = 45;
}
}
}
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class volatility_arbitrage_spread_oscillator_model_strategy(Strategy):
def __init__(self):
super(volatility_arbitrage_spread_oscillator_model_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Length of RSI", "Parameters")
self._long_threshold = self.Param("LongThreshold", 35) \
.SetDisplay("Long Threshold", "RSI level to enter long", "Parameters")
self._exit_threshold = self.Param("ExitThreshold", 65) \
.SetDisplay("Exit Threshold", "RSI level to exit", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles", "Parameters")
self._front_close = 0.0
self._second_close = 0.0
self._rsi_val = 0.0
self._prev_rsi = 0.0
self._cooldown = 0
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def long_threshold(self):
return self._long_threshold.Value
@property
def exit_threshold(self):
return self._exit_threshold.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(volatility_arbitrage_spread_oscillator_model_strategy, self).OnReseted()
self._front_close = 0.0
self._second_close = 0.0
self._rsi_val = 0.0
self._prev_rsi = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(volatility_arbitrage_spread_oscillator_model_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def on_process(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
self._front_close = float(candle.ClosePrice)
self._prev_rsi = self._rsi_val
self._rsi_val = float(rsi_value)
if self._cooldown > 0:
self._cooldown -= 1
return
if self._prev_rsi == 0:
return
# Long entry when RSI crosses below threshold
if self._rsi_val < self.long_threshold and self.Position <= 0:
self.BuyMarket()
self._cooldown = 45
# Exit long / short entry when RSI crosses above threshold
elif self._rsi_val > self.exit_threshold and self.Position >= 0:
self.SellMarket()
self._cooldown = 45
def CreateClone(self):
return volatility_arbitrage_spread_oscillator_model_strategy()