| 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 |
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")
{
}
}
}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;
}
}
}