Overall Statistics
Total Trades
1
Average Win
0%
Average Loss
0%
Compounding Annual Return
-42.612%
Drawdown
0.500%
Expectancy
0
Net Profit
0%
Sharpe Ratio
-9.165
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0.042
Annual Variance
0.002
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$1.98
using System;
using System.Collections;
using System.Collections.Generic;
using QuantConnect.Securities;
using QuantConnect.Models;

namespace QuantConnect 
{
    public class Consolidator 
    {
        private TradeBar _resultBar;
        private TradeBar _workingBar;
        private DateTime _start;
        private TimeSpan _period;
        
        //Result:
        public TradeBar Bar
        {
            get
            {
                return _resultBar;
            }
        }
        
        //Constructor: Set the period we'd like to scan
        public Consolidator(TimeSpan span) 
        {
            this._period = span;
            this._resultBar = new TradeBar();
            this._workingBar = new TradeBar(new DateTime(), "", Decimal.Zero, Decimal.MinValue, Decimal.MaxValue, 0, 0);
        }
        
        //Submit this bar, return true if we've started a new one.
        public bool Update(TradeBar newBar)
        {
            //Intialize:
            if (_start == new DateTime()) 
            {
                _start = newBar.Time;
            }
            
            //While we're less than end date, keep adding to this bar:
            if (newBar.Time < (_start + _period))
            {
                //Building bar:
                AddToBar(newBar);
                return false;
            } 
            else 
            {
                //Completed bar: start new one:
                _resultBar = _workingBar;
                //Create a new bar:
                _workingBar = new TradeBar(newBar.Time, newBar.Symbol, Decimal.Zero, Decimal.MinValue, Decimal.MaxValue, 0, 0);
                //Start of this bar:
                _start = newBar.Time;
                AddToBar(newBar);
                return true;
            }
        }
        
        //Add to a tradebar
        private void AddToBar(TradeBar newBar)
        {
            //Add this data to working bar:
            if (_workingBar.Time == new DateTime()) _workingBar.Time = newBar.Time;
            if (_workingBar.Symbol == "") _workingBar.Symbol = newBar.Symbol;
            if (_workingBar.Open == Decimal.Zero) _workingBar.Open = newBar.Open;
            if (newBar.High > _workingBar.High) _workingBar.High = newBar.High;
            if (newBar.Low < _workingBar.Low) _workingBar.Low = newBar.Low;
            _workingBar.Close = newBar.Close;
            _workingBar.Volume = newBar.Volume;
        }
    }
}                        
namespace QuantConnect
{   
    public class OptimizedVRP : QCAlgorithm
    {
    	// Notes
    	
    	/*
    	SUMMARY:

		https://www.quantconnect.com/forum/discussion/comment/2442#Comment_2442
		https://www.quantconnect.com/forum/discussion/444
		https://www.quantconnect.com/forum/discussion/435
    	*/
    	
        // User-editable Fields


		private string _longsymbol = "VXX";
		private string _shortsymbol = "XIV";
		private string _metricsymbol = "SPY";
		private int _smoothingdays = 5;
		private int _historicalvolatilitydays = 2;
		private string _quandlcode = "SPDJ/SPVIXSTR";

        // Class Fields

		public enum Direction { Long, Short };
        private bool _firstondatacall = true;
		private bool _enabletrading = true;
		private Direction _direction = Direction.Long;
		private int _warmupdays = 1;

		StandardDeviation _lnstd;
        decimal _metricdelta = 0.0m;
        decimal _metricprevclose = 0.0m;
        private TimeSpan _metricbarperiod = TimeSpan.FromDays(1);
        private Consolidator _metricconsolidator;
        
        private SimpleMovingAverage _smaVIX;
        
        ExponentialMovingAverage _emadiff;
        decimal _diff = 0.0m;
		decimal sqrt252 = Convert.ToDecimal(Math.Pow(252, 0.5));
        private TimeSpan _emabarperiod = TimeSpan.FromDays(1);
        private Consolidator _emaconsolidator;

        // Initializer

        public override void Initialize()
        {
            SetStartDate(2016, 2, 1);
            SetEndDate(2016, 2, 12);
            SetCash(10000);

            AddSecurity(SecurityType.Equity, _longsymbol, Resolution.Hour);
        	AddSecurity(SecurityType.Equity, _shortsymbol, Resolution.Hour);
        	AddSecurity(SecurityType.Equity, _metricsymbol, Resolution.Hour);

            Securities[_longsymbol].SetDataNormalizationMode(DataNormalizationMode.TotalReturn);
            Securities[_shortsymbol].SetDataNormalizationMode(DataNormalizationMode.TotalReturn);
            Securities[_metricsymbol].SetDataNormalizationMode(DataNormalizationMode.TotalReturn);

            Securities[_longsymbol].SetLeverage(1);
            Securities[_shortsymbol].SetLeverage(1);
            Securities[_metricsymbol].SetLeverage(1);
            
            AddData<QuandlVixContract>(_quandlcode, Resolution.Daily);

			// Custom Indicator: natural log version of standard deviation = standard deviation(ln(todaysclose/yesterdaysclose) : ln(yesterdaysclose/twodaysagoclose))
            _metricconsolidator = new Consolidator(_metricbarperiod);
			_lnstd = new StandardDeviation(_historicalvolatilitydays);

			// Standard Indicator: same as identity of closing price of vix contract (from quandl data)
            _smaVIX = SMA(_quandlcode, 1);

			// Custom Indicator: EMA(5) of (smaVix - (_lnstd(2) * 100 * sqrt(252))   --->  where _lnstd(2) is the above indicator
            _emaconsolidator = new Consolidator(_emabarperiod);
			_emadiff = new ExponentialMovingAverage(_smoothingdays);
			
            SetWarmup(_warmupdays);
        }

