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; } } }