Ejemplo n.º 1
0
        /// <summary>
        /// The update trade submitted trading histories.
        /// </summary>
        /// <param name="order">
        /// The order.
        /// </param>
        /// <param name="tradingHistory">
        /// The trading history.
        /// </param>
        /// <param name="backwardWindowSize">
        /// The backward window size.
        /// </param>
        /// <param name="forwardWindowSize">
        /// The forward window size.
        /// </param>
        /// <returns>
        /// The <see cref="ITradingHistoryStack"/>.
        /// </returns>
        private ITradingHistoryStack UpdateTradeSubmittedTradingHistories(
            Order order,
            ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack> tradingHistory,
            TimeSpan backwardWindowSize,
            TimeSpan?forwardWindowSize)
        {
            if (!tradingHistory.ContainsKey(order.Instrument.Identifiers))
            {
                ITradingHistoryStack history =
                    new TradingHistoryStack(
                        backwardWindowSize,
                        i => i.PlacedDate.GetValueOrDefault(),
                        this.tradingStackLogger);

                ITradingHistoryStack historyDecorator =
                    forwardWindowSize != null
                        ? new TradingHistoryDelayedDecorator(history, forwardWindowSize.GetValueOrDefault())
                        : null;

                var stack = historyDecorator ?? history;
                stack.Add(order, order.PlacedDate.GetValueOrDefault());
                tradingHistory.TryAdd(order.Instrument.Identifiers, stack);
            }
            else
            {
                tradingHistory.TryGetValue(order.Instrument.Identifiers, out var history);

                history?.Add(order, order.PlacedDate.GetValueOrDefault());
                history?.ArchiveExpiredActiveItems(order.PlacedDate.GetValueOrDefault());
            }

            tradingHistory.TryGetValue(order.Instrument.Identifiers, out var updatedHistory);

            return(updatedHistory);
        }
        /// <summary>
        /// The run post order event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunPostOrderEvent(ITradingHistoryStack history)
        {
            var tradeWindow = history?.ActiveTradeHistory();

            if (tradeWindow == null || !tradeWindow.Any())
            {
                return;
            }

            var mostRecentTrade = tradeWindow.Pop();

            var tradingPosition = new TradePositionCancellations(
                new List <Order>(),
                this.parameters.CancelledOrderPercentagePositionThreshold,
                this.parameters.CancelledOrderCountPercentageThreshold,
                this.logger);

            tradingPosition.Add(mostRecentTrade);
            var ruleBreach = this.CheckPositionForCancellations(tradeWindow, mostRecentTrade, tradingPosition);

            if (ruleBreach.HasBreachedRule())
            {
                this.logger.LogInformation(
                    $"RunRule has breached parameter conditions for {mostRecentTrade?.Instrument?.Identifiers}. Adding message to alert stream.");
                var message = new UniverseAlertEvent(Rules.CancelledOrders, ruleBreach, this.operationContext);
                this.alertStream.Add(message);
            }
            else
            {
                this.logger.LogInformation(
                    $"RunRule did not breach parameter conditions for {mostRecentTrade?.Instrument?.Identifiers}.");
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// The run rule guard.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        protected override bool RunRuleGuard(ITradingHistoryStack history)
        {
            var activeWindow = history.ActiveTradeHistory();

            if (!activeWindow.Any())
            {
                return(false);
            }

            var baseOrder = activeWindow.Any() ? activeWindow.Peek() : null;

            var tradeBuy = activeWindow.Where(aw => aw != null).Where(
                aw => aw.OrderDirection == OrderDirections.BUY || aw.OrderDirection == OrderDirections.COVER).ToList();

            var tradeSell = activeWindow.Where(aw => aw != null).Where(
                aw => aw.OrderDirection == OrderDirections.SELL || aw.OrderDirection == OrderDirections.SHORT).ToList();

            var securitiesBrought = tradeBuy.Sum(tb => tb.OrderFilledVolume);
            var securitiesSold    = tradeSell.Sum(tb => tb.OrderFilledVolume);

            if (securitiesBrought > securitiesSold)
            {
                this.Logger.LogInformation(
                    $"RunRuleGuard securities brought {securitiesBrought} exceeded securities sold {securitiesSold}. Proceeding to evaluate market closure rule.");

                return(true);
            }

            this.Logger.LogInformation(
                $"RunRuleGuard securities brought {securitiesBrought} exceeded or equaled securities sold {securitiesSold}. Not proceeding to evaluate market closure rule.");

            this.SetNoLiveTradesJudgement(baseOrder);

            return(false);
        }
        /// <summary>
        /// The run post order event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunPostOrderEvent(ITradingHistoryStack history)
        {
            var activeTrades = history.ActiveTradeHistory();

            if (!activeTrades.Any())
            {
                return;
            }

            var liveTrades = this.FilterByClientAccount(
                history.ActiveTradeHistory().Pop(),
                history.ActiveTradeHistory());

            if (!liveTrades?.Any() ?? true)
            {
                return;
            }

            var tradePosition = new TradePosition(
                this.FilterByClientAccount(history.ActiveTradeHistory().Pop(), history.ActiveTradeHistory()));

            // Net change analysis
            var averagePositionCheckTask = this.NettingTrades(liveTrades);

            averagePositionCheckTask.Wait();
            var averagePositionCheck = averagePositionCheckTask.Result;

            // Clustering trade analysis
            var clusteringPositionCheck = this.ClusteringTrades(liveTrades);

            if ((averagePositionCheck == null || !averagePositionCheck.AveragePositionRuleBreach) &&
                (clusteringPositionCheck == null || !clusteringPositionCheck.ClusteringPositionBreach))
            {
                return;
            }

            var security = liveTrades?.FirstOrDefault()?.Instrument;

            this.logger.LogInformation(
                $"incrementing alerts because of security {security?.Name} at {this.UniverseDateTime}");

            // wrong but should be a judgement anyway
            var breach = new WashTradeRuleBreach(
                this.equitiesParameters.Windows.BackwardWindowSize,
                this.OrganisationFactorValue,
                this.RuleCtx.SystemProcessOperationContext(),
                this.RuleCtx.CorrelationId(),
                this.equitiesParameters,
                tradePosition,
                security,
                averagePositionCheck,
                clusteringPositionCheck,
                null,
                null,
                this.UniverseDateTime);

            var universeAlert = new UniverseAlertEvent(Rules.WashTrade, breach, this.RuleCtx);

            this.alertStream.Add(universeAlert);
        }
        /// <summary>
        /// The run initial submission event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunInitialSubmissionEvent(ITradingHistoryStack history)
        {
            this.logger.LogInformation(
                $"{nameof(FixedIncomeHighVolumeRule)} RunInitialSubmissionRule called at {this.UniverseDateTime}");

            this.logger.LogInformation(
                $"{nameof(FixedIncomeHighVolumeRule)} RunInitialSubmissionRule completed for {this.UniverseDateTime}");
        }
        /// <summary>
        /// The run order filled event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        public override void RunOrderFilledEvent(ITradingHistoryStack history)
        {
            this.logger.LogInformation(
                $"{nameof(FixedIncomeHighVolumeRule)} RunOrderFilledEvent called at {this.UniverseDateTime}");

            this.logger.LogInformation(
                $"{nameof(FixedIncomeHighVolumeRule)} RunOrderFilledEvent completed for {this.UniverseDateTime}");
        }
Ejemplo n.º 7
0
        /// <summary>
        /// The run initial submission event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunInitialSubmissionEvent(ITradingHistoryStack history)
        {
            var activeTrades = history?.ActiveTradeHistory();
            var portfolio    = this.portfolioFactory.Build();

            portfolio.Add(activeTrades);

            var lastTrade = history?.ActiveTradeHistory()?.Any() ?? false
                                ? history?.ActiveTradeHistory()?.Peek()
                                : null;

            if (lastTrade == null)
            {
                return;
            }

            if (lastTrade.OrderStatus() != OrderStatus.Filled)
            {
                this.logger.LogInformation("Order under analysis was not in filled state, exiting spoofing rule");
                return;
            }

            var lastTradeSentiment   = this.analysisService.ResolveSentiment(lastTrade);
            var otherTrades          = activeTrades.Where(i => i != lastTrade).ToList();
            var orderLedgerSentiment = this.analysisService.ResolveSentiment(otherTrades);

            if (lastTradeSentiment == orderLedgerSentiment)
            {
                this.logger.LogInformation("Order under analysis was consistent with a priori pricing sentiment");
                return;
            }

            if (lastTradeSentiment == PriceSentiment.Neutral)
            {
                this.logger.LogInformation("Order under analysis was considered price neutral on sentiment");
                return;
            }

            var analyzedOrders              = this.analysisService.AnalyseOrder(activeTrades);
            var alignedSentimentPortfolio   = this.AlignedSentimentPortfolio(analyzedOrders, lastTradeSentiment);
            var unalignedSentimentPortfolio = this.UnalignedSentimentPortfolio(analyzedOrders, lastTradeSentiment);

            if (!this.UnalignedPortfolioOverCancellationThreshold(unalignedSentimentPortfolio))
            {
                return;
            }

            if (!this.CancellationVolumeOverThreshold(alignedSentimentPortfolio, unalignedSentimentPortfolio))
            {
                return;
            }

            this.logger.LogInformation(
                $"Rule breach for {lastTrade?.Instrument?.Identifiers} at {this.UniverseDateTime}. Passing to alert stream.");
            this.RecordRuleBreach(lastTrade, alignedSentimentPortfolio, unalignedSentimentPortfolio);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// The run initial submission event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunInitialSubmissionEvent(ITradingHistoryStack history)
        {
            var tradeWindow = history?.ActiveTradeHistory();

            if (tradeWindow == null ||
                !tradeWindow.Any())
            {
                return;
            }

            if (tradeWindow.All(trades => trades.OrderDirection == tradeWindow.First().OrderDirection))
            {
                return;
            }

            var mostRecentTrade = tradeWindow.Pop();

            if (mostRecentTrade.OrderStatus() != OrderStatus.Filled)
            {
                return;
            }

            var buyPosition  = new TradePosition(new List <Order>());
            var sellPosition = new TradePosition(new List <Order>());

            this.AddToPositions(buyPosition, sellPosition, mostRecentTrade);

            var tradingPosition =
                (mostRecentTrade.OrderDirection == OrderDirections.BUY ||
                 mostRecentTrade.OrderDirection == OrderDirections.COVER)
                    ? buyPosition
                    : sellPosition;

            var opposingPosition =
                (mostRecentTrade.OrderDirection == OrderDirections.SELL ||
                 mostRecentTrade.OrderDirection == OrderDirections.SHORT)
                    ? buyPosition
                    : sellPosition;

            var layeringRuleBreach =
                this.CheckPositionForLayering(
                    tradeWindow,
                    buyPosition,
                    sellPosition,
                    tradingPosition,
                    opposingPosition,
                    mostRecentTrade);

            if (layeringRuleBreach != null)
            {
                this.logger.LogInformation($"RunInitialSubmissionRule had a breach for {mostRecentTrade?.Instrument?.Identifiers}. Passing to alert stream.");
                var universeAlert = new UniverseAlertEvent(Domain.Surveillance.Scheduling.Rules.Layering, layeringRuleBreach, this.ruleContext);
                this.alertStream.Add(universeAlert);
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// The run post order event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunPostOrderEvent(ITradingHistoryStack history)
        {
            var tradeWindow = history?.ActiveTradeHistory();

            if (tradeWindow == null ||
                !tradeWindow.Any())
            {
                return;
            }

            var tradedSecurities =
                tradeWindow
                .Where(tr =>
                       tr.OrderFilledVolume.GetValueOrDefault() > 0)
                .ToList();

            var tradedVolume = tradedSecurities.Sum(tr => tr.OrderFilledVolume.GetValueOrDefault(0));

            var tradePosition   = new TradePosition(tradedSecurities.ToList());
            var mostRecentTrade = tradeWindow.Peek();

            var dailyBreach     = this.CheckDailyVolume(mostRecentTrade, tradedVolume);
            var windowBreach    = this.CheckWindowVolume(mostRecentTrade, tradedVolume);
            var marketCapBreach = this.CheckMarketCap(mostRecentTrade, tradedSecurities);

            if (this.HasNoBreach(dailyBreach, windowBreach, marketCapBreach))
            {
                return;
            }

            // wrong should use a judgement
            var breach =
                new HighVolumeRuleBreach(
                    this.OrganisationFactorValue,
                    this.RuleCtx.SystemProcessOperationContext(),
                    this.RuleCtx.CorrelationId(),
                    this.EquitiesParameters?.Windows?.BackwardWindowSize ?? TimeSpan.FromDays(1),
                    tradePosition,
                    mostRecentTrade?.Instrument,
                    this.EquitiesParameters,
                    dailyBreach,
                    windowBreach,
                    marketCapBreach,
                    tradedVolume,
                    null,
                    null,
                    this.UniverseDateTime);

            this.Logger.LogInformation($"RunRule had a breach for {mostRecentTrade?.Instrument?.Identifiers}. Daily Breach {dailyBreach?.HasBreach} | Window Breach {windowBreach?.HasBreach} | Market Cap Breach {marketCapBreach?.HasBreach}. Passing to alert stream.");
            var message = new UniverseAlertEvent(Domain.Surveillance.Scheduling.Rules.HighVolume, breach, this.RuleCtx);

            this.AlertStream.Add(message);
        }
        /// <summary>
        /// The run post order event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunPostOrderEvent(ITradingHistoryStack history)
        {
            this.logger.LogInformation($"{nameof(FixedIncomeHighVolumeRule)} RunRule called at {this.UniverseDateTime}");

            var tradeWindow = history?.ActiveTradeHistory() ?? new Stack <Order>();

            if (this.HasEmptyTradeWindow(tradeWindow))
            {
                this.logger.LogInformation($"RunPostOrderEvent had an empty trade window");

                return;
            }

            var tradedSecurities = tradeWindow.Where(_ => _.OrderFilledVolume.GetValueOrDefault() > 0).ToList();

            tradedSecurities = this.FilterOutOtc(tradedSecurities);
            var tradedVolume = tradedSecurities.Sum(_ => _.OrderFilledVolume.GetValueOrDefault(0));

            var tradePosition   = new TradePosition(tradedSecurities.ToList());
            var mostRecentTrade = tradeWindow.Peek();

            var dailyBreach  = this.CheckDailyVolume(mostRecentTrade, tradedVolume);
            var windowBreach = this.CheckWindowVolume(mostRecentTrade, tradedVolume);

            if (this.HasNoBreach(dailyBreach, windowBreach))
            {
                this.logger.LogInformation($"RunPostOrderEvent passing judgement with no daily or window breach for {mostRecentTrade.Instrument.Identifiers}");
                this.PassJudgementForNoBreachAsync(mostRecentTrade, tradePosition).Wait();
            }

            if (windowBreach.VolumeBreach)
            {
                this.logger.LogInformation($"RunPostOrderEvent passing judgement with window breach for {mostRecentTrade.Instrument.Identifiers}");
                this.PassJudgementForWindowBreachAsync(mostRecentTrade, tradePosition, windowBreach).Wait();
            }

            if (dailyBreach.VolumeBreach)
            {
                this.logger.LogInformation($"RunPostOrderEvent passing judgement with no daily breach for {mostRecentTrade.Instrument.Identifiers}");
                this.PassJudgementForDailyBreachAsync(mostRecentTrade, tradePosition, dailyBreach)?.Wait();
            }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// The run post order event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunPostOrderEvent(ITradingHistoryStack history)
        {
            this.logger.LogInformation($"RunPostOrderEvent called at {this.UniverseDateTime}");

            var filteredOrders = this.FilterByClientAccount(
                history.ActiveTradeHistory().Any() ? history.ActiveTradeHistory().Peek() : null,
                history.ActiveTradeHistory().ToList());

            var clusteringAnalysis     = this.ClusteringAnalysis(filteredOrders);
            var averageNettingAnalysis = this.NettingTrades(filteredOrders);

            if ((clusteringAnalysis == null || !clusteringAnalysis.ClusteringPositionBreach) &&
                (averageNettingAnalysis == null || !averageNettingAnalysis.AveragePositionRuleBreach))
            {
                return;
            }

            var security = filteredOrders?.FirstOrDefault()?.Instrument;

            // wrong but should be a judgement anyway
            var breach = new WashTradeRuleBreach(
                this.parameters.Windows.BackwardWindowSize,
                this.OrganisationFactorValue,
                this.RuleCtx.SystemProcessOperationContext(),
                this.RuleCtx.CorrelationId(),
                this.parameters,
                new TradePosition(filteredOrders),
                security,
                averageNettingAnalysis,
                clusteringAnalysis,
                null,
                null,
                this.UniverseDateTime);

            var universeAlert = new UniverseAlertEvent(Rules.FixedIncomeWashTrades, breach, this.RuleCtx);

            this.alertStream.Add(universeAlert);

            this.logger.LogInformation($"RunPostOrderEvent completed for {this.UniverseDateTime}");
        }
Ejemplo n.º 12
0
        /// <summary>
        /// The run order filled event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        public override void RunOrderFilledEvent(ITradingHistoryStack history)
        {
            var tradeWindow = history?.ActiveTradeHistory();

            if (tradeWindow == null ||
                !tradeWindow.Any())
            {
                return;
            }

            if (!this.ExceedsTradingFrequencyThreshold(tradeWindow))
            {
                // LOG THEN EXIT
                this.logger.LogInformation($"Trading Frequency of {this.rampingParameters.ThresholdOrdersExecutedInWindow} was not exceeded. Returning.");
                return;
            }

            if (!this.ExceedsTradingVolumeInWindowThreshold(tradeWindow.ToList(), tradeWindow.Any() ? tradeWindow.Peek() : null))
            {
                // LOG THEN EXIT
                this.logger.LogInformation($"Trading Volume of {this.rampingParameters.ThresholdVolumePercentageWindow} was not exceeded. Returning.");
                return;
            }

            var lastTrade    = tradeWindow.Any() ? tradeWindow.Peek() : null;
            var tradingHours = this.tradingHoursService.GetTradingHoursForMic(lastTrade.Market?.MarketIdentifierCode);

            if (!tradingHours.IsValid)
            {
                this.logger.LogError($"Request for trading hours was invalid. MIC - {lastTrade.Market?.MarketIdentifierCode}");
                return;
            }

            var tradingDates = this.tradingHoursService.GetTradingDaysWithinRangeAdjustedToTime(
                tradingHours.OpeningInUtcForDay(UniverseDateTime.Subtract(this.TradeBackwardWindowSize)),
                tradingHours.ClosingInUtcForDay(UniverseDateTime),
                lastTrade.Market?.MarketIdentifierCode);

            var subtractDate = this.TradeBackwardWindowSize > TimeSpan.FromDays(30) ? this.TradeBackwardWindowSize : TimeSpan.FromDays(30);

            var marketDataRequest = new MarketDataRequest(
                lastTrade.Market?.MarketIdentifierCode,
                lastTrade.Instrument.Cfi,
                lastTrade.Instrument.Identifiers,
                tradingHours.OpeningInUtcForDay(UniverseDateTime.Subtract(subtractDate)),
                tradingHours.ClosingInUtcForDay(UniverseDateTime),
                this.ruleContext?.Id(),
                DataSource.AnyIntraday);

            var marketData = UniverseEquityIntradayCache.GetMarketsForRange(marketDataRequest, tradingDates, RunMode);

            if (marketData.HadMissingData)
            {
                this.hadMissingData = true;
                this.logger.LogWarning($"Missing data for {marketDataRequest}.");
                return;
            }

            var windowStackCopy        = new Stack <Order>(tradeWindow);
            var rampingOrders          = new Stack <Order>(windowStackCopy);
            var rampingAnalysisResults = new List <IRampingStrategySummaryPanel>();

            while (rampingOrders.Any())
            {
                var rampingOrderList      = rampingOrders.ToList();
                var rootOrder             = rampingOrders.Any() ? rampingOrders.Peek() : null;
                var marketDataSubset      = marketData.Response.Where(_ => _.TimeStamp <= rootOrder.FilledDate).ToList();
                var rampingAnalysisResult = this.rampingAnalyzer.Analyse(rampingOrderList, marketDataSubset);
                rampingAnalysisResults.Add(rampingAnalysisResult);
                rampingOrders.Pop();
            }

            if (!rampingAnalysisResults.Any() ||
                !rampingAnalysisResults.First().HasRampingStrategy() ||
                rampingAnalysisResults.All(_ => !_.HasRampingStrategy()))
            {
                // LOG THEN EXIT
                this.logger.LogInformation($"A rule breach was not detected for {lastTrade?.Instrument?.Identifiers}. Returning.");
                return;
            }

            var rampingPrevalence = this.RampingPrevalence(rampingAnalysisResults);

            if (rampingPrevalence < this.rampingParameters.AutoCorrelationCoefficient)
            {
                // LOG THEN EXIT
                this.logger.LogInformation($"A rule breach was not detected due to an auto correlation of {rampingPrevalence} for {lastTrade?.Instrument?.Identifiers}. Returning.");
                return;
            }

            var tradePosition = new TradePosition(tradeWindow.ToList());

            // wrong but should be a judgement
            var breach =
                new RampingRuleBreach(
                    this.TradeBackwardWindowSize,
                    tradePosition,
                    lastTrade.Instrument,
                    this.rampingParameters.Id,
                    this.ruleContext?.Id(),
                    this.ruleContext?.CorrelationId(),
                    this.OrganisationFactorValue,
                    rampingAnalysisResults.Last(),
                    this.rampingParameters,
                    null,
                    null,
                    this.UniverseDateTime);

            this.logger.LogInformation($"RunRule has breached parameter conditions for {lastTrade?.Instrument?.Identifiers}. Adding message to alert stream.");
            var message = new UniverseAlertEvent(Domain.Surveillance.Scheduling.Rules.Ramping, breach, this.ruleContext);

            this.alertStream.Add(message);
        }
Ejemplo n.º 13
0
 /// <summary>
 /// The run order filled event.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 public override void RunOrderFilledEvent(ITradingHistoryStack history)
 {
 }
Ejemplo n.º 14
0
 /// <summary>
 /// The run initial submission event.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 protected override void RunInitialSubmissionEvent(ITradingHistoryStack history)
 {
 }
Ejemplo n.º 15
0
 /// <summary>
 /// The run rule guard, always true but provides override to derived classes.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 /// <returns>
 /// The <see cref="bool"/>.
 /// </returns>
 protected virtual bool RunRuleGuard(ITradingHistoryStack history)
 {
     return(true);
 }
 /// <summary>
 /// The run initial submission event delayed.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 protected override void RunInitialSubmissionEventDelayed(ITradingHistoryStack history)
 {
     // do nothing
 }
        /// <summary>
        /// The run post order event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunPostOrderEvent(ITradingHistoryStack history)
        {
            this.FlushFilterEvents();

            if (history == null)
            {
                this.logger.LogInformation($"null history received by run post order event");
                return;
            }

            var activeHistory = history.ActiveTradeHistory();

            if (activeHistory == null ||
                !activeHistory.Any())
            {
                return;
            }

            if (this.decimalRangeRuleFilter.Type == RuleFilterType.None)
            {
                this.UpdatePassedFilterWithOrders(activeHistory);
                return;
            }

            var mostRecentTrade = activeHistory.Peek();

            var tradingHours = this.tradingHoursService.GetTradingHoursForMic(mostRecentTrade.Market?.MarketIdentifierCode);

            if (!tradingHours.IsValid)
            {
                this.logger.LogError($"Request for trading hours was invalid. MIC - {mostRecentTrade.Market?.MarketIdentifierCode}");

                this.UpdatePassedFilterWithOrders(activeHistory);
                return;
            }

            var marketTradedVolume = this.RetrieveMarketTradedVolume(mostRecentTrade, tradingHours, activeHistory);

            if (marketTradedVolume == null)
            {
                return;
            }

            var volumeTraded = activeHistory.Sum(_ => _.OrderFilledVolume ?? 0);

            if (marketTradedVolume <= 0)
            {
                this.logger.LogInformation($"market traded volume was {marketTradedVolume} for {mostRecentTrade.Instrument.Identifiers}");

                this.UpdatePassedFilterWithOrders(activeHistory);
                return;
            }

            if (volumeTraded <= 0)
            {
                this.logger.LogInformation($"market traded volume was {volumeTraded} for {mostRecentTrade.Instrument.Identifiers}");

                this.UpdatePassedFilterWithOrders(activeHistory);
                return;
            }

            var proportionOfTradedVolume = (volumeTraded / (decimal)marketTradedVolume);

            var passedFilter = false;

            if (this.decimalRangeRuleFilter.Type == RuleFilterType.Include)
            {
                passedFilter =
                    (this.decimalRangeRuleFilter.Max == null || this.decimalRangeRuleFilter.Max == 1 || proportionOfTradedVolume <= this.decimalRangeRuleFilter.Max) &&
                    (this.decimalRangeRuleFilter.Min == null || proportionOfTradedVolume >= this.decimalRangeRuleFilter.Min);
            }
            else if (this.decimalRangeRuleFilter.Type == RuleFilterType.Exclude)
            {
                passedFilter =
                    (this.decimalRangeRuleFilter.Max == null || this.decimalRangeRuleFilter.Max == 1 || proportionOfTradedVolume > this.decimalRangeRuleFilter.Max) ||
                    (this.decimalRangeRuleFilter.Min == null || proportionOfTradedVolume < this.decimalRangeRuleFilter.Min);
            }

            if (passedFilter)
            {
                this.UpdatePassedFilterWithOrders(activeHistory);
            }
        }
Ejemplo n.º 18
0
 /// <summary>
 /// The run post order event.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 protected override void RunPostOrderEvent(ITradingHistoryStack history)
 {
     // we don't analyse rules based on when their status last changed in the layering rule
 }
 public TradingHistoryDelayedDecorator(ITradingHistoryStack stack, TimeSpan delay)
 {
     this._stack         = stack ?? throw new ArgumentNullException(nameof(stack));
     this._delay         = delay;
     this._delayedOrders = new Queue <DelayedOrder>();
 }
Ejemplo n.º 20
0
        /// <summary>
        /// Main method for high profit analysis
        /// </summary>
        /// <param name="history">Trading history qualified for high profit analysis</param>
        /// <param name="intradayCache">Market data for analysis</param>
        protected void EvaluateHighProfits(ITradingHistoryStack history, IUniverseFixedIncomeIntraDayCache intradayCache)
        {
            if (!this.RunRuleGuard(history))
            {
                this.Logger.LogInformation($"EvaluateHighProfits did not pass the rule run guard exiting");

                return;
            }

            var orderUnderAnalysis = this.UniverseEvent.UnderlyingEvent as Order;

            var activeTrades = history.ActiveTradeHistory();

            this.Logger.LogInformation($"EvaluateHighProfits about to filter over Filled with {activeTrades.Count} trades");

            var liveTrades = activeTrades.Where(at => at.OrderStatus() == OrderStatus.Filled).ToList();

            this.Logger.LogInformation($"EvaluateHighProfits about to filter over clean / dirty with {liveTrades.Count} trades");

            var cleanTrades = liveTrades.Where(_ => _.OrderCleanDirty == OrderCleanDirty.CLEAN).ToList();

            this.Logger.LogInformation($"EvaluateHighProfits filtered by clean and had {cleanTrades.Count} trades");

            if (orderUnderAnalysis == null)
            {
                orderUnderAnalysis = activeTrades.LastOrDefault();
            }

            if (!cleanTrades.Any())
            {
                this.Logger.LogInformation($"EvaluateHighProfits had no active and filled trades, exiting");
                this.SetNoLiveTradesJudgement(orderUnderAnalysis);

                return;
            }

            var targetCurrency            = new Currency(this.FixedIncomeParameters.HighProfitCurrencyConversionTargetCurrency);
            var allTradesInCommonCurrency = this.CheckTradesInCommonCurrency(cleanTrades, targetCurrency);
            var costCalculator            = this.GetCostCalculator(allTradesInCommonCurrency, targetCurrency);
            var revenueCalculator         = this.GetRevenueCalculator(allTradesInCommonCurrency, targetCurrency);

            var marketCache =
                this.MarketClosureRule
                    ? this.marketDataCacheFactory.InterdayStrategy(this.UniverseFixedIncomeInterdayCache)
                    : this.marketDataCacheFactory.IntradayStrategy(intradayCache);

            var costTask    = costCalculator.CalculateCostOfPosition(cleanTrades, this.UniverseDateTime, this.RuleCtx);
            var revenueTask = revenueCalculator.CalculateRevenueOfPosition(cleanTrades, this.UniverseDateTime, this.RuleCtx, marketCache);

            var cost            = costTask.Result;
            var revenueResponse = revenueTask.Result;

            if (revenueResponse.HadMissingMarketData)
            {
                this.Logger.LogInformation($"Had missing market data for fixed income high profits, exiting {cleanTrades.FirstOrDefault()?.Instrument?.Identifiers}");
                this.SetMissingMarketDataJudgement(orderUnderAnalysis);
                this.hasMissingData = true;

                return;
            }

            var revenue = revenueResponse.Money;

            if (revenue == null || revenue.Value.Value <= 0)
            {
                this.Logger.LogInformation($"rule had null for revenues for {cleanTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}. Returning.");
                this.NoRevenueOrCostJudgement(orderUnderAnalysis);

                return;
            }

            if (cost == null || cost.Value.Value <= 0)
            {
                this.Logger.LogInformation(
                    $"We have calculable revenues but not costs for {cleanTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}. Returning.");
                this.NoRevenueOrCostJudgement(orderUnderAnalysis);

                return;
            }

            if (!revenue.Value.DenominatedInCommonCurrency(cost.Value))
            {
                var convertedCostTask =
                    this.currencyConverterService.Convert(
                        new[] { cost.Value },
                        revenue.Value.Currency,
                        UniverseDateTime,
                        this.RuleCtx);

                var convertedCost = convertedCostTask.Result;

                if (convertedCost == null || !revenue.Value.DenominatedInCommonCurrency(convertedCost.Value))
                {
                    this.Logger.LogError($"Could not convert cost to revenue currency. Expected currency '{revenue.Value.Currency}' but received currency '{convertedCost.Value.Currency}'. For trade {liveTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}.");
                    return;
                }

                cost = convertedCost;
            }

            this.Logger.LogInformation($"Absolute profit calculating...currency of revenue {revenue.Value.Currency} - currency of costs {cost.Value.Currency} for trade {liveTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}.");
            var absoluteProfit = revenue.Value - cost.Value;

            this.Logger.LogInformation($"Profit ratio calculating...currency of revenue {revenue.Value.Currency} - currency of costs {cost.Value.Currency} for trade {liveTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}.");
            var profitRatio = (revenue.Value.Value / cost.Value.Value) - 1;

            this.Logger.LogInformation($"Currency conversion success of revenue {revenue.Value.Currency} - currency of costs {cost.Value.Currency} for trade {liveTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}.");
            var hasHighProfitAbsolute   = this.HasHighProfitAbsolute(absoluteProfit);
            var hasHighProfitPercentage = this.HasHighProfitPercentage(profitRatio);

            IExchangeRateProfitBreakdown exchangeRateProfits = null;

            if (this.FixedIncomeParameters.UseCurrencyConversions &&
                !string.IsNullOrEmpty(this.FixedIncomeParameters.HighProfitCurrencyConversionTargetCurrency))
            {
                this.Logger.LogInformation(
                    $"is set to use currency conversions and has a target conversion currency to {this.FixedIncomeParameters.HighProfitCurrencyConversionTargetCurrency}. Calling set exchange rate profits.");

                exchangeRateProfits = this.SetExchangeRateProfits(cleanTrades);
            }

            RuleBreachContext ruleBreachContext = null;

            if (hasHighProfitAbsolute || hasHighProfitPercentage)
            {
                this.Logger.LogInformation(
                    $"had a breach for {cleanTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}. High Profit Absolute {hasHighProfitAbsolute} and High Profit Percentage {hasHighProfitPercentage}.");

                ruleBreachContext = new RuleBreachContext(
                    this.FixedIncomeParameters.Windows.BackwardWindowSize
                    + this.FixedIncomeParameters.Windows.FutureWindowSize,
                    new TradePosition(cleanTrades),
                    cleanTrades.FirstOrDefault(_ => _?.Instrument != null)?.Instrument,
                    this.RuleCtx.IsBackTest(),
                    this.RuleCtx.RuleParameterId(),
                    this.RuleCtx.SystemProcessOperationContext().Id.ToString(),
                    this.RuleCtx.CorrelationId(),
                    this.OrganisationFactorValue,
                    this.FixedIncomeParameters,
                    this.UniverseDateTime);
            }

            this.SetJudgementForFullAnalysis(
                absoluteProfit,
                profitRatio,
                hasHighProfitAbsolute,
                hasHighProfitPercentage,
                exchangeRateProfits,
                ruleBreachContext,
                orderUnderAnalysis);
        }
Ejemplo n.º 21
0
 /// <summary>
 /// The run order filled event.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 public override void RunOrderFilledEvent(ITradingHistoryStack history)
 {
     // placing order with no intent to execute will not use this
 }
Ejemplo n.º 22
0
 /// <summary>
 /// The run initial submission event.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 protected override void RunInitialSubmissionEvent(ITradingHistoryStack history)
 {
     // placing order with no intent to execute will not use this
 }
Ejemplo n.º 23
0
        /// <summary>
        /// The run post order event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunPostOrderEvent(ITradingHistoryStack history)
        {
            if (!this.processingMarketClose ||
                this.latestMarketClosure == null)
            {
                return;
            }

            var ordersToCheck =
                history
                .ActiveTradeHistory()
                .Where(_ =>
                       _.OrderLimitPrice?.Value != null &&
                       _.OrderType == OrderTypes.LIMIT &&
                       (
                           _.OrderStatus() == OrderStatus.Placed ||
                           _.OrderStatus() == OrderStatus.Booked ||
                           _.OrderStatus() == OrderStatus.Amended ||
                           _.OrderStatus() == OrderStatus.Cancelled ||
                           _.OrderStatus() == OrderStatus.Rejected))
                .ToList();

            if (!ordersToCheck.Any())
            {
                this.logger.LogInformation("RunPostOrderEvent did not have any orders to check after filtering for invalid order status values");
                return;
            }

            var openingHours   = this.latestMarketClosure.MarketClose - this.latestMarketClosure.MarketOpen;
            var benchmarkOrder = ordersToCheck.First();

            var tradingHours = this.tradingHoursService.GetTradingHoursForMic(benchmarkOrder.Market?.MarketIdentifierCode);

            if (!tradingHours.IsValid)
            {
                this.logger.LogError($"Request for trading hours was invalid. MIC - {benchmarkOrder.Market?.MarketIdentifierCode}");
            }

            var tradingDates = this.tradingHoursService.GetTradingDaysWithinRangeAdjustedToTime(
                tradingHours.OpeningInUtcForDay(UniverseDateTime.Subtract(this.TradeBackwardWindowSize)),
                tradingHours.ClosingInUtcForDay(UniverseDateTime),
                benchmarkOrder.Market?.MarketIdentifierCode);

            var marketDataRequest = new MarketDataRequest(
                benchmarkOrder.Market.MarketIdentifierCode,
                benchmarkOrder.Instrument.Cfi,
                benchmarkOrder.Instrument.Identifiers,
                UniverseDateTime.Subtract(openingHours), // implicitly correct (market closure event trigger)
                UniverseDateTime,
                this.ruleContext?.Id(),
                DataSource.AnyIntraday);

            var dataResponse = UniverseEquityIntradayCache.GetMarketsForRange(marketDataRequest, tradingDates, RunMode);

            if (dataResponse.HadMissingData ||
                dataResponse.Response == null ||
                !dataResponse.Response.Any())
            {
                this.logger.LogInformation($"RunPostOrderEvent could not find relevant market data for {benchmarkOrder.Instrument?.Identifiers} on {this.latestMarketClosure?.MarketId}");
                this.hadMissingData = true;
                return;
            }

            // ReSharper disable once AssignNullToNotNullAttribute
            var pricesInTimeBars = dataResponse.Response.Select(_ => (double)_.SpreadTimeBar.Price.Value).ToList();
            var sd   = (decimal)MathNet.Numerics.Statistics.Statistics.StandardDeviation(pricesInTimeBars);
            var mean = (decimal)MathNet.Numerics.Statistics.Statistics.Mean(pricesInTimeBars);

            var ruleBreaches =
                ordersToCheck
                .Select(_ => this.ReferenceOrderSigma(_, sd, mean))
                .Where(_ => _.Item1 > 0 && _.Item1 > this.parameters.Sigma)
                .Where(_ => this.CheckIfOrderWouldNotOfExecuted(_, dataResponse.Response))
                .ToList();

            if (!ruleBreaches.Any())
            {
                return;
            }

            var position = new TradePosition(ruleBreaches.Select(_ => _.Item2).ToList());
            var poe      = ruleBreaches.Select(_ => this.ExecutionUnderNormalDistribution(_.Item2, mean, sd, _.Item1)).ToList();

            // wrong but should be a judgement
            var breach =
                new PlacingOrderWithNoIntentToExecuteRuleRuleBreach(
                    this.parameters.Windows.BackwardWindowSize,
                    position,
                    benchmarkOrder.Instrument,
                    this.OrganisationFactorValue,
                    mean,
                    sd,
                    poe,
                    this.parameters,
                    this.ruleContext,
                    null,
                    null,
                    this.UniverseDateTime);

            var alertEvent = new UniverseAlertEvent(Domain.Surveillance.Scheduling.Rules.PlacingOrderWithNoIntentToExecute, breach, this.ruleContext);

            this.alertStream.Add(alertEvent);
        }
Ejemplo n.º 24
0
 /// <summary>
 /// The run post order event.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 protected override void RunPostOrderEvent(ITradingHistoryStack history)
 {
     // we don't use post order event in ramping rule
 }
Ejemplo n.º 25
0
 /// <summary>
 /// The run initial submission event.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 protected override void RunInitialSubmissionEvent(ITradingHistoryStack history)
 {
     // we don't use post order event in ramping rule
 }
Ejemplo n.º 26
0
 /// <summary>
 /// The run order filled event.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 public override void RunOrderFilledEvent(ITradingHistoryStack history)
 {
     // we don't analyse rules based on fills in the layering rule
 }
 /// <summary>
 /// The run post order event delayed.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 protected override void RunPostOrderEventDelayed(ITradingHistoryStack history)
 {
     // do nothing
 }
Ejemplo n.º 28
0
        /// <summary>
        /// The run post order event.
        /// </summary>
        /// <param name="history">
        /// The history.
        /// </param>
        protected override void RunPostOrderEvent(ITradingHistoryStack history)
        {
            if (!this.processingMarketClose ||
                this.latestMarketClosure == null)
            {
                return;
            }

            history.ArchiveExpiredActiveItems(this.latestMarketClosure.MarketClose);

            var securities = history.ActiveTradeHistory();

            if (!securities.Any())
            {
                // no securities were being traded within the market closure time window
                return;
            }

            // filter the security list by the mic of the closing market....
            var filteredMarketSecurities =
                securities
                .Where(i =>
                       string.Equals(
                           i.Market?.MarketIdentifierCode,
                           this.latestMarketClosure.MarketId,
                           StringComparison.InvariantCultureIgnoreCase))
                .ToList();

            if (!filteredMarketSecurities.Any())
            {
                // no relevant securities were being traded within the market closure time window
                return;
            }

            var marketSecurities = new Stack <Order>(filteredMarketSecurities);

            VolumeBreach dailyVolumeBreach = null;

            if (this.equitiesParameters.PercentageThresholdDailyVolume != null)
            {
                dailyVolumeBreach = this.CheckDailyVolumeTraded(marketSecurities);
            }

            VolumeBreach windowVolumeBreach = null;

            if (this.equitiesParameters.PercentageThresholdWindowVolume != null)
            {
                windowVolumeBreach = this.CheckWindowVolumeTraded(marketSecurities);
            }

            if ((dailyVolumeBreach == null || !dailyVolumeBreach.HasBreach()) &&
                (windowVolumeBreach == null || !windowVolumeBreach.HasBreach()))
            {
                this.logger.LogInformation($"had no breaches for {marketSecurities.FirstOrDefault()?.Instrument?.Identifiers} at {UniverseDateTime}");
                return;
            }

            var position = new TradePosition(marketSecurities.ToList());

            // wrong but should be a judgement
            var breach = new MarkingTheCloseBreach(
                this.OrganisationFactorValue,
                this.ruleContext.SystemProcessOperationContext(),
                this.ruleContext.CorrelationId(),
                this.equitiesParameters.Windows.BackwardWindowSize,
                marketSecurities.FirstOrDefault()?.Instrument,
                this.latestMarketClosure,
                position,
                this.equitiesParameters,
                dailyVolumeBreach ?? new VolumeBreach(),
                windowVolumeBreach ?? new VolumeBreach(),
                null,
                null,
                this.UniverseDateTime);

            this.logger.LogInformation($"had a breach for {marketSecurities.FirstOrDefault()?.Instrument?.Identifiers} at {UniverseDateTime}. Adding to alert stream.");
            var alertEvent = new UniverseAlertEvent(Domain.Surveillance.Scheduling.Rules.MarkingTheClose, breach, this.ruleContext);

            this.alertStream.Add(alertEvent);
        }
 /// <summary>
 /// The run order filled event delayed.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 public override void RunOrderFilledEventDelayed(ITradingHistoryStack history)
 {
     // do nothing
 }
Ejemplo n.º 30
0
 /// <summary>
 /// The run post order event delayed triggered method with future window delay offset.
 /// </summary>
 /// <param name="history">
 /// The history.
 /// </param>
 protected override void RunPostOrderEventDelayed(ITradingHistoryStack history)
 {
     this.EvaluateHighProfits(history, this.FutureUniverseFixedIncomeIntradayCache);
 }