public SpoofingRuleBreach( IFactorValue factorValue, ISystemProcessOperationContext operationContext, string correlationId, TimeSpan window, ITradePosition fulfilledTradePosition, ITradePosition cancelledTradePosition, FinancialInstrument security, Order mostRecentTrade, ISpoofingRuleEquitiesParameters spoofingEquitiesParameters, string description, string caseTitle, DateTime universeDateTime) { this.FactorValue = factorValue; this.Window = window; this.Security = security; this.MostRecentTrade = mostRecentTrade; var totalTrades = fulfilledTradePosition.Get().ToList(); totalTrades.AddRange(cancelledTradePosition.Get()); this.Trades = new TradePosition(totalTrades); this.TradesInFulfilledPosition = fulfilledTradePosition; this.CancelledTrades = cancelledTradePosition; this.RuleParameterId = spoofingEquitiesParameters?.Id ?? string.Empty; this.SystemOperationId = operationContext.Id.ToString(); this.CorrelationId = correlationId; this.RuleParameters = spoofingEquitiesParameters; this.Description = description ?? string.Empty; this.CaseTitle = caseTitle ?? string.Empty; this.UniverseDateTime = universeDateTime; }
public LayeringRuleBreach( IFactorValue factorValue, ISystemProcessOperationContext operationContext, string correlationId, ILayeringRuleEquitiesParameters equitiesParameters, TimeSpan window, ITradePosition trades, FinancialInstrument security, RuleBreachDescription bidirectionalTradeBreach, RuleBreachDescription dailyVolumeTradeBreach, RuleBreachDescription windowVolumeTradeBreach, RuleBreachDescription priceMovementBreach, string description, string caseTitle, DateTime universeDateTime) { this.FactorValue = factorValue; this.EquitiesParameters = equitiesParameters; this.Window = window; this.Trades = trades; this.Security = security; this.BidirectionalTradeBreach = bidirectionalTradeBreach; this.DailyVolumeTradeBreach = dailyVolumeTradeBreach; this.WindowVolumeTradeBreach = windowVolumeTradeBreach; this.PriceMovementBreach = priceMovementBreach; this.RuleParameterId = equitiesParameters?.Id ?? string.Empty; this.SystemOperationId = operationContext.Id.ToString(); this.CorrelationId = correlationId; this.RuleParameters = equitiesParameters; this.Description = description ?? string.Empty; this.CaseTitle = caseTitle ?? string.Empty; this.UniverseDateTime = universeDateTime; }
public PlacingOrderWithNoIntentToExecuteRuleRuleBreach( TimeSpan window, ITradePosition trades, FinancialInstrument security, IFactorValue factorValue, decimal meanPrice, decimal sdPrice, IReadOnlyCollection <ProbabilityOfExecution> probabilityForOrders, IPlacingOrderWithNoIntentToExecuteRuleEquitiesParameters parameters, ISystemProcessOperationRunRuleContext ctx, string description, string caseTitle, DateTime universeDateTime) { this.Window = window; this.Trades = trades; this.Security = security; this.FactorValue = factorValue; this.Parameters = parameters; this.MeanPrice = meanPrice; this.StandardDeviationPrice = sdPrice; this.ProbabilityForOrders = probabilityForOrders ?? new List <ProbabilityOfExecution>(); this.RuleParameterId = parameters.Id; this.SystemOperationId = ctx.Id(); this.CorrelationId = ctx.CorrelationId(); this.RuleParameters = parameters; this.Description = description ?? string.Empty; this.CaseTitle = caseTitle ?? string.Empty; this.UniverseDateTime = universeDateTime; }
/// <summary> /// Initializes a new instance of the <see cref="RuleBreach"/> class. /// </summary> /// <param name="window"> /// The window. /// </param> /// <param name="trades"> /// The trades. /// </param> /// <param name="security"> /// The security. /// </param> /// <param name="isBackTestRun"> /// The is back test run. /// </param> /// <param name="ruleParameterId"> /// The rule parameter id. /// </param> /// <param name="systemOperationId"> /// The system operation id. /// </param> /// <param name="correlationId"> /// The correlation id. /// </param> /// <param name="factorValue"> /// The factor value. /// </param> /// <param name="ruleParameter"> /// The rule parameter. /// </param> /// <param name="universeDateTime"> /// The universe date time. /// </param> /// <param name="description"> /// The description. /// </param> /// <param name="caseTitle"> /// The case title. /// </param> public RuleBreach( TimeSpan window, ITradePosition trades, FinancialInstrument security, bool isBackTestRun, string ruleParameterId, string systemOperationId, string correlationId, IFactorValue factorValue, IRuleParameter ruleParameter, DateTime universeDateTime, string description, string caseTitle) { this.Window = window; this.Trades = trades; this.Security = security; this.IsBackTestRun = isBackTestRun; this.RuleParameterId = ruleParameterId; this.SystemOperationId = systemOperationId; this.CorrelationId = correlationId; this.FactorValue = factorValue; this.RuleParameters = ruleParameter; this.UniverseDateTime = universeDateTime; this.Description = description; this.CaseTitle = caseTitle; }
public RampingRuleBreach( TimeSpan window, ITradePosition trades, FinancialInstrument security, string ruleParameterId, string systemOperationId, string correlationId, IFactorValue factorValue, IRampingStrategySummaryPanel summaryPanel, IRampingRuleEquitiesParameters parameters, string description, string caseTitle, DateTime universeDateTime) { this.Window = window; this.Trades = trades; this.Security = security; this.RuleParameterId = ruleParameterId ?? string.Empty; this.SystemOperationId = systemOperationId ?? string.Empty; this.CorrelationId = correlationId ?? string.Empty; this.FactorValue = factorValue; this.SummaryPanel = summaryPanel; this.RuleParameters = parameters; this.Description = description ?? string.Empty; this.CaseTitle = caseTitle ?? string.Empty; this.UniverseDateTime = universeDateTime; }
public MarkingTheCloseBreach( IFactorValue factorValue, ISystemProcessOperationContext operationContext, string correlationId, TimeSpan window, FinancialInstrument security, MarketOpenClose marketClose, ITradePosition tradingPosition, IMarkingTheCloseEquitiesParameters equitiesParameters, VolumeBreach dailyBreach, VolumeBreach windowBreach, string description, string caseTitle, DateTime universeDateTime) { this.FactorValue = factorValue; this.Window = window; this.Security = security ?? throw new ArgumentNullException(nameof(security)); this.MarketClose = marketClose ?? throw new ArgumentNullException(nameof(marketClose)); this.Trades = tradingPosition ?? new TradePosition(new List <Order>()); this.EquitiesParameters = equitiesParameters ?? throw new ArgumentNullException(nameof(equitiesParameters)); this.DailyBreach = dailyBreach; this.WindowBreach = windowBreach; this.RuleParameterId = equitiesParameters?.Id ?? string.Empty; this.SystemOperationId = operationContext.Id.ToString(); this.CorrelationId = correlationId; this.RuleParameters = equitiesParameters; this.Description = description ?? string.Empty; this.CaseTitle = caseTitle ?? string.Empty; this.UniverseDateTime = universeDateTime; }
public WashTradeRuleBreach( TimeSpan windowSize, IFactorValue factorValue, ISystemProcessOperationContext operationContext, string correlationId, IWashTradeRuleParameters equitiesParameters, ITradePosition tradePosition, FinancialInstrument security, WashTradeAveragePositionBreach averagePositionBreach, WashTradeClusteringPositionBreach clusteringPositionBreach, string description, string caseTitle, DateTime universeDateTime) { this.FactorValue = factorValue; this.EquitiesParameters = equitiesParameters ?? throw new ArgumentNullException(nameof(equitiesParameters)); this.Window = windowSize; this.Trades = tradePosition; this.Security = security; this.AveragePositionBreach = averagePositionBreach ?? throw new ArgumentNullException(nameof(averagePositionBreach)); this.ClusteringPositionBreach = clusteringPositionBreach ?? throw new ArgumentNullException(nameof(clusteringPositionBreach)); this.RuleParameterId = equitiesParameters?.Id ?? string.Empty; this.SystemOperationId = operationContext.Id.ToString(); this.CorrelationId = correlationId; this.RuleParameters = equitiesParameters; this.Description = description ?? string.Empty; this.CaseTitle = caseTitle ?? string.Empty; this.UniverseDateTime = universeDateTime; }
/// <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> /// Check if the current position (this) is a subset of the provided (arg) position /// uses BY REFERENCE for comparision /// </summary> public bool PositionIsSubsetOf(ITradePosition position) { if (position == null) { return(false); } return(!this._trades.Except(position.Get()).Any()); }
/// <summary> /// Initializes a new instance of the <see cref="FixedIncomeHighVolumeJudgementContext"/> class. /// </summary> /// <param name="judgement"> /// The judgement. /// </param> /// <param name="raiseRuleViolation"> /// The project to alert. /// </param> /// <param name="tradePosition"> /// The trade position. /// </param> /// <param name="venue"> /// The venue. /// </param> public FixedIncomeHighVolumeJudgementContext( IFixedIncomeHighVolumeJudgement judgement, bool raiseRuleViolation, ITradePosition tradePosition, Market venue) { this.Judgement = judgement ?? throw new ArgumentNullException(nameof(judgement)); this.RaiseRuleViolation = raiseRuleViolation; this.TradePosition = tradePosition ?? throw new ArgumentNullException(nameof(tradePosition)); this.Venue = venue; }
/// <summary> /// Check if the current position (this) is a subset of the provided (argument) position uses BY REFERENCE for comparison /// </summary> /// <param name="position"> /// The position. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> public bool PositionIsSubsetOf(ITradePosition position) { if (position == null) { return(false); } if (position.Get().SequenceEqual(this.trades)) { return(true); } return(!this.trades.Except(position.Get()).Any()); }
public ExchangeRateProfitBreakdown( ITradePosition positionCost, ITradePosition positionRevenue, decimal positionCostWer, decimal positionRevenueWer, Domain.Core.Financial.Money.Currency fixedCurrency, Domain.Core.Financial.Money.Currency variableCurrency) { this.PositionCost = positionCost; this.PositionRevenue = positionRevenue; this.PositionCostWer = positionCostWer; this.PositionRevenueWer = positionRevenueWer; this.FixedCurrency = fixedCurrency; this.VariableCurrency = variableCurrency; }
public async Task <decimal> WeightedExchangeRate( ITradePosition position, Currency targetCurrency, ISystemProcessOperationRunRuleContext ruleCtx) { if (position == null || position.TotalVolume() == 0) { this._logger.LogInformation( "asked to calculate WER for either null position or position with 0 volume. Returning 0"); return(0); } var totalVolume = position.TotalVolume(); var weightedRates = new List <WeightedXRate>(); foreach (var order in position.Get()) { if (order.OrderFilledVolume.GetValueOrDefault() == 0) { continue; } var weight = order.OrderFilledVolume.GetValueOrDefault(0) / totalVolume; var rate = await this._exchangeRatesService.GetRate( order.OrderCurrency, targetCurrency, order.MostRecentDateEvent(), ruleCtx); weightedRates.Add(new WeightedXRate(weight, (decimal?)rate?.Rate ?? 0m)); } foreach (var item in weightedRates) { if (item == null) { continue; } this._logger.LogInformation($"had a sub component with {item.Weight} and {item.XRate}"); } var weightedAverage = weightedRates.Sum(wr => wr.Weight * wr.XRate); return(weightedAverage); }
public async Task <ExchangeRateProfitBreakdown> ExchangeRateMovement( ITradePosition positionCost, ITradePosition positionRevenue, Domain.Core.Financial.Money.Currency variableCurrency, ISystemProcessOperationRunRuleContext ruleCtx) { if (string.IsNullOrEmpty(variableCurrency.Code)) { this._logger.LogInformation( "ExchangeRateProfitCalculator ExchangeRateMovement had a null or empty variable currency. Returning null."); return(null); } var orderCurrency = positionCost.Get() .FirstOrDefault(pos => !string.IsNullOrWhiteSpace(pos.OrderCurrency.Code))?.OrderCurrency; if (string.Equals(orderCurrency?.Code, variableCurrency.Code, StringComparison.InvariantCultureIgnoreCase)) { this._logger.LogInformation( "ExchangeRateProfitCalculator ExchangeRateMovement could not find an order currency. Returning null."); return(null); } if (string.IsNullOrWhiteSpace(orderCurrency.GetValueOrDefault().Code)) { orderCurrency = positionRevenue.Get() .FirstOrDefault(pos => !string.IsNullOrWhiteSpace(pos.OrderCurrency.Code))?.OrderCurrency; } var costRates = await this._werExchangeRateService.WeightedExchangeRate(positionCost, variableCurrency, ruleCtx); var revenueRates = await this._werExchangeRateService.WeightedExchangeRate( positionRevenue, variableCurrency, ruleCtx); var breakdown = new ExchangeRateProfitBreakdown( positionCost, positionRevenue, costRates, revenueRates, orderCurrency.GetValueOrDefault(), variableCurrency); return(breakdown); }
/// <summary> /// The add to positions. /// </summary> /// <param name="buyPosition"> /// The buy position. /// </param> /// <param name="sellPosition"> /// The sell position. /// </param> /// <param name="nextTrade"> /// The next trade. /// </param> private void AddToPositions(ITradePosition buyPosition, ITradePosition sellPosition, Order nextTrade) { switch (nextTrade.OrderDirection) { case OrderDirections.BUY: case OrderDirections.COVER: buyPosition.Add(nextTrade); break; case OrderDirections.SELL: case OrderDirections.SHORT: sellPosition.Add(nextTrade); break; default: this.logger.LogError("not considering an out of range order direction"); this.ruleContext.EventException("not considering an out of range order direction"); throw new ArgumentOutOfRangeException(nameof(nextTrade)); } }
public HighVolumeRuleBreach( IFactorValue factorValue, ISystemProcessOperationContext operationContext, string correlationId, TimeSpan window, ITradePosition trades, FinancialInstrument security, IHighVolumeRuleEquitiesParameters equitiesParameters, BreachDetails dailyBreach, BreachDetails windowBreach, BreachDetails marketCapBreach, decimal totalOrdersTradedInWindow, string description, string caseTitle, DateTime universeDateTime) { this.FactorValue = factorValue; this.Window = window; this.Trades = trades; this.Security = security; this.EquitiesParameters = equitiesParameters; this.DailyBreach = dailyBreach; this.WindowBreach = windowBreach; this.MarketCapBreach = marketCapBreach; this.TotalOrdersTradedInWindow = totalOrdersTradedInWindow; this.RuleParameterId = equitiesParameters?.Id ?? string.Empty; this.SystemOperationId = operationContext.Id.ToString(); this.CorrelationId = correlationId; this.RuleParameters = equitiesParameters; this.Description = description ?? string.Empty; this.CaseTitle = caseTitle ?? string.Empty; this.UniverseDateTime = universeDateTime; }
public CancelledOrderRuleBreach( IFactorValue factorValue, ISystemProcessOperationContext ctx, string correlationId, ICancelledOrderRuleEquitiesParameters parameters, ITradePosition trades, FinancialInstrument security, bool exceededPercentagePositionCancellations, decimal?percentagePositionCancelled, int?amountOfPositionCancelled, int?amountOfPositionInTotal, bool exceededPercentageTradeCountCancellations, decimal?percentageTradeCountCancelled, string description, string caseTitle, DateTime universeDateTime) { this.FactorValue = factorValue; this.Parameters = parameters; this.Trades = trades; this.Security = security; this.ExceededPercentagePositionCancellations = exceededPercentagePositionCancellations; this.PercentagePositionCancelled = percentagePositionCancelled; this.AmountOfPositionCancelled = amountOfPositionCancelled; this.AmountOfPositionInTotal = amountOfPositionInTotal; this.ExceededPercentageTradeCountCancellations = exceededPercentageTradeCountCancellations; this.PercentageTradeCountCancelled = percentageTradeCountCancelled; this.Window = parameters.Windows.BackwardWindowSize; this.RuleParameterId = this.Parameters?.Id ?? string.Empty; this.SystemOperationId = ctx.Id.ToString(); this.CorrelationId = correlationId; this.RuleParameters = this.Parameters; this.Description = description ?? string.Empty; this.CaseTitle = caseTitle ?? string.Empty; this.UniverseDateTime = universeDateTime; }
public void Setup() { this.tradePosition = A.Fake <ITradePosition>(); this.judgement = A.Fake <IFixedIncomeHighVolumeJudgement>(); this.market = new Market("id-1", "XLON", "London Stock Exchange", MarketTypes.STOCKEXCHANGE); }
/// <summary> /// The check for price movement. /// </summary> /// <param name="opposingPosition"> /// The opposing position. /// </param> /// <param name="mostRecentTrade"> /// The most recent trade. /// </param> /// <returns> /// The <see cref="RuleBreachDescription"/>. /// </returns> private RuleBreachDescription CheckForPriceMovement( ITradePosition opposingPosition, Order mostRecentTrade) { var startDate = opposingPosition.Get().Where(op => op.PlacedDate != null).Min(op => op.PlacedDate).GetValueOrDefault(); var endDate = opposingPosition.Get().Where(op => op.PlacedDate != null).Max(op => op.PlacedDate).GetValueOrDefault(); if (endDate.Subtract(startDate) < TimeSpan.FromMinutes(1)) { endDate = endDate.AddMinutes(1); } var marketRequest = new MarketDataRequest( mostRecentTrade.Market.MarketIdentifierCode, mostRecentTrade.Instrument.Cfi, mostRecentTrade.Instrument.Identifiers, startDate.Subtract(this.TradeBackwardWindowSize), endDate, this.ruleContext?.Id(), DataSource.AnyIntraday); var tradingDays = this.tradingHoursService.GetTradingDaysWithinRangeAdjustedToTime( UniverseDateTime.Subtract(this.TradeBackwardWindowSize), UniverseDateTime, mostRecentTrade.Market.MarketIdentifierCode); var marketResult = UniverseEquityIntradayCache.GetMarketsForRange(marketRequest, tradingDays, RunMode); if (marketResult.HadMissingData) { this.logger.LogInformation($"unable to fetch market data frames for {mostRecentTrade.Market.MarketIdentifierCode} at {UniverseDateTime}."); this.hadMissingData = true; return(RuleBreachDescription.False()); } if (mostRecentTrade.PlacedDate > endDate) { endDate = mostRecentTrade.PlacedDate.GetValueOrDefault(); } var securityDataTicks = marketResult.Response; var startTick = this.StartTick(securityDataTicks, startDate); if (startTick == null) { this.logger.LogInformation($"unable to fetch starting exchange tick data for ({startDate}) {mostRecentTrade.Market.MarketIdentifierCode} at {UniverseDateTime}."); this.hadMissingData = true; return(RuleBreachDescription.False()); } var endTick = this.EndTick(securityDataTicks, endDate); if (endTick == null) { this.logger.LogInformation($"unable to fetch ending exchange tick data for ({endDate}) {mostRecentTrade.Market.MarketIdentifierCode} at {UniverseDateTime}."); this.hadMissingData = true; return(RuleBreachDescription.False()); } var priceMovement = endTick.SpreadTimeBar.Price.Value - startTick.SpreadTimeBar.Price.Value; return(this.BuildDescription(mostRecentTrade, priceMovement, startTick, endTick)); }
/// <summary> /// The check window 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 CheckWindowVolumeBreach( ITradePosition opposingPosition, Order mostRecentTrade) { var marketDataRequest = new MarketDataRequest( mostRecentTrade.Market.MarketIdentifierCode, mostRecentTrade.Instrument.Cfi, mostRecentTrade.Instrument.Identifiers, UniverseDateTime.Subtract(this.TradeBackwardWindowSize), UniverseDateTime, this.ruleContext?.Id(), DataSource.AnyIntraday); var tradingDays = this.tradingHoursService.GetTradingDaysWithinRangeAdjustedToTime( UniverseDateTime.Subtract(this.TradeBackwardWindowSize), UniverseDateTime, mostRecentTrade.Market.MarketIdentifierCode); var securityResult = UniverseEquityIntradayCache.GetMarketsForRange(marketDataRequest, tradingDays, RunMode); if (securityResult.HadMissingData) { this.logger.LogWarning($"unable to fetch market data frames for {mostRecentTrade.Market.MarketIdentifierCode} at {UniverseDateTime}."); this.hadMissingData = true; return(RuleBreachDescription.False()); } var windowVolume = securityResult.Response.Sum(sdt => sdt?.SpreadTimeBar.Volume.Traded); if (windowVolume <= 0) { this.logger.LogInformation($"unable to sum meaningful volume from market data frames for volume window in {mostRecentTrade.Market.MarketIdentifierCode} at {UniverseDateTime}."); this.hadMissingData = true; return(RuleBreachDescription.False()); } if (opposingPosition.TotalVolumeOrderedOrFilled() <= 0) { this.logger.LogInformation($"unable to calculate opposing position volume window in {mostRecentTrade.Market.MarketIdentifierCode} at {UniverseDateTime}."); this.hadMissingData = true; return(RuleBreachDescription.False()); } var percentageWindowVolume = (decimal)opposingPosition.TotalVolumeOrderedOrFilled() / (decimal)windowVolume; if (percentageWindowVolume >= this.equitiesParameters.PercentageOfMarketWindowVolume) { return(new RuleBreachDescription { RuleBreached = true, Description = $" Percentage of market volume traded within a {this.equitiesParameters.Windows.BackwardWindowSize.TotalSeconds} second window exceeded the layering window threshold of {this.equitiesParameters.PercentageOfMarketWindowVolume * 100}%." }); } return(RuleBreachDescription.False()); }
/// <summary> /// The check position for layering. /// </summary> /// <param name="tradeWindow"> /// The trade window. /// </param> /// <param name="buyPosition"> /// The buy position. /// </param> /// <param name="sellPosition"> /// The sell position. /// </param> /// <param name="tradingPosition"> /// The trading position. /// </param> /// <param name="opposingPosition"> /// The opposing position. /// </param> /// <param name="mostRecentTrade"> /// The most recent trade. /// </param> /// <returns> /// The <see cref="ILayeringRuleBreach"/>. /// </returns> private ILayeringRuleBreach CheckPositionForLayering( Stack <Order> tradeWindow, ITradePosition buyPosition, ITradePosition sellPosition, ITradePosition tradingPosition, ITradePosition opposingPosition, Order mostRecentTrade) { var hasTradesInWindow = tradeWindow.Any(); RuleBreachDescription hasBidirectionalBreach = RuleBreachDescription.False(); RuleBreachDescription hasDailyVolumeBreach = RuleBreachDescription.False(); RuleBreachDescription hasWindowVolumeBreach = RuleBreachDescription.False(); RuleBreachDescription priceMovementBreach = RuleBreachDescription.False(); // ReSharper disable once LoopVariableIsNeverChangedInsideLoop while (hasTradesInWindow) { if (!tradeWindow.Any()) { // ReSharper disable once RedundantAssignment hasTradesInWindow = false; break; } var nextTrade = tradeWindow.Pop(); this.AddToPositions(buyPosition, sellPosition, nextTrade); if (!tradingPosition.Get().Any() || !opposingPosition.Get().Any()) { continue; } // IF ALL PARAMETERS ARE NULL JUST DO THE BIDIRECTIONAL TRADE CHECK if (this.equitiesParameters.PercentageOfMarketDailyVolume == null && this.equitiesParameters.PercentageOfMarketWindowVolume == null && this.equitiesParameters.CheckForCorrespondingPriceMovement == null) { hasBidirectionalBreach = new RuleBreachDescription { RuleBreached = true, Description = " Trading in both buy/sell positions simultaneously was detected." }; } if (this.equitiesParameters.PercentageOfMarketDailyVolume != null) { hasDailyVolumeBreach = this.CheckDailyVolumeBreach(opposingPosition, mostRecentTrade); } if (this.equitiesParameters.PercentageOfMarketWindowVolume != null) { hasWindowVolumeBreach = this.CheckWindowVolumeBreach(opposingPosition, mostRecentTrade); } if (this.equitiesParameters.CheckForCorrespondingPriceMovement != null && this.equitiesParameters.CheckForCorrespondingPriceMovement.Value) { priceMovementBreach = this.CheckForPriceMovement(opposingPosition, mostRecentTrade); } } var allTradesInPositions = opposingPosition.Get().Concat(tradingPosition.Get()).ToList(); var allTrades = new TradePosition(allTradesInPositions); if (!this.HasRuleBreach( hasBidirectionalBreach, hasDailyVolumeBreach, hasWindowVolumeBreach, priceMovementBreach)) { return(null); } return(new LayeringRuleBreach( this.OrganisationFactorValue, this.ruleContext.SystemProcessOperationContext(), this.ruleContext.CorrelationId(), this.equitiesParameters, this.equitiesParameters.Windows?.BackwardWindowSize ?? TimeSpan.Zero, allTrades, mostRecentTrade.Instrument, hasBidirectionalBreach, hasDailyVolumeBreach, hasWindowVolumeBreach, priceMovementBreach, null, null, UniverseDateTime)); }