/// <summary> /// The retrieve market traded volume. /// </summary> /// <param name="mostRecentTrade"> /// The most recent trade. /// </param> /// <param name="tradingHours"> /// The trading hours. /// </param> /// <param name="activeHistory"> /// The active history. /// </param> /// <returns> /// The <see cref="long?"/>. /// </returns> private long?RetrieveMarketTradedVolume(Order mostRecentTrade, ITradingHours tradingHours, Stack <Order> activeHistory) { var closeTime = this.source == DataSource.AnyIntraday ? UniverseDateTime : tradingHours.ClosingInUtcForDay(UniverseDateTime); var marketDataRequest = new MarketDataRequest( mostRecentTrade.Market?.MarketIdentifierCode, mostRecentTrade.Instrument.Cfi, mostRecentTrade.Instrument.Identifiers, tradingHours.OpeningInUtcForDay(UniverseDateTime.Subtract(this.TradeBackwardWindowSize)), closeTime, RuleCtx.Id(), this.source); var hadMissingData = false; long?marketTradedVolume = null; switch (this.source) { case DataSource.AnyInterday: var securityResultInterday = UniverseEquityInterdayCache.GetMarkets(marketDataRequest); hadMissingData = securityResultInterday.HadMissingData; if (!hadMissingData) { marketTradedVolume = this.InterdayMarketTradedVolume(securityResultInterday); } break; case DataSource.AnyIntraday: var securityResultIntraday = UniverseEquityIntradayCache.GetMarkets(marketDataRequest); hadMissingData = securityResultIntraday.HadMissingData; if (!hadMissingData) { marketTradedVolume = this.IntradayMarketTradedVolume(securityResultIntraday); } break; } if (hadMissingData && RunMode == RuleRunMode.ForceRun) { this.UpdatePassedFilterWithOrders(activeHistory); return(null); } if (hadMissingData && RunMode == RuleRunMode.ValidationRun) { this.logger.LogInformation($"market traded volume was not calculable for {mostRecentTrade.Instrument.Identifiers} due to missing data"); this.hadMissingData = true; return(null); } return(marketTradedVolume); }
/// <summary> /// The check daily volume breach. /// </summary> /// <param name="opposingPosition"> /// The opposing position. /// </param> /// <param name="mostRecentTrade"> /// The most recent trade. /// </param> /// <returns> /// The <see cref="RuleBreachDescription"/>. /// </returns> private RuleBreachDescription CheckDailyVolumeBreach( ITradePosition opposingPosition, Order mostRecentTrade) { var tradingHoursManager = this.tradingHoursService.GetTradingHoursForMic(mostRecentTrade.Market.MarketIdentifierCode); if (!tradingHoursManager.IsValid) { this.logger.LogInformation($"unable to fetch market data for ({mostRecentTrade.Market.MarketIdentifierCode}) for the most recent trade {mostRecentTrade?.Instrument?.Identifiers} the market data did not contain the security indicated as trading in that market"); this.hadMissingData = true; return(RuleBreachDescription.False()); } var marketRequest = new MarketDataRequest( mostRecentTrade.Market.MarketIdentifierCode, mostRecentTrade.Instrument.Cfi, mostRecentTrade.Instrument.Identifiers, tradingHoursManager.OpeningInUtcForDay(UniverseDateTime.Subtract(this.TradeBackwardWindowSize)), tradingHoursManager.ClosingInUtcForDay(UniverseDateTime), this.ruleContext?.Id(), DataSource.AnyInterday); var marketResult = UniverseEquityInterdayCache.Get(marketRequest); if (marketResult.HadMissingData) { this.logger.LogInformation($"unable to fetch market data for ({mostRecentTrade.Market.MarketIdentifierCode}) for the most recent trade {mostRecentTrade?.Instrument?.Identifiers} the market data did not contain the security indicated as trading in that market"); this.hadMissingData = true; return(RuleBreachDescription.False()); } var marketSecurityData = marketResult.Response; if (marketSecurityData?.DailySummaryTimeBar?.DailyVolume.Traded <= 0 || opposingPosition.TotalVolumeOrderedOrFilled() <= 0) { this.logger.LogInformation($"unable to evaluate for {mostRecentTrade?.Instrument?.Identifiers} either the market daily volume data was not available or the opposing position had a bad total volume value (daily volume){marketSecurityData?.DailySummaryTimeBar?.DailyVolume.Traded} - (opposing position){opposingPosition.TotalVolumeOrderedOrFilled()}"); this.hadMissingData = true; return(RuleBreachDescription.False()); } var percentageDailyVolume = (decimal)opposingPosition.TotalVolumeOrderedOrFilled() / (decimal)marketSecurityData?.DailySummaryTimeBar?.DailyVolume.Traded; if (percentageDailyVolume >= this.equitiesParameters.PercentageOfMarketDailyVolume) { return(new RuleBreachDescription { RuleBreached = true, Description = $" Percentage of market daily volume traded within a {this.equitiesParameters.Windows.BackwardWindowSize.TotalSeconds} second window exceeded the layering window threshold of {this.equitiesParameters.PercentageOfMarketDailyVolume * 100}%." }); } return(RuleBreachDescription.False()); }
/// <summary> /// The daily volume check. /// </summary> /// <param name="mostRecentTrade"> /// The most recent trade. /// </param> /// <param name="tradedVolume"> /// The traded volume. /// </param> /// <returns> /// The <see cref="BreachDetails"/>. /// </returns> private HighVolumeRuleBreach.BreachDetails DailyVolumeCheck(Order mostRecentTrade, decimal tradedVolume) { if (mostRecentTrade == null) { return(HighVolumeRuleBreach.BreachDetails.None()); } var tradingHours = this.TradingHoursService.GetTradingHoursForMic(mostRecentTrade.Market?.MarketIdentifierCode); if (!tradingHours.IsValid) { this.Logger.LogError($"Request for trading hours was invalid. MIC - {mostRecentTrade.Market?.MarketIdentifierCode}"); } var marketDataRequest = new MarketDataRequest( mostRecentTrade.Market?.MarketIdentifierCode, mostRecentTrade.Instrument.Cfi, mostRecentTrade.Instrument.Identifiers, tradingHours.OpeningInUtcForDay(UniverseDateTime.Subtract(this.TradeBackwardWindowSize)), tradingHours.ClosingInUtcForDay(UniverseDateTime), this.RuleCtx?.Id(), DataSource.AnyInterday); var securityResult = UniverseEquityInterdayCache.Get(marketDataRequest); if (securityResult.HadMissingData) { this.HadMissingData = true; this.Logger.LogWarning($"Missing data for {marketDataRequest}."); return(HighVolumeRuleBreach.BreachDetails.None()); } var security = securityResult.Response; var threshold = (long)Math.Ceiling( this.EquitiesParameters.HighVolumePercentageDaily.GetValueOrDefault(0) * security.DailySummaryTimeBar.DailyVolume.Traded); if (threshold <= 0) { this.HadMissingData = true; this.Logger.LogInformation($"Daily volume threshold of {threshold} was recorded."); return(HighVolumeRuleBreach.BreachDetails.None()); } var breachPercentage = security.DailySummaryTimeBar.DailyVolume.Traded != 0 && tradedVolume != 0 ? (decimal)tradedVolume / (decimal)security.DailySummaryTimeBar.DailyVolume.Traded : 0; if (tradedVolume >= threshold) { return(new HighVolumeRuleBreach.BreachDetails(true, breachPercentage, threshold, mostRecentTrade.Market)); } return(HighVolumeRuleBreach.BreachDetails.None()); }
/// <summary> /// The check daily volume traded. /// </summary> /// <param name="securities"> /// The securities. /// </param> /// <returns> /// The <see cref="VolumeBreach"/>. /// </returns> private VolumeBreach CheckDailyVolumeTraded( Stack <Order> securities) { if (!securities.Any()) { return(new VolumeBreach()); } var marketDataRequest = new MarketDataRequest( securities.Peek().Market.MarketIdentifierCode, securities.Peek().Instrument.Cfi, securities.Peek().Instrument.Identifiers, UniverseDateTime.Subtract(this.TradeBackwardWindowSize), // implicitly correct (market closure event trigger) UniverseDateTime, this.ruleContext?.Id(), DataSource.AnyInterday); var dataResponse = UniverseEquityInterdayCache.Get(marketDataRequest); if (dataResponse.HadMissingData) { this.hadMissingData = true; this.logger.LogInformation($"had missing data for {securities.Peek().Instrument.Identifiers} on {UniverseDateTime}"); return(new VolumeBreach()); } var tradedSecurity = dataResponse.Response; var thresholdVolumeTraded = tradedSecurity.DailySummaryTimeBar.DailyVolume.Traded * this.equitiesParameters.PercentageThresholdDailyVolume; if (thresholdVolumeTraded == null) { this.hadMissingData = true; return(new VolumeBreach()); } var result = this.CalculateVolumeBreaches( securities, thresholdVolumeTraded.GetValueOrDefault(0), tradedSecurity.DailySummaryTimeBar.DailyVolume.Traded); return(result); }