/// <summary> /// Will first check and add all the required conversion rate securities /// and later will seed an initial value to them. /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="universeSelection">The universe selection instance</param> public static void SetupCurrencyConversions( IAlgorithm algorithm, UniverseSelection universeSelection) { // this is needed to have non-zero currency conversion rates during warmup // will also set the Cash.ConversionRateSecurity universeSelection.EnsureCurrencyDataFeeds(SecurityChanges.None); // now set conversion rates var cashToUpdate = algorithm.Portfolio.CashBook.Values .Where(x => x.ConversionRateSecurity != null && x.ConversionRate == 0) .ToList(); var historyRequestFactory = new HistoryRequestFactory(algorithm); var historyRequests = new List <HistoryRequest>(); foreach (var cash in cashToUpdate) { var configs = algorithm .SubscriptionManager .SubscriptionDataConfigService .GetSubscriptionDataConfigs(cash.ConversionRateSecurity.Symbol, includeInternalConfigs: true); // we need to order and select a specific configuration type // so the conversion rate is deterministic var configToUse = configs.OrderBy(x => x.TickType).First(); var hours = cash.ConversionRateSecurity.Exchange.Hours; var resolution = configs.GetHighestResolution(); var startTime = historyRequestFactory.GetStartTimeAlgoTz( cash.ConversionRateSecurity.Symbol, 10, resolution, hours, configToUse.DataTimeZone); var endTime = algorithm.Time; historyRequests.Add(historyRequestFactory.CreateHistoryRequest( configToUse, startTime, endTime, cash.ConversionRateSecurity.Exchange.Hours, resolution)); } var slices = algorithm.HistoryProvider.GetHistory(historyRequests, algorithm.TimeZone); slices.PushThrough(data => { foreach (var cash in cashToUpdate .Where(x => x.ConversionRateSecurity.Symbol == data.Symbol)) { cash.Update(data); } }); Log.Trace("BaseSetupHandler.SetupCurrencyConversions():" + $"{Environment.NewLine}{algorithm.Portfolio.CashBook}"); }
/// <summary> /// Will first check and add all the required conversion rate securities /// and later will seed an initial value to them. /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="universeSelection">The universe selection instance</param> public static void SetupCurrencyConversions( IAlgorithm algorithm, UniverseSelection universeSelection) { // this is needed to have non-zero currency conversion rates during warmup // will also set the Cash.ConversionRateSecurity universeSelection.EnsureCurrencyDataFeeds(SecurityChanges.None); // now set conversion rates var cashToUpdate = algorithm.Portfolio.CashBook.Values .Where(x => x.ConversionRateSecurity != null && x.ConversionRate == 0) .ToList(); var historyRequestFactory = new HistoryRequestFactory(algorithm); var historyRequests = new List <HistoryRequest>(); foreach (var cash in cashToUpdate) { // if we already added a history request for this security, skip if (historyRequests.Any(x => x.Symbol == cash.ConversionRateSecurity.Symbol)) { continue; } var configs = algorithm .SubscriptionManager .SubscriptionDataConfigService .GetSubscriptionDataConfigs(cash.ConversionRateSecurity.Symbol); var resolution = configs.GetHighestResolution(); var startTime = historyRequestFactory.GetStartTimeAlgoTz( cash.ConversionRateSecurity.Symbol, 1, resolution, cash.ConversionRateSecurity.Exchange.Hours); var endTime = algorithm.Time.RoundDown(resolution.ToTimeSpan()); // we need to order and select a specific configuration type // so the conversion rate is deterministic var configToUse = configs.OrderBy(x => x.TickType).First(); historyRequests.Add(historyRequestFactory.CreateHistoryRequest( configToUse, startTime, endTime, cash.ConversionRateSecurity.Exchange.Hours, resolution)); } var slices = algorithm.HistoryProvider.GetHistory(historyRequests, algorithm.TimeZone); slices.PushThrough(data => { foreach (var cash in cashToUpdate .Where(x => x.ConversionRateSecurity.Symbol == data.Symbol)) { cash.Update(data); } }); }
/// <summary> /// Will first check and add all the required conversion rate securities /// and later will seed an initial value to them. /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="universeSelection">The universe selection instance</param> public static void SetupCurrencyConversions( IAlgorithm algorithm, UniverseSelection universeSelection) { // this is needed to have non-zero currency conversion rates during warmup // will also set the Cash.ConversionRateSecurity universeSelection.EnsureCurrencyDataFeeds(SecurityChanges.None); // now set conversion rates var cashToUpdate = algorithm.Portfolio.CashBook.Values .Where(x => x.CurrencyConversion != null && x.ConversionRate == 0) .ToList(); var securitiesToUpdate = cashToUpdate .SelectMany(x => x.CurrencyConversion.ConversionRateSecurities) .Distinct() .ToList(); var historyRequestFactory = new HistoryRequestFactory(algorithm); var historyRequests = new List <HistoryRequest>(); foreach (var security in securitiesToUpdate) { var configs = algorithm .SubscriptionManager .SubscriptionDataConfigService .GetSubscriptionDataConfigs(security.Symbol, includeInternalConfigs: true); // we need to order and select a specific configuration type // so the conversion rate is deterministic var configToUse = configs.OrderBy(x => x.TickType).First(); var hours = security.Exchange.Hours; var resolution = configs.GetHighestResolution(); var startTime = historyRequestFactory.GetStartTimeAlgoTz( security.Symbol, 10, resolution, hours, configToUse.DataTimeZone); var endTime = algorithm.Time; historyRequests.Add(historyRequestFactory.CreateHistoryRequest( configToUse, startTime, endTime, security.Exchange.Hours, resolution)); } // Attempt to get history for these requests and update cash var slices = algorithm.HistoryProvider.GetHistory(historyRequests, algorithm.TimeZone); slices.PushThrough(data => { foreach (var security in securitiesToUpdate.Where(x => x.Symbol == data.Symbol)) { security.SetMarketPrice(data); } }); foreach (var cash in cashToUpdate) { cash.Update(); } // Any remaining unassigned cash will attempt to fall back to a daily resolution history request to resolve var unassignedCash = cashToUpdate.Where(x => x.ConversionRate == 0).ToList(); if (unassignedCash.Any()) { Log.Error( $"Failed to assign conversion rates for the following cash: {string.Join(",", unassignedCash.Select(x => x.Symbol))}." + $" Attempting to request daily resolution history to resolve conversion rate"); var unassignedCashSymbols = unassignedCash .SelectMany(x => x.SecuritySymbols) .ToHashSet(); var replacementHistoryRequests = new List <HistoryRequest>(); foreach (var request in historyRequests.Where(x => unassignedCashSymbols.Contains(x.Symbol) && x.Resolution < Resolution.Daily)) { var newRequest = new HistoryRequest(request.EndTimeUtc.AddDays(-10), request.EndTimeUtc, request.DataType, request.Symbol, Resolution.Daily, request.ExchangeHours, request.DataTimeZone, request.FillForwardResolution, request.IncludeExtendedMarketHours, request.IsCustomData, request.DataNormalizationMode, request.TickType); replacementHistoryRequests.Add(newRequest); } slices = algorithm.HistoryProvider.GetHistory(replacementHistoryRequests, algorithm.TimeZone); slices.PushThrough(data => { foreach (var security in securitiesToUpdate.Where(x => x.Symbol == data.Symbol)) { security.SetMarketPrice(data); } }); foreach (var cash in unassignedCash) { cash.Update(); } } Log.Trace("BaseSetupHandler.SetupCurrencyConversions():" + $"{Environment.NewLine}{algorithm.Portfolio.CashBook}"); }