/// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public override IEnumerable <Insight> Update(QCAlgorithmFramework algorithm, Slice data) { var insights = new List <Insight>(); foreach (var kvp in _symbolDataBySymbol) { var symbol = kvp.Key; OptionChain chain; if (!TryGetOptionChain(algorithm, symbol, out chain)) { return(insights); } //compute IV from some ATM options decimal iv = 0; var options = chain.Where((o) => o.UnderlyingLastPrice > o.Strike - STRIKE_SPREAD && o.UnderlyingLastPrice < o.Strike + STRIKE_SPREAD); if (options.Count() < 2) { algorithm.Log("No options available to compute IV!"); return(insights); } iv = AverageIV(algorithm, options); kvp.Value.Update(data.Time, iv); var std = kvp.Value.STD; var previousState = kvp.Value.State; var previousMag = kvp.Value.Mag; double mag; var state = GetState(std, out mag); if ((state != previousState || mag > previousMag) && std.IsReady) { var insightPeriod = _resolution.Multiply(_period); switch (state) { case State.Neutral: insights.Add(Insight.Price(symbol, insightPeriod, InsightDirection.Flat)); break; case State.TrippedHigh: insights.Add(Insight.Price(symbol, insightPeriod, _inverted ? InsightDirection.Up : InsightDirection.Down, mag)); break; case State.TrippedLow: insights.Add(Insight.Price(symbol, insightPeriod, _inverted ? InsightDirection.Down : InsightDirection.Up, mag)); break; } kvp.Value.State = state; kvp.Value.Mag = mag; } } return(insights); }
/// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public override IEnumerable <Insight> Update(QCAlgorithmFramework algorithm, Slice data) { var insights = new List <Insight>(); foreach (var kvp in _symbolDataBySymbol) { var symbol = kvp.Key; OptionChain chain; if (!TryGetOptionChain(algorithm, symbol, out chain)) { return(insights); } decimal max_pain_strike = FindMaxPain(algorithm, chain); if (max_pain_strike <= 0) { algorithm.Log("Insufficient data to compute max pain!"); return(insights); } //find the distance of price to the current max pain strike decimal max_pain_distance = chain.Underlying.Price - max_pain_strike; kvp.Value.Update(data.Time, max_pain_strike, max_pain_distance); var std = kvp.Value.STD; var previousState = kvp.Value.State; var previousMag = kvp.Value.Mag; double mag; var state = GetState(std, max_pain_distance, out mag); //get the STD (magnitude) if ((state != previousState || mag > previousMag) && std.IsReady) { var insightPeriod = _resolution.Multiply(_period); switch (state) { case State.Neutral: insights.Add(Insight.Price(symbol, insightPeriod, InsightDirection.Flat)); break; case State.TrippedHigh: //bullish insights.Add(Insight.Price(symbol, insightPeriod, _inverted ? InsightDirection.Down : InsightDirection.Up, mag)); break; case State.TrippedLow: //bearish insights.Add(Insight.Price(symbol, insightPeriod, _inverted ? InsightDirection.Up : InsightDirection.Down, mag)); break; } kvp.Value.State = state; kvp.Value.Mag = mag; } } return(insights); }
/// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public override IEnumerable <Insight> Update(QCAlgorithmFramework algorithm, Slice data) { var insights = new List <Insight>(); foreach (var kvp in _symbolDataBySymbol) { var symbol = kvp.Key; try { var frontOptions = OptionTools.GetOptionsForExpiry(algorithm, symbol, 0); var backOptions = OptionTools.GetOptionsForExpiry(algorithm, symbol, 1); var frontiv = AverageIV(algorithm, frontOptions); var backiv = AverageIV(algorithm, backOptions); kvp.Value.Update(data.Time, frontiv, backiv); } catch (Exception ex) { algorithm.Log("Failed to compute IV!"); continue; } var std = kvp.Value.STD; var previousState = kvp.Value.State; var previousMag = kvp.Value.Mag; double mag; var state = GetState(std, out mag); if ((state != previousState || mag > previousMag) && std.IsReady) { var insightPeriod = _resolution.Multiply(_period); switch (state) { case State.Neutral: insights.Add(Insight.Price(symbol, insightPeriod, InsightDirection.Flat)); break; case State.TrippedHigh: insights.Add(Insight.Price(symbol, insightPeriod, _inverted ? InsightDirection.Up : InsightDirection.Down, mag)); break; case State.TrippedLow: insights.Add(Insight.Price(symbol, insightPeriod, _inverted ? InsightDirection.Down : InsightDirection.Up, mag)); break; } kvp.Value.State = state; kvp.Value.Mag = mag; } } return(insights); }
/// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public override IEnumerable <Insight> Update(QCAlgorithmFramework algorithm, Slice data) { var insights = new List <Insight>(); foreach (var kvp in _symbolDataBySymbol) { if (!data.ContainsKey(kvp.Key) || data[kvp.Key] == null) { continue; } var symbol = kvp.Key; kvp.Value.Update(data[kvp.Key]); var std = kvp.Value.STD; if (!std.IsReady) { continue; } var previousState = kvp.Value.State; var previousMag = kvp.Value.Mag; double mag; var state = GetState(kvp.Value.Indicator.Current.Value, std, out mag); if ((state != previousState || mag > previousMag) && std.IsReady) { var insightPeriod = _resolution.Multiply(_period); switch (state) { case State.Neutral: insights.Add(Insight.Price(symbol, insightPeriod, InsightDirection.Flat)); break; case State.TrippedHigh: insights.Add(Insight.Price(symbol, insightPeriod, _inverted ? InsightDirection.Up : InsightDirection.Down, mag)); break; case State.TrippedLow: insights.Add(Insight.Price(symbol, insightPeriod, _inverted ? InsightDirection.Down : InsightDirection.Up, mag)); break; } kvp.Value.State = state; kvp.Value.Mag = mag; } } return(insights); }
/// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public override IEnumerable <Insight> Update(QCAlgorithm algorithm, Slice data) { var insights = new List <Insight>(); foreach (var symbolData in _symbolDataBySymbol.Values) { if (symbolData.Fast.IsReady && symbolData.Slow.IsReady) { var ratio1 = (double)symbolData.Slow.Current.Value / (double)symbolData.Fast.Current.Value; var ratio2 = (double)symbolData.Fast.Current.Value / (double)symbolData.Slow.Current.Value; var insightPeriod = _resolution.ToTimeSpan().Multiply(_predictionInterval); if (symbolData.FastIsOverSlow) { if (ratio1 > 1.0005) { insights.Add(Insight.Price( symbolData.Symbol, _resolution, _predictionInterval, InsightDirection.Down, null, null, null, ratio1 )); } } else if (symbolData.SlowIsOverFast) { if (ratio2 > 1.0005) { insights.Add(Insight.Price( symbolData.Symbol, _resolution, _predictionInterval, InsightDirection.Up, null, null, null, ratio2 )); } } } symbolData.FastIsOverSlow = symbolData.Fast > symbolData.Slow; } return(insights); }
/// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public override IEnumerable <Insight> Update(QCAlgorithmFramework algorithm, Slice data) { if (data == null || data.OptionChains == null || data.OptionChains.Count() < 1) { return(new List <Insight>()); } var chainItem = data.OptionChains.First(); var symbol = chainItem.Key.Underlying; var options = OptionTools.GetOptionsForExpiry(algorithm, symbol, 0); var count = options.Where((o) => (o.Expiry - data.Time).TotalDays <= _daysOpenBegin && (o.Expiry - data.Time).TotalDays >= _daysOpenEnd) .Count(); if (count > 0) { return(new List <Insight>() { Insight.Price(chainItem.Key.Underlying, TimeSpan.FromDays(1), InsightDirection.Up) }); } count = options.Where((o) => Math.Abs((o.Expiry - data.Time).TotalDays) <= _daysCloseBegin && Math.Abs((o.Expiry - data.Time).TotalDays) >= _daysCloseEnd) .Count(); if (count > 0) { return(new List <Insight>() { Insight.Price(chainItem.Key.Underlying, TimeSpan.FromDays(1), InsightDirection.Down) }); } return(new List <Insight>()); }
/// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public override IEnumerable <Insight> Update(QCAlgorithm algorithm, Slice data) { var insights = new List <Insight>(); foreach (var symbolData in _symbolDataBySymbol.Values) { if (symbolData.CanEmit()) { var direction = InsightDirection.Flat; var magnitude = (double)symbolData.ROC.Current.Value; if (magnitude > 0) { direction = InsightDirection.Up; } if (magnitude < 0) { direction = InsightDirection.Down; } insights.Add(Insight.Price(symbolData.Security.Symbol, _predictionInterval, direction, magnitude, null)); } } return(insights); }
/// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public virtual IEnumerable <Insight> Update(QCAlgorithmFramework algorithm, Slice data) { if (_mean?.IsReady != true) { return(Enumerable.Empty <Insight>()); } // don't re-emit the same direction if (_state != State.LongRatio && _ratio > _upperThreshold) { _state = State.LongRatio; // asset1/asset2 is more than 2 std away from mean, short asset1, long asset2 var shortAsset1 = Insight.Price(_asset1, TimeSpan.FromMinutes(15), InsightDirection.Down); var longAsset2 = Insight.Price(_asset2, TimeSpan.FromMinutes(15), InsightDirection.Up); // creates a group id and set the GroupId property on each insight object Insight.Group(shortAsset1, longAsset2); return(new[] { shortAsset1, longAsset2 }); } // don't re-emit the same direction if (_state != State.ShortRatio && _ratio < _lowerThreshold) { _state = State.ShortRatio; // asset1/asset2 is less than 2 std away from mean, long asset1, short asset2 var longAsset1 = Insight.Price(_asset1, TimeSpan.FromMinutes(15), InsightDirection.Up); var shortAsset2 = Insight.Price(_asset2, TimeSpan.FromMinutes(15), InsightDirection.Down); // creates a group id and set the GroupId property on each insight object Insight.Group(longAsset1, shortAsset2); return(new[] { longAsset1, shortAsset2 }); } return(Enumerable.Empty <Insight>()); }
/// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public override IEnumerable <Insight> Update(QCAlgorithmFramework algorithm, Slice data) { var insights = new List <Insight>(); foreach (var symbolData in _symbolDataBySymbol.Values) { if (data.ContainsKey(symbolData.Symbol) && symbolData.BB.IsReady) { var bar = ((TradeBar)data[symbolData.Symbol]); if (bar == null) { return(insights); } symbolData.Update(bar); var price = bar.Price; var insightPeriod = _resolution.ToTimeSpan().Multiply(_period); InsightDirection?direction = null; if (price <= symbolData.BB.LowerBand.Current.Price) { direction = InsightDirection.Down; } else if (price >= symbolData.BB.UpperBand.Current.Price) { direction = InsightDirection.Up; } else { if (symbolData.LastDirection == InsightDirection.Up) { if (price <= symbolData.BB.MiddleBand.Current.Price) { direction = InsightDirection.Flat; } } if (symbolData.LastDirection == InsightDirection.Down) { if (price >= symbolData.BB.MiddleBand.Current.Price) { direction = InsightDirection.Flat; } } } if (direction != null && direction != symbolData.LastDirection) { symbolData.LastDirection = (InsightDirection)direction; if (direction == InsightDirection.Down) { insights.Add(Insight.Price(symbolData.Symbol, insightPeriod, _inverted ? InsightDirection.Down : InsightDirection.Up)); } else if (direction == InsightDirection.Up) { insights.Add(Insight.Price(symbolData.Symbol, insightPeriod, _inverted ? InsightDirection.Up : InsightDirection.Down)); } else { insights.Add(Insight.Price(symbolData.Symbol, insightPeriod, InsightDirection.Flat)); } } } } return(insights); }
/// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public override IEnumerable <Insight> Update(QCAlgorithmFramework algorithm, Slice data) { var insights = new List <Insight>(); foreach (var kvp in _symbolDataBySymbol) { var symbol = kvp.Key; OptionChain chain; if (!TryGetOptionChain(algorithm, symbol, out chain)) { return(insights); } decimal calls_iv = 0; decimal puts_iv = 0; //compute IV for all reasonable OTM calls var options = chain.Where((o) => o.Right == OptionRight.Call && o.UnderlyingLastPrice <o.Strike && o.AskPrice> .15m); calls_iv = AverageIV(algorithm, options); //compute IV for all reasonable OTM puts options = chain.Where((o) => o.Right == OptionRight.Put && o.UnderlyingLastPrice > o.Strike && o.AskPrice > .15m); puts_iv = AverageIV(algorithm, options); if (calls_iv <= 0 || puts_iv <= 0) { algorithm.Log("Insufficient data to compute skew!"); return(insights); } //calls - puts => ratio, +skew bullish, -skew bearish decimal iv_ratio = calls_iv - puts_iv; kvp.Value.Update(data.Time, iv_ratio); //get the STD (magnitude) of skew var std = kvp.Value.STD; var previousState = kvp.Value.State; var previousMag = kvp.Value.Mag; double mag; var state = GetState(std, iv_ratio, out mag); if ((state != previousState || mag > previousMag) && std.IsReady) { var insightPeriod = _resolution.Multiply(_period); switch (state) { case State.Neutral: insights.Add(Insight.Price(symbol, insightPeriod, InsightDirection.Flat)); break; case State.TrippedHigh: //bullish insights.Add(Insight.Price(symbol, insightPeriod, _inverted ? InsightDirection.Down : InsightDirection.Up, mag)); break; case State.TrippedLow: //bearish insights.Add(Insight.Price(symbol, insightPeriod, _inverted ? InsightDirection.Up : InsightDirection.Down, mag)); break; } kvp.Value.State = state; kvp.Value.Mag = mag; } } return(insights); }
/// <summary> /// Generates a new insight for a given <see cref="OrderEvent"/>. /// </summary> /// <param name="orderEvent">The <see cref="OrderEvent"/> to create a new /// <see cref="Insight"/> from</param> /// <param name="securityHolding">The <see cref="SecurityHolding"/> of the /// related <see cref="OrderEvent.Symbol"/></param> /// <returns></returns> public Insight GenerateInsightFromFill(OrderEvent orderEvent, SecurityHolding securityHolding) { var desiredFinalQuantity = orderEvent.FillQuantity + securityHolding.Quantity; Insight existingInsight; _insights.TryGetValue(orderEvent.Symbol, out existingInsight); double?confidence; if (// new position securityHolding.Quantity == 0 // closing the entire position || desiredFinalQuantity == 0 // changing market sides || Math.Sign(desiredFinalQuantity) != Math.Sign(securityHolding.Quantity) // increasing the position || Math.Sign(orderEvent.FillQuantity) == Math.Sign(securityHolding.Quantity)) { confidence = 1; } else { // we are reducing the position, so set the confidence based on the original position confidence = (double)(securityHolding.AbsoluteQuantity - orderEvent.AbsoluteFillQuantity) / (double)securityHolding.AbsoluteQuantity; if (existingInsight != null) { // we have to adjust new confidence based on previous confidence = confidence * existingInsight.Confidence; } } var insightDirection = desiredFinalQuantity > 0 ? InsightDirection.Up : desiredFinalQuantity == 0 ? InsightDirection.Flat : InsightDirection.Down; var insight = Insight.Price(orderEvent.Symbol, Time.EndOfTime, insightDirection, null, confidence, AutoGeneratedSourceModel); insight.GeneratedTimeUtc = orderEvent.UtcTime; // When a new insight is generated, will update the <see cref="Insight.CloseTimeUtc"/> // of the previous insight for the same <see cref="Symbol"/>. if (existingInsight != null) { // close the previous insight existingInsight.CloseTimeUtc = insight.GeneratedTimeUtc; _insights.Remove(insight.Symbol); } _insights.Add(insight.Symbol, insight); insight.SetPeriodAndCloseTime(null); return(insight); }