/// <summary> /// Initializes a new instance of the <see cref="BaseUniverseRule"/> class. /// </summary> /// <param name="tradeBackwardWindowSize"> /// The trade backward window size. /// </param> /// <param name="marketBackwardWindowSize"> /// The market backward window size. /// </param> /// <param name="forwardWindowSize"> /// The forward window size. /// </param> /// <param name="rules"> /// The rules. /// </param> /// <param name="version"> /// The version. /// </param> /// <param name="name"> /// The name. /// </param> /// <param name="ruleContext"> /// The rule context. /// </param> /// <param name="equityFactory"> /// The equity factory. /// </param> /// <param name="fixedIncomeFactory"> /// The fixed income factory. /// </param> /// <param name="runMode"> /// The run mode. /// </param> /// <param name="logger"> /// The logger. /// </param> /// <param name="tradingStackLogger"> /// The trading stack logger. /// </param> protected BaseUniverseRule( TimeSpan tradeBackwardWindowSize, TimeSpan marketBackwardWindowSize, TimeSpan forwardWindowSize, Rules rules, string version, string name, ISystemProcessOperationRunRuleContext ruleContext, IUniverseEquityMarketCacheFactory equityFactory, IUniverseFixedIncomeMarketCacheFactory fixedIncomeFactory, RuleRunMode runMode, ILogger logger, ILogger <TradingHistoryStack> tradingStackLogger) { this.TradeBackwardWindowSize = tradeBackwardWindowSize; this.ForwardWindowSize = forwardWindowSize; this.Rule = rules; this.Version = version ?? string.Empty; this.UniverseEquityIntradayCache = equityFactory?.BuildIntraday(marketBackwardWindowSize, runMode) ?? throw new ArgumentNullException(nameof(equityFactory)); this.FutureUniverseEquityIntradayCache = equityFactory?.BuildIntraday(forwardWindowSize, runMode) ?? throw new ArgumentNullException(nameof(equityFactory)); this.UniverseEquityInterdayCache = equityFactory?.BuildInterday(runMode) ?? throw new ArgumentNullException(nameof(equityFactory)); this.UniverseFixedIncomeIntradayCache = fixedIncomeFactory?.BuildIntraday(marketBackwardWindowSize, runMode) ?? throw new ArgumentNullException(nameof(fixedIncomeFactory)); this.FutureUniverseFixedIncomeIntradayCache = fixedIncomeFactory?.BuildIntraday(forwardWindowSize, runMode) ?? throw new ArgumentNullException(nameof(fixedIncomeFactory)); this.UniverseFixedIncomeInterdayCache = fixedIncomeFactory?.BuildInterday(runMode) ?? throw new ArgumentNullException(nameof(fixedIncomeFactory)); this.TradingHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(); this.TradingFillsHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(); this.TradingInitialHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(); this.DelayedTradingHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(); this.DelayedTradingFillsHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(); this.DelayedTradingInitialHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(); this.RuleCtx = ruleContext ?? throw new ArgumentNullException(nameof(ruleContext)); this.name = name ?? "Unnamed rule"; this.RunMode = runMode; this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.tradingStackLogger = tradingStackLogger ?? throw new ArgumentNullException(nameof(tradingStackLogger)); }
/// <summary> /// The base clone. /// </summary> public void BaseClone() { this.UniverseEquityIntradayCache = (IUniverseEquityIntraDayCache)this.UniverseEquityIntradayCache.Clone(); this.UniverseEquityInterdayCache = (IUniverseEquityInterDayCache)this.UniverseEquityInterdayCache.Clone(); this.FutureUniverseEquityIntradayCache = (IUniverseEquityIntraDayCache)this.FutureUniverseEquityIntradayCache.Clone(); this.UniverseFixedIncomeInterdayCache = (IUniverseFixedIncomeInterDayCache)this.UniverseFixedIncomeInterdayCache.Clone(); this.UniverseFixedIncomeIntradayCache = (IUniverseFixedIncomeIntraDayCache)this.UniverseFixedIncomeIntradayCache.Clone(); this.FutureUniverseFixedIncomeIntradayCache = (IUniverseFixedIncomeIntraDayCache)this.FutureUniverseFixedIncomeIntradayCache.Clone(); this.TradingHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(this.TradingHistory); this.TradingFillsHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(this.TradingFillsHistory); this.TradingInitialHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(this.TradingInitialHistory); this.DelayedTradingHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(this.DelayedTradingHistory); this.DelayedTradingFillsHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(this.DelayedTradingFillsHistory); this.DelayedTradingInitialHistory = new ConcurrentDictionary <InstrumentIdentifiers, ITradingHistoryStack>(this.DelayedTradingInitialHistory); }
public IMarketDataCacheStrategy IntradayStrategy(IUniverseFixedIncomeIntraDayCache cache) { return(new FixedIncomeIntraDayMarketCacheStrategy(cache)); }
/// <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); }
public FixedIncomeIntraDayMarketCacheStrategy(IUniverseFixedIncomeIntraDayCache cache) { this._cache = cache ?? throw new ArgumentNullException(nameof(cache)); }