public void Setup() { this.fixedIncomeHighProfitJudgement = A.Fake <IFixedIncomeHighProfitJudgement>(); this.ruleBreachContext = A.Fake <IRuleBreachContext>(); this.fixedIncomeParameters = A.Fake <IHighProfitsRuleFixedIncomeParameters>(); this.profitBreakdown = A.Fake <IExchangeRateProfitBreakdown>(); }
public void Setup() { this.logger = A.Fake <ILogger <FixedIncomeHighProfitJudgementMapper> >(); this.judgementContext = A.Fake <IFixedIncomeHighProfitJudgementContext>(); this.ruleBreachContext = A.Fake <IRuleBreachContext>(); this.parameters = A.Fake <IHighProfitsRuleFixedIncomeParameters>(); this.profitBreakdown = A.Fake <IExchangeRateProfitBreakdown>(); }
/// <summary> /// The set judgement for full analysis covers downstream logic for its code branch. /// </summary> /// <param name="absoluteProfit"> /// The absolute profit. /// </param> /// <param name="profitRatio"> /// The profit ratio. /// </param> /// <param name="hasHighProfitAbsolute"> /// The has high profit absolute. /// </param> /// <param name="hasHighProfitPercentage"> /// The has high profit percentage. /// </param> /// <param name="exchangeRateProfits"> /// The exchange rate profits. /// </param> /// <param name="ruleBreachContext"> /// The rule breach context. /// </param> /// <param name="orderUnderAnalysis"> /// The order under analysis. /// </param> private void SetJudgementForFullAnalysis( Money absoluteProfit, decimal profitRatio, bool hasHighProfitAbsolute, bool hasHighProfitPercentage, IExchangeRateProfitBreakdown exchangeRateProfits, RuleBreachContext ruleBreachContext, Order orderUnderAnalysis) { var absoluteHighProfit = hasHighProfitAbsolute ? absoluteProfit.Value : (decimal?)null; var absoluteHighProfitCurrency = hasHighProfitAbsolute ? absoluteProfit.Currency.Code : null; var percentageHighProfit = hasHighProfitPercentage ? profitRatio : (decimal?)null; var jsonParameters = JsonConvert.SerializeObject(this.FixedIncomeParameters); var judgement = new FixedIncomeHighProfitJudgement( this.RuleCtx.RuleParameterId(), this.RuleCtx.CorrelationId(), orderUnderAnalysis?.ReddeerOrderId?.ToString(), orderUnderAnalysis?.OrderId, absoluteHighProfit, absoluteHighProfitCurrency, percentageHighProfit, jsonParameters, false, false); this.JudgementService.Judgement( new FixedIncomeHighProfitJudgementContext( judgement, hasHighProfitAbsolute || hasHighProfitPercentage, ruleBreachContext, this.FixedIncomeParameters, absoluteProfit, absoluteProfit.Currency.Symbol, profitRatio, hasHighProfitAbsolute, hasHighProfitPercentage, exchangeRateProfits)); }
/// <summary> /// Initializes a new instance of the <see cref="FixedIncomeHighProfitJudgementContext"/> class. /// </summary> /// <param name="judgement"> /// The judgement. /// </param> /// <param name="projectToAlert"> /// The project to alert. /// </param> /// <param name="ruleBreachContext"> /// The rule breach context. /// </param> /// <param name="fixedIncomeParameters"> /// The fixed income parameters. /// </param> /// <param name="absoluteProfits"> /// The absolute profits. /// </param> /// <param name="absoluteProfitCurrency"> /// The absolute profit currency. /// </param> /// <param name="relativeProfits"> /// The relative profits. /// </param> /// <param name="hasAbsoluteProfitBreach"> /// The has absolute profit breach. /// </param> /// <param name="hasRelativeProfitBreach"> /// The has relative profit breach. /// </param> /// <param name="profitBreakdown"> /// The profit breakdown. /// </param> public FixedIncomeHighProfitJudgementContext( IFixedIncomeHighProfitJudgement judgement, bool projectToAlert, IRuleBreachContext ruleBreachContext, IHighProfitsRuleFixedIncomeParameters fixedIncomeParameters, Money?absoluteProfits, string absoluteProfitCurrency, decimal?relativeProfits, bool hasAbsoluteProfitBreach, bool hasRelativeProfitBreach, IExchangeRateProfitBreakdown profitBreakdown) { this.Judgement = judgement; this.RaiseRuleViolation = projectToAlert; this.RuleBreachContext = ruleBreachContext; this.FixedIncomeParameters = fixedIncomeParameters; this.AbsoluteProfits = absoluteProfits; this.AbsoluteProfitCurrency = absoluteProfitCurrency; this.RelativeProfits = relativeProfits; this.HasAbsoluteProfitBreach = hasAbsoluteProfitBreach; this.HasRelativeProfitBreach = hasRelativeProfitBreach; this.ExchangeRateProfits = profitBreakdown; }
/// <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); }
/// <summary> /// The evaluate high profits. /// </summary> /// <param name="history"> /// The history. /// </param> /// <param name="intradayCache"> /// The intraday cache. /// </param> protected void EvaluateHighProfits(ITradingHistoryStack history, IUniverseEquityIntraDayCache intradayCache) { if (!this.RunRuleGuard(history)) { return; } var orderUnderAnalysis = this.UniverseEvent.UnderlyingEvent as Order; var activeTrades = history.ActiveTradeHistory(); var liveTrades = activeTrades.Where(at => at.OrderStatus() == OrderStatus.Filled).ToList(); if (orderUnderAnalysis == null) { orderUnderAnalysis = activeTrades.LastOrDefault(); } if (!liveTrades.Any()) { this.SetNoLiveTradesJudgement(orderUnderAnalysis); return; } var targetCurrency = new Currency(this.EquitiesParameters.HighProfitCurrencyConversionTargetCurrency); var allTradesInCommonCurrency = liveTrades.Any() && liveTrades.All( x => string.Equals( x.OrderCurrency.Code, targetCurrency.Code, StringComparison.InvariantCultureIgnoreCase)); var costCalculator = this.GetCostCalculator(allTradesInCommonCurrency, targetCurrency); var revenueCalculator = this.GetRevenueCalculator(allTradesInCommonCurrency, targetCurrency); var marketCache = this.MarketClosureRule ? this.MarketDataCacheFactory.InterdayStrategy(this.UniverseEquityInterdayCache) : this.MarketDataCacheFactory.IntradayStrategy(intradayCache); var costTask = costCalculator.CalculateCostOfPosition(liveTrades, this.UniverseDateTime, this.RuleContext); var revenueTask = revenueCalculator.CalculateRevenueOfPosition( liveTrades, this.UniverseDateTime, this.RuleContext, marketCache); var cost = costTask.Result; var revenueResponse = revenueTask.Result; if (revenueResponse.HadMissingMarketData) { 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 {liveTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}. Returning."); this.NoRevenueOrCostJudgement(orderUnderAnalysis); return; } if (cost == null || cost.Value.Value <= 0) { this.Logger.LogError( $"something went wrong. We have calculable revenues but not costs for {liveTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}. Returning."); this.NoRevenueOrCostJudgement(orderUnderAnalysis); return; } if (!revenue.Value.DenominatedInCommonCurrency(cost.Value)) { var convertedCostTask = this.currencyConversionService.Convert(new[] { cost.Value }, revenue.Value.Currency, UniverseDateTime, RuleCtx); var convertedCost = convertedCostTask.Result; if (convertedCost == null) { this.Logger.LogError($"Currency of revenue {revenue.Value.Currency} - currency of costs {cost.Value.Currency} for trade {liveTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}."); return; } cost = convertedCost.Value; } this.Logger.LogInformation($"Calculating absolute profit 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($"Calculating profit ratio 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($"Calculating success profit ratio Currency 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.EquitiesParameters.UseCurrencyConversions && !string.IsNullOrEmpty( this.EquitiesParameters.HighProfitCurrencyConversionTargetCurrency)) { this.Logger.LogInformation( $"is set to use currency conversions and has a target conversion currency to {this.EquitiesParameters.HighProfitCurrencyConversionTargetCurrency}. Calling set exchange rate profits."); exchangeRateProfits = this.SetExchangeRateProfits(liveTrades); } RuleBreachContext ruleBreachContext = null; if (hasHighProfitAbsolute || hasHighProfitPercentage) { this.Logger.LogInformation( $"had a breach for {liveTrades.FirstOrDefault()?.Instrument?.Identifiers} at {this.UniverseDateTime}. High Profit Absolute {hasHighProfitAbsolute} and High Profit Percentage {hasHighProfitPercentage}."); ruleBreachContext = new RuleBreachContext( this.EquitiesParameters.Windows.BackwardWindowSize + this.EquitiesParameters.Windows.FutureWindowSize, new TradePosition(liveTrades), liveTrades.FirstOrDefault(_ => _?.Instrument != null)?.Instrument, this.RuleContext.IsBackTest(), this.RuleContext.RuleParameterId(), this.RuleContext.SystemProcessOperationContext().Id.ToString(), this.RuleContext.CorrelationId(), this.OrganisationFactorValue, this.EquitiesParameters, this.UniverseDateTime); } this.SetJudgementForFullAnalysis( absoluteProfit, profitRatio, hasHighProfitAbsolute, hasHighProfitPercentage, exchangeRateProfits, ruleBreachContext, orderUnderAnalysis); }