GitHub で見る

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 = 20
    • StopLossPercent = 2.0m
    • CandleType = 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));
			}
		}
	}
}