        // Event-Driven Methods
        
        public override void OnData(Slice data)
        {
			UpdateLNStd(data.Bars);
			
			UpdateEMADiff(data);
        	
        	// Abandon method if we're warming up the algorithm with historical data
            if (IsWarmingUp)
            {
            	if (IsEvaluationTime())
            	{
            		Log("WARM UP DAY");
            		
            		AssessMetric();
            	}
            	return;
            }
            
            // Abandon method if this is the first time the OnData() method is called
            if (_firstondatacall)
            {
                _firstondatacall = false;
            	_enabletrading = true;
                return;
            }
            
			// Assess interval rules
            if (IsEvaluationTime())
           	{
           		Log("TRADING DAY");
           		
           		_enabletrading = false;
           		
				AssessMetric();
				
				TakeAction();
            }
        }
        
        public override void OnEndOfDay() 
        {
			_enabletrading = true;
        }

        // Rebalance Rules Methods
		
		public void AssessMetric()
		{
			if (_emadiff > 1.0) // short VIX (long XIV)
			{
				_direction = Direction.Short;
			}
			else // long VIX (long VXX)
			{
				_direction = Direction.Long;
			}
		}
		
		public void TakeAction()
		{
			if (_direction == Direction.Long)
			{
				if (Portfolio[_longsymbol].HoldStock == false)
				{
					SetHoldings(_shortsymbol, 0.0m);
					SetHoldings(_longsymbol, 0.95m);
					Log(String.Format("ACTION: Direction is 'Long'. Setting holdings to 100% {0}.", _longsymbol));
				}
				else
				{	
					Log(String.Format("ACTION: Direction is 'Long'. We are already 100% on {0}. No action taken.", _longsymbol));
				}
			}
			else if (_direction == Direction.Short)
			{
				if (Portfolio[_shortsymbol].HoldStock == false)
				{
					SetHoldings(_longsymbol, 0.0m);
					SetHoldings(_shortsymbol, 0.95m);
					Log(String.Format("ACTION: Direction is 'Short'. Setting holdings to 100% {0}.", _shortsymbol));
				}
				else
				{
					Log(String.Format("ACTION: Direction is 'Short'. We are already 100% on {0}. No action taken.", _shortsymbol));
				}
			}
		}
		
		// Helper Methods
		
		public void UpdateLNStd(TradeBars data)
		{
			if (data.ContainsKey(_metricsymbol))
			{
				if (_metricconsolidator.Update(data[_metricsymbol]))
		        {
		            try
		            {
		                if(_metricprevclose != 0.0m)
		                {
		                	_metricdelta = (decimal)Math.Log((double)data[_metricsymbol].Close/(double)_metricprevclose);
		                }
		                
		                TradeBar bar;
		                if (data.TryGetValue(_metricsymbol, out bar))
		                {
		                    _lnstd.Update(bar.Time, _metricdelta);
		                }
		                
    					Log(String.Format("PrevClose: {0}\tCurrentClose: {1}\tDelta: {2}\tLNStd: {3}", _metricprevclose, data[_metricsymbol].Close, _metricdelta, _lnstd));
		                
		             	_metricprevclose = data[_metricsymbol].Close;
						}
		            catch(Exception e)
		            {
		                Debug(e.Message);
		            }
		        }
			}
		}

		public void UpdateEMADiff(Slice data)
		{
			/* I WANT TO DO THE FOLLOWING:

			1.)  _diff = _smaVIX - (sqrt252 * 100.0m * _lnstd);
			2.)  _emadiff.Update(quandldata.Period, _diff);

			*/
		}
		
		public bool IsEvaluationTime()
		{
			bool satisfied = false;
			
			if (this.Time.Hour == 15 && _enabletrading == true) // Afternoon 
				satisfied = true;
			else
				satisfied = false;
			
			return satisfied;
		}
    }
}                        
namespace QuantConnect
{
    public class QuandlVixContract : Quandl
    {
        public QuandlVixContract() : base(valueColumnName: "S&P 500 VIX Short-Term Index MCAP") 
        {
        }
    }
}