17 using System.Collections.Generic;
19 using System.Linq.Expressions;
20 using System.Globalization;
22 using NodaTime.TimeZones;
42 using System.Collections.Concurrent;
58 using Newtonsoft.Json;
69 #region Documentation Attribute Categories
70 const string AddingData =
"Adding Data";
71 const string AlgorithmFramework =
"Algorithm Framework";
72 const string Charting =
"Charting";
73 const string ConsolidatingData =
"Consolidating Data";
74 const string HandlingData =
"Handling Data";
75 const string HistoricalData =
"Historical Data";
76 const string Indicators =
"Indicators";
77 const string LiveTrading =
"Live Trading";
78 const string Logging =
"Logging";
79 const string MachineLearning =
"Machine Learning";
80 const string Modeling =
"Modeling";
81 const string ParameterAndOptimization =
"Parameter and Optimization";
82 const string ScheduledEvents =
"Scheduled Events";
83 const string SecuritiesAndPortfolio =
"Securities and Portfolio";
84 const string TradingAndOrders =
"Trading and Orders";
85 const string Universes =
"Universes";
86 const string StatisticsTag =
"Statistics";
102 private string _name;
103 private HashSet<string> _tags;
104 private bool _tagsLimitReachedLogSent;
105 private bool _tagsCollectionTruncatedLogSent;
106 private DateTime _start;
107 private DateTime _startDate;
108 private DateTime _endDate;
109 private bool _locked;
110 private bool _liveMode;
113 private string _algorithmId =
"";
114 private ConcurrentQueue<string> _debugMessages =
new ConcurrentQueue<string>();
115 private ConcurrentQueue<string> _logMessages =
new ConcurrentQueue<string>();
116 private ConcurrentQueue<string> _errorMessages =
new ConcurrentQueue<string>();
120 private readonly HashSet<string> _oneTimeCommandErrors =
new();
121 private readonly Dictionary<string, Func<CallbackCommand, bool?>> _registeredCommands =
new(StringComparer.InvariantCultureIgnoreCase);
124 private string _previousDebugMessage =
"";
125 private string _previousErrorMessage =
"";
138 private bool _checkedForOnDataSlice;
139 private Action<Slice> _onDataSlice;
142 private bool _userSetSecurityInitializer;
145 private TimeSpan? _warmupTimeSpan;
146 private int? _warmupBarCount;
147 private Dictionary<string, string> _parameters =
new Dictionary<string, string>();
160 Name = GetType().Name;
172 _startDate =
new DateTime(1998, 01, 01);
326 return _brokerageModel;
330 _brokerageModel = value;
333 BrokerageName = Brokerages.BrokerageModel.GetBrokerageName(_brokerageModel);
335 catch (ArgumentOutOfRangeException)
476 [Obsolete(
"OptionChainProvider property is will soon be deprecated. " +
477 "The new OptionChain() method should be used to fetch equity and index option chains, " +
478 "which will contain additional data per contract, like daily price data, implied volatility and greeks.")]
509 throw new InvalidOperationException(
"Cannot set algorithm name after it is initialized.");
512 if (!
string.IsNullOrEmpty(value))
523 public HashSet<string>
Tags
536 var tags = value.Where(x => !
string.IsNullOrEmpty(x?.Trim())).ToList();
538 if (tags.Count >
MaxTagsCount && !_tagsCollectionTruncatedLogSent)
540 Log($
"Warning: The tags collection cannot contain more than {MaxTagsCount} items. It will be truncated.");
541 _tagsCollectionTruncatedLogSent =
true;
571 get {
return _localTimeKeeper.
LocalTime; }
580 get {
return _timeKeeper.UtcTime; }
590 get {
return _localTimeKeeper.
TimeZone; }
648 return _algorithmMode;
659 return _deploymentTarget;
672 return _debugMessages;
676 _debugMessages = value;
693 _logMessages = value;
713 return _errorMessages;
717 _errorMessages = value;
757 throw new NotImplementedException(
"Please override the Initialize() method");
768 if (_endDate < _startDate)
770 throw new ArgumentException(
"Please select an algorithm end date greater than start date.");
774 if (portfolioConstructionModel !=
null)
784 portfolioConstructionModel.RebalanceOnInsightChanges
793 Debug(
"Warning: rebalance portfolio settings are set but not supported by the current IPortfolioConstructionModel type: " +
794 $
"{PortfolioConstruction.GetType()}");
812 securityBenchmark.Security.Symbol, securityBenchmark.Security.Type);
815 Log($
"QCAlgorithm.PostInitialize(): Warning: Using a security benchmark of a different timezone ({benchmarkTimeZone})" +
816 $
" than the algorithm TimeZone ({TimeZone}) may lead to skewed and incorrect statistics. Use a higher resolution than daily to minimize.");
820 if (TryGetWarmupHistoryStartTime(out var result))
831 Debug(
"Accurate daily end-times now enabled by default. See more at https://qnt.co/3YHaWHL. To disable it and use legacy daily bars set self.settings.daily_precise_end_time = False.");
856 return _parameters.TryGetValue(name, out var value) ? value : defaultValue;
869 return _parameters.TryGetValue(name, out var strValue) &&
int.TryParse(strValue, out var value) ? value : defaultValue;
882 return _parameters.TryGetValue(name, out var strValue) &&
883 double.TryParse(strValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) ? value : defaultValue;
896 return _parameters.TryGetValue(name, out var strValue) &&
897 decimal.TryParse(strValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) ? value : defaultValue;
906 return _parameters.ToReadOnlyDictionary();
917 _parameters = parameters.ToDictionary();
922 catch (Exception err)
924 Error(
"Error applying parameter values: " + err.Message);
935 if (availableDataTypes ==
null)
940 foreach (var dataFeed
in availableDataTypes)
957 throw new Exception(
"SetSecurityInitializer() cannot be called after algorithm initialization. " +
958 "When you use the SetSecurityInitializer() method it will apply to all universes and manually added securities.");
961 if (_userSetSecurityInitializer)
963 Debug(
"Warning: SetSecurityInitializer() has already been called, existing security initializers in all universes will be overwritten.");
967 _userSetSecurityInitializer =
true;
976 [Obsolete(
"This method is deprecated. Please use this overload: SetSecurityInitializer(Action<Security> securityInitializer)")]
1034 if (!_checkedForOnDataSlice)
1036 _checkedForOnDataSlice =
true;
1038 var method = GetType().GetMethods()
1039 .Where(x => x.Name ==
"OnData")
1040 .Where(x => x.DeclaringType != typeof(
QCAlgorithm))
1041 .Where(x => x.GetParameters().Length == 1)
1042 .FirstOrDefault(x => x.GetParameters()[0].ParameterType == typeof(
Slice));
1049 var
self = Expression.Constant(
this);
1050 var parameter = Expression.Parameter(typeof(
Slice),
"data");
1051 var call = Expression.Call(
self, method, parameter);
1052 var lambda = Expression.Lambda<Action<Slice>>(call, parameter);
1053 _onDataSlice = lambda.Compile();
1056 if (_onDataSlice !=
null)
1058 _onDataSlice(slice);
1133 [Obsolete(
"This method is deprecated and will be removed after August 2021. Please use this overload: OnEndOfDay(Symbol symbol)")]
1231 _timeKeeper.SetUtcDateTime(frontier);
1248 tz = DateTimeZoneProviders.Tzdb[timeZone];
1250 catch (DateTimeZoneNotFoundException)
1252 throw new ArgumentException($
"TimeZone with id '{timeZone}' was not found. For a complete list of time zones please visit: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones");
1267 throw new InvalidOperationException(
"Algorithm.SetTimeZone(): Cannot change time zone after algorithm running.");
1270 if (timeZone ==
null)
throw new ArgumentNullException(nameof(timeZone));
1271 _timeKeeper.AddTimeZone(timeZone);
1272 _localTimeKeeper = _timeKeeper.GetLocalTimeKeeper(timeZone);
1283 _start = _startDate;
1290 SetLiveModeStartDate();
1315 if (!_userSetSecurityInitializer)
1323 var security = kvp.Value;
1328 var leverage = security.Leverage;
1333 security.SetLeverage(leverage);
1370 [Obsolete(
"Symbol implicit operator to string is provided for algorithm use only.")]
1378 throw new InvalidOperationException(
"Algorithm.SetBenchmark(): Cannot change Benchmark after algorithm initialized.");
1382 if (!
BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
1410 symbol =
Securities.FirstOrDefault(x => x.Key.Value == ticker).Key;
1415 Debug($
"Warning: SetBenchmark({ticker}): no existing symbol found, benchmark security will be added with {SecurityType.Equity} type.");
1435 throw new InvalidOperationException(
"Algorithm.SetBenchmark(): Cannot change Benchmark after algorithm initialized.");
1454 throw new InvalidOperationException(
"Algorithm.SetBenchmark(): Cannot change Benchmark after algorithm initialized.");
1489 if (!
string.IsNullOrEmpty(tag?.Trim()))
1493 if (!_tagsLimitReachedLogSent)
1495 Log($
"Warning: AddTag({tag}): Unable to add tag. Tags are limited to a maximum of {MaxTagsCount}.");
1496 _tagsLimitReachedLogSent =
true;
1531 throw new InvalidOperationException(
"Algorithm.SetAccountCurrency(): " +
1532 "Cannot change AccountCurrency after algorithm initialized.");
1535 if (startingCash ==
null)
1537 Debug($
"Changing account currency from {AccountCurrency} to {accountCurrency}...");
1541 Debug($
"Changing account currency from {AccountCurrency} to {accountCurrency}, with a starting cash of {startingCash}...");
1556 SetCash((decimal)startingCash);
1568 SetCash((decimal)startingCash);
1585 throw new InvalidOperationException(
"Algorithm.SetCash(): Cannot change cash available after algorithm initialized.");
1596 public void SetCash(
string symbol, decimal startingCash, decimal conversionRate = 0)
1604 throw new InvalidOperationException(
"Algorithm.SetCash(): Cannot change cash available after algorithm initialized.");
1623 var start =
new DateTime(year, month, day);
1630 catch (Exception err)
1632 throw new ArgumentException($
"Date Invalid: {err.Message}");
1649 var end =
new DateTime(year, month, day);
1652 end = end.Date.AddDays(1).Subtract(TimeSpan.FromTicks(1));
1656 catch (Exception err)
1658 throw new ArgumentException($
"Date Invalid: {err.Message}");
1670 _algorithmId = algorithmId;
1683 if (_liveMode)
return;
1686 start = start.RoundDown(TimeSpan.FromDays(1));
1690 if (start < (
new DateTime(1900, 01, 01)))
1692 throw new ArgumentOutOfRangeException(nameof(start),
"Please select a start date after January 1st, 1900.");
1696 var todayInAlgorithmTimeZone = DateTime.UtcNow.ConvertFromUtc(
TimeZone).Date;
1697 if (start > todayInAlgorithmTimeZone)
1699 throw new ArgumentOutOfRangeException(nameof(start),
"Please select start date less than today");
1705 _start = _startDate = start;
1710 throw new InvalidOperationException(
"Algorithm.SetStartDate(): Cannot change start date after algorithm initialized.");
1724 if (_liveMode)
return;
1729 throw new InvalidOperationException(
"Algorithm.SetEndDate(): Cannot change end date after algorithm initialized.");
1734 var yesterdayInAlgorithmTimeZone = DateTime.UtcNow.ConvertFromUtc(
TimeZone).Date.AddDays(-1);
1735 if (end > yesterdayInAlgorithmTimeZone)
1737 end = yesterdayInAlgorithmTimeZone;
1741 _endDate = end.RoundDown(TimeSpan.FromDays(1)).AddDays(1).AddTicks(-1);
1782 SetLiveModeStartDate();
1796 _algorithmMode = algorithmMode;
1809 _deploymentTarget = deploymentTarget;
1838 return AddSecurity(securityType, ticker, resolution, fillForward,
Security.
NullLeverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1857 return AddSecurity(securityType, ticker, resolution,
null, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1879 return AddOption(ticker, resolution, market, fillForward, leverage);
1884 return AddFuture(ticker, resolution, market, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1891 if (!
BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
1893 throw new KeyNotFoundException($
"No default market set for security type: {securityType}");
1899 symbol.ID.Market != market ||
1900 symbol.SecurityType != securityType)
1905 return AddSecurity(symbol, resolution, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1907 catch (Exception err)
1909 Error(
"Algorithm.AddSecurity(): " + err);
1932 var contractOffset = (uint)Math.Abs(contractDepthOffset);
1935 throw new ArgumentOutOfRangeException(nameof(contractDepthOffset), $
"'contractDepthOffset' current maximum value is {Futures.MaximumContractDepthOffset}." +
1936 $
" Front month (0) and only {Futures.MaximumContractDepthOffset} back month contracts are currently supported.");
1944 return AddOptionContract(symbol, resolution, fillForward, leverage, extendedMarketHours);
1947 var securityResolution = resolution;
1948 var securityFillForward = fillForward;
1953 securityFillForward =
false;
1956 var isFilteredSubscription = !isCanonical;
1957 List<SubscriptionDataConfig> configs;
1960 if (dataNormalizationMode.HasValue)
1964 securityFillForward,
1965 extendedMarketHours,
1966 isFilteredSubscription,
1967 dataNormalizationMode: dataNormalizationMode.
Value,
1968 contractDepthOffset: (uint)contractDepthOffset);
1974 securityFillForward,
1975 extendedMarketHours,
1976 isFilteredSubscription,
1977 contractDepthOffset: (uint)contractDepthOffset);
1991 var canonicalConfig = configs.First();
1992 var universeSettingsResolution = canonicalConfig.Resolution;
2010 GetResolution(symbol, resolution,
null), isCanonical:
false);
2013 ExtendedMarketHours = extendedMarketHours,
2016 ContractDepthOffset = (int)contractOffset,
2017 SubscriptionDataTypes = dataTypes,
2025 continuousContractSymbol.ID.Symbol,
2026 continuousContractSymbol.ID.SecurityType,
2027 security.Exchange.Hours);
2038 return AddToUserDefinedUniverse(security, configs);
2056 return AddSecurity<Equity>(
SecurityType.Equity, ticker, resolution, market, fillForward, leverage, extendedMarketHours, normalizationMode: dataNormalizationMode);
2075 throw new KeyNotFoundException($
"No default market set for security type: {SecurityType.Option}");
2080 return AddOption(underlyingSymbol, resolution, market, fillForward, leverage);
2098 return AddOption(underlying,
null, resolution, market, fillForward, leverage);
2122 if (!
BrokerageModel.DefaultMarkets.TryGetValue(optionType, out market))
2124 throw new KeyNotFoundException($
"No default market set for security type: {optionType}");
2131 if (!
string.IsNullOrEmpty(targetOption))
2133 alias = $
"?{targetOption}";
2137 alias = $
"?{underlying.Value}";
2140 canonicalSymbol.ID.Market != market ||
2141 !canonicalSymbol.SecurityType.IsOption())
2165 bool fillForward =
true, decimal leverage =
Security.
NullLeverage,
bool extendedMarketHours =
false,
2173 throw new KeyNotFoundException($
"No default market set for security type: {SecurityType.Future}");
2178 var alias =
"/" + ticker;
2180 canonicalSymbol.ID.Market != market ||
2186 return (
Future)
AddSecurity(canonicalSymbol, resolution, fillForward, leverage, extendedMarketHours, dataMappingMode: dataMappingMode,
2187 dataNormalizationMode: dataNormalizationMode, contractDepthOffset: contractDepthOffset);
2203 return (
Future)
AddSecurity(symbol, resolution, fillForward, leverage, extendedMarketHours);
2218 throw new ArgumentException(
"Symbol provided must be canonical (i.e. the Symbol returned from AddFuture(), not AddFutureContract().");
2240 throw new ArgumentException(
"Expected non-canonical Symbol (i.e. a Symbol representing a specific Future contract");
2243 return AddOptionContract(symbol, resolution, fillForward, leverage, extendedMarketHours);
2257 return AddIndexOption(underlying,
null, resolution, market, fillForward);
2286 throw new ArgumentException(
"Symbol provided must be of type SecurityType.Index");
2306 throw new KeyNotFoundException($
"No default market set for underlying security type: {SecurityType.Index}");
2311 targetOption, resolution, fillForward);
2327 throw new ArgumentException(
"Symbol provided must be non-canonical and of type SecurityType.IndexOption");
2348 throw new ArgumentException($
"Unexpected option symbol {symbol}. " +
2349 $
"Please provide a valid option contract with it's underlying symbol set.");
2355 List<SubscriptionDataConfig> underlyingConfigs;
2360 underlyingSecurity =
AddSecurity(underlying, resolution, fillForward, leverage, extendedMarketHours);
2364 else if (underlyingSecurity !=
null && underlyingSecurity.IsDelisted)
2366 throw new ArgumentException($
"The underlying {underlying.SecurityType} asset ({underlying.Value}) is delisted " +
2367 $
"(current time is {Time})");
2374 var dataNormalizationMode = underlyingConfigs.DataNormalizationMode();
2379 throw new ArgumentException($
"The underlying {underlying.SecurityType} asset ({underlying.Value}) is set to " +
2380 $
"{dataNormalizationMode}, please change this to DataNormalizationMode.Raw with the " +
2381 "SetDataNormalization() method"
2392 underlyingSecurity.RefreshDataNormalizationModeProperty();
2404 Resolution = underlyingConfigs.GetHighestResolution(),
2405 ExtendedMarketHours = extendedMarketHours
2412 if (optionUniverse !=
null)
2414 foreach (var subscriptionDataConfig
in configs.Concat(underlyingConfigs))
2416 optionUniverse.
Add(subscriptionDataConfig);
2435 return AddSecurity<Forex>(
SecurityType.Forex, ticker, resolution, market, fillForward, leverage,
false);
2450 return AddSecurity<Cfd>(
SecurityType.Cfd, ticker, resolution, market, fillForward, leverage,
false);
2463 public Index
AddIndex(
string ticker,
Resolution? resolution =
null,
string market =
null,
bool fillForward =
true)
2465 var index = AddSecurity<Index>(
SecurityType.Index, ticker, resolution, market, fillForward, 1,
false);
2481 return AddSecurity<Crypto>(
SecurityType.Crypto, ticker, resolution, market, fillForward, leverage,
false);
2496 return AddSecurity<CryptoFuture>(
SecurityType.CryptoFuture, ticker, resolution, market, fillForward, leverage,
false);
2532 if (security.Invested)
2538 security.Cache.Reset();
2541 security.IsTradable =
false;
2545 foreach (var kvp
in UniverseManager.Where(x => x.Value.Configuration.Symbol == symbol
2548 var universe = kvp.Value;
2550 var otherUniverses =
UniverseManager.Select(ukvp => ukvp.Value).Where(u => !ReferenceEquals(u, universe)).ToList();
2554 if (!otherUniverses.Any(u => u.Members.ContainsKey(underlying.Symbol)))
2562 foreach (var child
in universe.Members.Values.OrderBy(security1 => security1.Symbol))
2564 if (!otherUniverses.Any(u => u.Members.ContainsKey(child.Symbol)) && !child.Symbol.IsCanonical())
2572 _universeSelectionUniverses.Remove(security.Symbol);
2577 lock (_pendingUniverseAdditionsLock)
2583 universe.Remove(symbol);
2586 _pendingUserDefinedUniverseSecurityAdditions.RemoveAll(addition => addition.Security.Symbol == symbol);
2609 return AddData<T>(ticker, resolution, fillForward:
false, leverage: 1m);
2628 return AddData<T>(underlying, resolution, fillForward:
false, leverage: 1m);
2646 return AddData<T>(ticker, resolution,
null, fillForward, leverage);
2663 return AddData<T>(underlying, resolution,
null, fillForward, leverage);
2680 return AddData(typeof(
T), ticker, resolution, timeZone, fillForward, leverage);
2697 return AddData(typeof(
T), underlying, resolution, timeZone, fillForward, leverage);
2719 SetDatabaseEntries(key, properties, exchangeHours);
2722 return AddData(typeof(
T), ticker, resolution,
null, fillForward, leverage);
2734 if (!_liveMode && (
string.IsNullOrEmpty(message) || _previousDebugMessage == message))
return;
2735 _debugMessages.Enqueue(message);
2736 _previousDebugMessage = message;
2748 Debug(message.ToStringInvariant());
2760 Debug(message.ToStringInvariant());
2772 Debug(message.ToStringInvariant());
2782 public void Log(
string message)
2784 if (!_liveMode &&
string.IsNullOrEmpty(message))
return;
2785 _logMessages.Enqueue(message);
2797 Log(message.ToStringInvariant());
2807 public void Log(
double message)
2809 Log(message.ToStringInvariant());
2819 public void Log(decimal message)
2821 Log(message.ToStringInvariant());
2833 if (!_liveMode && (
string.IsNullOrEmpty(message) || _previousErrorMessage == message))
return;
2834 _errorMessages.Enqueue(message);
2835 _previousErrorMessage = message;
2847 Error(message.ToStringInvariant());
2859 Error(message.ToStringInvariant());
2871 Error(message.ToStringInvariant());
2883 var message = error.Message;
2884 if (!_liveMode && (
string.IsNullOrEmpty(message) || _previousErrorMessage == message))
return;
2885 _errorMessages.Enqueue(message);
2886 _previousErrorMessage = message;
2894 public void Quit(
string message =
"")
2896 Debug(
"Quit(): " + message);
2945 private T AddSecurity<T>(
SecurityType securityType,
string ticker,
Resolution? resolution,
string market,
bool fillForward, decimal leverage,
bool extendedMarketHours,
2951 if (!
BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
2953 throw new Exception(
"No default market set for security type: " + securityType);
2958 if (!SymbolCache.TryGetSymbol(ticker, out symbol) ||
2959 symbol.ID.Market != market ||
2960 symbol.SecurityType != securityType)
2970 return (
T)AddToUserDefinedUniverse(security, configs);
2977 [DocumentationAttribute(HistoricalData)]
2980 if (historyProvider ==
null)
2982 throw new ArgumentNullException(nameof(historyProvider),
"Algorithm.SetHistoryProvider(): Historical data provider cannot be null.");
2995 if (exception ==
null)
2997 throw new ArgumentNullException(nameof(exception),
"Algorithm.SetRunTimeError(): Algorithm.RunTimeError cannot be set to null.");
3021 public string Download(
string address) =>
Download(address, Enumerable.Empty<KeyValuePair<string, string>>());
3032 public string Download(
string address, IEnumerable<KeyValuePair<string, string>> headers) =>
Download(address, headers,
null,
null);
3045 public string Download(
string address, IEnumerable<KeyValuePair<string, string>> headers,
string userName,
string password)
3047 return _api.
Download(address, headers, userName, password);
3058 return Schedule.TrainingNow(trainingCode);
3071 return Schedule.Training(dateRule, timeRule, trainingCode);
3079 private void OnInsightsGenerated(
Insight[] insights)
3084 Log($
"{Time}: ALPHA: {string.Join(" |
", insights.Select(i => i.ToString()).OrderBy(i => i))}");
3096 [DocumentationAttribute(HandlingData)]
3148 var shortableQuantity = security.ShortableProvider.ShortableQuantity(symbol, security.LocalTime);
3149 if (shortableQuantity ==
null)
3156 order => order.Symbol == symbol && (!updateOrderId.HasValue || order.OrderId != updateOrderId.Value));
3158 var portfolioQuantity = security.Holdings.Quantity;
3161 if (portfolioQuantity + openOrderQuantity <= -shortableQuantity)
3166 shortQuantity = -Math.Abs(shortQuantity);
3167 return portfolioQuantity + shortQuantity + openOrderQuantity >= -shortableQuantity;
3181 return security.ShortableProvider.ShortableQuantity(symbol, security.LocalTime) ?? 0;
3197 return _securityDefinitionSymbolResolver.
ISIN(isin, GetVerifiedTradingDate(tradingDate));
3209 return _securityDefinitionSymbolResolver.
ISIN(symbol);
3229 return _securityDefinitionSymbolResolver.
CompositeFIGI(compositeFigi, GetVerifiedTradingDate(tradingDate));
3241 return _securityDefinitionSymbolResolver.
CompositeFIGI(symbol);
3257 return _securityDefinitionSymbolResolver.
CUSIP(cusip, GetVerifiedTradingDate(tradingDate));
3269 return _securityDefinitionSymbolResolver.
CUSIP(symbol);
3285 return _securityDefinitionSymbolResolver.
SEDOL(sedol, GetVerifiedTradingDate(tradingDate));
3297 return _securityDefinitionSymbolResolver.
SEDOL(symbol);
3313 return _securityDefinitionSymbolResolver.
CIK(cik, GetVerifiedTradingDate(tradingDate));
3325 return _securityDefinitionSymbolResolver.
CIK(symbol);
3349 return symbols.Select(symbol =>
Fundamentals(symbol)).ToList();
3381 var canonicalSymbols = symbols.Select(GetCanonicalOptionSymbol).ToList();
3382 var optionCanonicalSymbols = canonicalSymbols.Where(x => x.SecurityType !=
SecurityType.FutureOption);
3383 var futureOptionCanonicalSymbols = canonicalSymbols.Where(x => x.SecurityType ==
SecurityType.FutureOption);
3385 var optionChainsData =
History(optionCanonicalSymbols, 1).GetUniverseData()
3386 .Select(x => (x.Keys.Single(), x.Values.Single().Cast<
OptionUniverse>()));
3389 var futureOptionChainsData = futureOptionCanonicalSymbols.Select(symbol =>
3395 EndTime =
Time.Date,
3397 return (symbol, optionChainData);
3400 var time =
Time.Date;
3402 foreach (var (symbol, contracts) in optionChainsData.Concat(futureOptionChainsData))
3405 var optionChain =
new OptionChain(symbol, time, contracts, symbolProperties);
3406 chains.Add(symbol, optionChain);
3419 var typeName = command.GetType().Name;
3420 if (command is
Command || typeName.Contains(
"AnonymousType", StringComparison.InvariantCultureIgnoreCase))
3422 return CommandLink(typeName, command);
3424 return string.Empty;
3435 var commandInstance = JsonConvert.DeserializeObject<
T>(command.Payload);
3436 return commandInstance.Run(
this);
3447 bool? result =
null;
3448 if (_registeredCommands.TryGetValue(command.
Type, out var target))
3452 result = target.Invoke(command);
3454 catch (Exception ex)
3457 if (_oneTimeCommandErrors.Add(command.
Type))
3459 Log($
"Unexpected error running command '{command.Type}' error: '{ex.Message}'");
3465 if (_oneTimeCommandErrors.Add(command.
Type))
3467 Log($
"Detected unregistered command type '{command.Type}', will be ignored");
3483 private string CommandLink(
string typeName,
object command)
3485 var payload =
new Dictionary<string, dynamic> { {
"projectId",
ProjectId }, {
"command", command } };
3486 if (_registeredCommands.ContainsKey(typeName))
3488 payload[
"command[$type]"] = typeName;
3490 return Api.Authentication.Link(
"live/commands/create", payload);
3493 private static Symbol GetCanonicalOptionSymbol(
Symbol symbol)
3496 if (symbol.SecurityType.HasOptions())
3501 if (symbol.SecurityType.IsOption())
3506 throw new ArgumentException($
"The symbol {symbol} is not an option or an underlying symbol.");
3534 private DateTime GetVerifiedTradingDate(DateTime? tradingDate)
3536 tradingDate ??=
Time.Date;
3537 if (tradingDate >
Time.Date)
3539 throw new ArgumentException($
"The trading date provided: \"{tradingDate:yyyy-MM-dd}\" is after the current algorithm's trading date: \"{Time:yyyy-MM-dd}\"");
3542 return tradingDate.Value;
3548 private void SetLiveModeStartDate()
3552 throw new InvalidOperationException(
"SetLiveModeStartDate should only be called during live trading!");
3554 _start = DateTime.UtcNow.ConvertFromUtc(
TimeZone);
3556 _startDate = _start.Date;
3566 if (_statisticsService ==
null)
3568 _statisticsService = statisticsService;