VIX Trigger
VIX Trigger reacts to changes in the Volatility Index. A rising VIX signals fear and possible reversals in the underlying instrument. The strategy compares VIX direction with price relative to a moving average.
Testing indicates an average annual return of about 148%. It performs best in the forex market.
When VIX increases and price is below the moving average, it buys expecting a recovery. Conversely, rising VIX with price above the average invites a short position.
Positions close when VIX falls or the stop-loss percentage is reached.
Details
- Entry Criteria: VIX rising while price relative to MA triggers longs or shorts.
- Long/Short: Both directions.
- Exit Criteria: VIX falls or stop.
- Stops: Yes.
- Default Values:
MAPeriod= 20StopLossPercent= 2.0mCandleType= TimeSpan.FromMinutes(5)
- Filters:
- Category: Contrarian
- Direction: Both
- Indicators: VIX, MA
- Stops: Yes
- Complexity: Intermediate
- Timeframe: Intraday
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using Ecng.ComponentModel;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that trades based on VIX (Volatility Index) movements.
/// It enters positions when VIX is rising (indicating increasing fear/volatility in the market)
/// and price is moving in an expected direction relative to its moving average.
/// </summary>
public class VixTriggerStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<Security> _vixSecurity;
private decimal _prevVix;
// Latest VIX value and trend flags
private decimal _latestVix;
private bool _isVixRising;
/// <summary>
/// Period for Moving Average calculation (default: 20)
/// </summary>
public int MAPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Stop-loss as percentage from entry price (default: 2%)
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Type of candles used for strategy calculation
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// VIX Security (required)
/// </summary>
public Security VixSecurity
{
get => _vixSecurity.Value;
set => _vixSecurity.Value = value;
}
/// <summary>
/// Initialize the VIX Trigger strategy
/// </summary>
public VixTriggerStrategy()
{
_maPeriod = Param(nameof(MAPeriod), 20)
.SetDisplay("MA Period", "Period for Moving Average calculation", "Technical Parameters")
.SetOptimize(10, 50, 5);
_stopLossPercent = Param(nameof(StopLossPercent), 2.0m)
.SetDisplay("Stop Loss %", "Stop loss as percentage from entry price", "Risk Management")
.SetOptimize(1.0m, 5.0m, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "Data");
_vixSecurity = Param<Security>(nameof(VixSecurity))
.SetDisplay("VIX Security", "VIX Security to use for signals", "Data")
.SetRequired();
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
// We need both the primary security and VIX
return
[
(Security, CandleType),
(VixSecurity, CandleType)
];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
// Reset state variables
_prevVix = 0;
_latestVix = 0;
_isVixRising = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicator
var sma = new SMA { Length = MAPeriod };
// Create subscriptions
var mainSubscription = SubscribeCandles(CandleType);
var vixSubscription = SubscribeCandles(CandleType, security: VixSecurity);
// Bind indicator to main security candles
mainSubscription
.Bind(sma, ProcessMainCandle)
.Start();
// Process VIX candles separately
vixSubscription
.Bind(ProcessVixCandle)
.Start();
// Configure chart
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, mainSubscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
// Setup protection with stop-loss
StartProtection(
new Unit(0), // No take profit
new Unit(StopLossPercent, UnitTypes.Percent) // Stop loss as percentage of entry price
);
}
/// <summary>
/// Process VIX candle to track VIX movements
/// </summary>
private void ProcessVixCandle(ICandleMessage candle)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Store latest VIX value
_latestVix = candle.ClosePrice;
// Initialize _prevVix on first VIX candle
if (_prevVix == 0)
{
_prevVix = _latestVix;
return;
}
// Check if VIX is rising
_isVixRising = _latestVix > _prevVix;
// Update previous VIX value
_prevVix = _latestVix;
}
/// <summary>
/// Process main security candle and check for trading signals
/// </summary>
private void ProcessMainCandle(ICandleMessage candle, decimal smaValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready to trade
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Check if we have received VIX data
if (_prevVix == 0)
return;
// Determine price position relative to MA
bool isPriceBelowMA = candle.ClosePrice < smaValue;
if (Position == 0)
{
// No position - check for entry signals
if (_isVixRising && isPriceBelowMA)
{
// VIX is rising and price is below MA - buy (contrarian strategy)
BuyMarket(Volume);
}
else if (_isVixRising && !isPriceBelowMA)
{
// VIX is rising and price is above MA - sell (contrarian strategy)
SellMarket(Volume);
}
}
else if (Position > 0)
{
// Long position - check for exit signal
if (!_isVixRising)
{
// VIX is decreasing - exit long
SellMarket(Position);
}
}
else if (Position < 0)
{
// Short position - check for exit signal
if (!_isVixRising)
{
// VIX is decreasing - exit short
BuyMarket(Math.Abs(Position));
}
}
}
}
import clr
clr.AddReference("System.Drawing")
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.BusinessEntities")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from System.Drawing import Color
from StockSharp.Messages import UnitTypes, Unit, DataType, ICandleMessage, CandleStates, Sides
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from StockSharp.BusinessEntities import Security, Subscription
from datatype_extensions import *
class vix_trigger_strategy(Strategy):
"""
Strategy that trades based on VIX (Volatility Index) movements.
It enters positions when VIX is rising (indicating increasing fear/volatility in the market)
and price is moving in an expected direction relative to its moving average.
"""
def __init__(self):
super(vix_trigger_strategy, self).__init__()
# Initialize internal state
self._prevVix = 0
self._latestVix = 0
self._isVixRising = False
# Initialize strategy parameters
self._maPeriod = self.Param("MAPeriod", 20) \
.SetDisplay("MA Period", "Period for Moving Average calculation", "Technical Parameters")
self._stopLossPercent = self.Param("StopLossPercent", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss as percentage from entry price", "Risk Management")
self._candleType = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Type of candles to use", "Data")
self._vixSecurity = self.Param[Security]("VixSecurity", None) \
.SetDisplay("VIX Security", "VIX Security to use for signals", "Data")
@property
def MAPeriod(self):
return self._maPeriod.Value
@MAPeriod.setter
def MAPeriod(self, value):
self._maPeriod.Value = value
@property
def StopLossPercent(self):
return self._stopLossPercent.Value
@StopLossPercent.setter
def StopLossPercent(self, value):
self._stopLossPercent.Value = value
@property
def CandleType(self):
return self._candleType.Value
@CandleType.setter
def CandleType(self, value):
self._candleType.Value = value
@property
def VixSecurity(self):
return self._vixSecurity.Value
@VixSecurity.setter
def VixSecurity(self, value):
self._vixSecurity.Value = value
def OnReseted(self):
"""
Resets internal state when strategy is reset.
"""
super(vix_trigger_strategy, self).OnReseted()
self._prevVix = 0
self._latestVix = 0
self._isVixRising = False
def OnStarted2(self, time):
"""
Called when the strategy starts. Sets up indicators, subscriptions, and charting.
:param time: The time when the strategy started.
"""
super(vix_trigger_strategy, self).OnStarted2(time)
# Create indicator
sma = SimpleMovingAverage()
sma.Length = self.MAPeriod
# Create subscriptions
mainSubscription = self.SubscribeCandles(self.CandleType)
vixSubscription = self.SubscribeCandles(self.CandleType, self.VixSecurity)
# Bind indicator to main security candles
mainSubscription.Bind(sma, self.ProcessMainCandle).Start()
# Process VIX candles separately
vixSubscription.Bind(self.ProcessVixCandle).Start()
# Configure chart if GUI is available
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, mainSubscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
# Setup protection with stop-loss
self.StartProtection(
takeProfit=Unit(0, UnitTypes.Absolute),
stopLoss=Unit(self.StopLossPercent, UnitTypes.Percent)
)
def ProcessVixCandle(self, candle):
"""
Process VIX candle to track VIX movements
:param candle: The VIX candle message.
"""
# Skip unfinished candles
if candle.State != CandleStates.Finished:
return
# Store latest VIX value
self._latestVix = float(candle.ClosePrice)
# Initialize _prevVix on first VIX candle
if self._prevVix == 0:
self._prevVix = self._latestVix
return
# Check if VIX is rising
self._isVixRising = self._latestVix > self._prevVix
# Update previous VIX value
self._prevVix = self._latestVix
def ProcessMainCandle(self, candle, smaValue):
"""
Process main security candle and check for trading signals
:param candle: The main security candle message.
:param smaValue: The current SMA value.
"""
# Skip unfinished candles
if candle.State != CandleStates.Finished:
return
# Check if strategy is ready to trade
# Check if we have received VIX data
if self._prevVix == 0:
return
# Determine price position relative to MA
isPriceBelowMA = candle.ClosePrice < smaValue
if self.Position == 0:
# No position - check for entry signals
if self._isVixRising and isPriceBelowMA:
# VIX is rising and price is below MA - buy (contrarian strategy)
self.BuyMarket(self.Volume)
elif self._isVixRising and not isPriceBelowMA:
# VIX is rising and price is above MA - sell (contrarian strategy)
self.SellMarket(self.Volume)
elif self.Position > 0:
# Long position - check for exit signal
if not self._isVixRising:
# VIX is decreasing - exit long
self.SellMarket(self.Position)
elif self.Position < 0:
# Short position - check for exit signal
if not self._isVixRising:
# VIX is decreasing - exit short
self.BuyMarket(Math.Abs(self.Position))
def CreateClone(self):
"""
!! REQUIRED!! Creates a new instance of the strategy.
"""
return vix_trigger_strategy()