/// <summary> /// Computes the average value /// </summary> /// <param name="time"></param> /// <param name="input">The data for the calculation</param> /// <returns>The average value</returns> protected override DoubleArray Forward(long time, DoubleArray input) { var price = (input[HighIdx] + input[LowIdx]) / 2; _high.Add(input[HighIdx]); _low.Add(input[LowIdx]); // our first data point just return identity if (_high.Samples <= _high.Size) { return(price); } var hh = _high.Take(_n / 2).Max(); var ll = _low.Take(_n / 2).Min(); var n1 = (hh - ll) / (_n / 2); hh = _high.Skip(_n / 2).Take(_n / 2).Max(); ll = _low.Skip(_n / 2).Take(_n / 2).Min(); var n2 = (hh - ll) / (_n / 2); var n3 = (_high.Max() - _low.Min()) / _n; double dimen = 0; if (n1 + n2 > 0 && n3 > 0) { dimen = Math.Log((n1 + n2) / n3) / Math.Log(2); } var alpha = Math.Exp(_w * (dimen - 1)); if (alpha < .01d) { alpha = .01d; } if (alpha > 1) { alpha = 1; } return(alpha * price + (1 - alpha) * Current.Value); }
public override void Initialize() { SetStartDate(2015, 1, 1); SetEndDate(DateTime.Now); SetCash(10000); foreach (var equity in _equities) { AddSecurity(SecurityType.Equity, equity, Resolution.Minute); } _s = new int[_stocks.Length]; _x0 = new int[_stocks.Length]; _x1 = Enumerable.Repeat(1d / _stocks.Length, _stocks.Length).ToArray(); _symbolData = new Dictionary <Symbol, SymbolData>(); _bb = new BollingerBands(_spy, 22, 1.05m, MovingAverageType.Simple); _spyWvf = new RollingWindow <decimal>(22); foreach (var stock in _stocks) { var closes = new RollingWindow <decimal>(17 * 390); var dailyCloses = new RollingWindow <TradeBar>(29); var dailyConsolidator = new TradeBarConsolidator(TimeSpan.FromDays(1)); dailyConsolidator.DataConsolidated += (sender, consolidated) => _symbolData[consolidated.Symbol].UpdateDaily(consolidated); SubscriptionManager.AddConsolidator(stock, dailyConsolidator); _symbolData.Add(stock, new SymbolData(closes, dailyCloses)); } var spyDailyCloses = new RollingWindow <TradeBar>(28); var spyDailyConsolidator = new TradeBarConsolidator(TimeSpan.FromDays(1)); spyDailyConsolidator.DataConsolidated += (sender, consolidated) => _symbolData[consolidated.Symbol].UpdateDaily(consolidated); SubscriptionManager.AddConsolidator(_spy, spyDailyConsolidator); _symbolData.Add(_spy, new SymbolData(null, spyDailyCloses)); var vxxDailyConsolidator = new TradeBarConsolidator(TimeSpan.FromDays(1)); vxxDailyConsolidator.DataConsolidated += (sender, consolidated) => _symbolData[consolidated.Symbol].UpdateDaily(consolidated); SubscriptionManager.AddConsolidator(_vxx, vxxDailyConsolidator); _symbolData.Add(_spy, new SymbolData(null, spyDailyCloses)); Schedule.On(DateRules.EveryDay(), TimeRules.AfterMarketOpen("SPY", 15d), () => { if (_symbolData[_spy].IsReady) { return; } var vxxCloses = _symbolData[_vxx].DailyHistory.Select(tb => tb.Close); var vxxLows = _symbolData[_vxx].DailyHistory.Select(tb => tb.Low); // William's VIX Fix indicator a.k.a. the Synthetic VIX var previousMax = vxxCloses.Take(28).Max(); var previousWvf = 100 * (previousMax - vxxLows.Skip(27).First()) / previousMax; var max = vxxCloses.Skip(1).Max(); var wvf = 100 * (max - vxxLows.Last()) / max; if (previousWvf < WvfLimit && wvf >= WvfLimit) { SetHoldings(_vxx, 0); SetHoldings(_xiv, 0.07); } else if (previousWvf > WvfLimit && wvf <= WvfLimit) { SetHoldings(_vxx, 0.07); SetHoldings(_xiv, 0); } }); Schedule.On(DateRules.EveryDay(), TimeRules.AfterMarketOpen("SPY", 15d), () => { if (_symbolData[_spy].IsReady) { return; } var spyCloses = _symbolData[_spy].NDaysDailyHistory(22).Select(tb => tb.Close); var spyLows = _symbolData[_spy].NDaysDailyHistory(22).Select(tb => tb.Low); var max = spyCloses.Max(); var wvf = 100 * (max - spyLows.Last()) / max; _bb.Update(DateTime.Now, wvf); _spyWvf.Add(wvf); var rangeHigh = _spyWvf.Max() * 0.9m; var latestClose = _symbolData[_spy].NDaysDailyHistory(1).First().Close; var spy_higher_then_Xdays_back = latestClose > _symbolData[_spy].NDaysDailyHistory(3).First().Close; var spy_lower_then_longterm = latestClose > _symbolData[_spy].NDaysDailyHistory(40).First().Close; var spy_lower_then_midterm = latestClose > _symbolData[_spy].NDaysDailyHistory(14).First().Close; // Alerts Criteria var alert2 = !(_spyWvf[0] >= _bb.UpperBand && _spyWvf[0] >= rangeHigh) && (_spyWvf[1] >= _bb.UpperBand && _spyWvf[2] >= rangeHigh); if ((alert2 || spy_higher_then_Xdays_back) && (spy_lower_then_longterm || spy_lower_then_midterm)) { SetHoldings(_spy, 0.3); SetHoldings(_shortSpy, 0); } else { SetHoldings(_spy, 0); SetHoldings(_shortSpy, 0.3); } }); Schedule.On(DateRules.EveryDay(), TimeRules.AfterMarketOpen("SPY", 15d), () => { if (_symbolData[_spy].IsReady) { return; } var returns = new List <double[]>(); // 28? foreach (var stock in _stocks) { _symbolData[stock].UpdateWeights(); returns.Add(_symbolData[stock].PercentReturn.Select(pr => (double)(pr / _symbolData[stock].Norm)).ToArray()); } var retNorm = _symbolData.Select(s => s.Value.Norm); var retNormMax = retNorm.Max(); var epsFactor = retNormMax > 0 ? 0.9m : 1.0m; var eps = (double)(epsFactor * retNormMax); var constraints = new List <LinearConstraint>(); constraints.Add(new LinearConstraint(Enumerable.Repeat(1.0, _stocks.Length).ToArray()) { ShouldBe = ConstraintType.EqualTo, Value = 1 }); constraints.Add(new LinearConstraint(retNorm.Select(x => (double)x).ToArray()) { ShouldBe = ConstraintType.GreaterThanOrEqualTo, Value = eps + eps * 0.01 }); // Add and subtract small bounce to achieve inequality? constraints.Add(new LinearConstraint(retNorm.Select(x => (double)x).ToArray()) { ShouldBe = ConstraintType.LesserThanOrEqualTo, Value = eps - eps * 0.01 }); // Add and subtract small bounce to achieve inequality? constraints.Add(new LinearConstraint(_stocks.Length) { VariablesAtIndices = Enumerable.Range(0, _stocks.Length).ToArray(), ShouldBe = ConstraintType.GreaterThanOrEqualTo, Value = 0 }); constraints.Add(new LinearConstraint(_stocks.Length) { VariablesAtIndices = Enumerable.Range(0, _stocks.Length).ToArray(), ShouldBe = ConstraintType.LesserThanOrEqualTo, Value = 1 }); var initialGuess = new double[_stocks.Length]; var f = new QuadraticObjectiveFunction(() => Variance(initialGuess, returns.ToMatrix())); var solver = new GoldfarbIdnani(f, constraints); solver.Minimize(); var weights = _x1; var totalWeight = weights.Sum(); if (solver.Status == GoldfarbIdnaniStatus.Success) { weights = solver.Solution; } for (var i = 0; i < _stocks.Length; i++) { SetHoldings(_stocks[i], weights[i] / totalWeight); } }); }