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;
61 using System.Threading.Tasks;
72 #region Documentation Attribute Categories
73 const string AddingData =
"Adding Data";
74 const string AlgorithmFramework =
"Algorithm Framework";
75 const string Charting =
"Charting";
76 const string ConsolidatingData =
"Consolidating Data";
77 const string HandlingData =
"Handling Data";
78 const string HistoricalData =
"Historical Data";
79 const string Indicators =
"Indicators";
80 const string LiveTrading =
"Live Trading";
81 const string Logging =
"Logging";
82 const string MachineLearning =
"Machine Learning";
83 const string Modeling =
"Modeling";
84 const string ParameterAndOptimization =
"Parameter and Optimization";
85 const string ScheduledEvents =
"Scheduled Events";
86 const string SecuritiesAndPortfolio =
"Securities and Portfolio";
87 const string TradingAndOrders =
"Trading and Orders";
88 const string Universes =
"Universes";
89 const string StatisticsTag =
"Statistics";
105 private string _name;
106 private HashSet<string> _tags;
107 private bool _tagsLimitReachedLogSent;
108 private bool _tagsCollectionTruncatedLogSent;
109 private DateTime _start;
110 private DateTime _startDate;
111 private DateTime _endDate;
112 private bool _locked;
113 private bool _liveMode;
116 private string _algorithmId =
"";
117 private ConcurrentQueue<string> _debugMessages =
new ConcurrentQueue<string>();
118 private ConcurrentQueue<string> _logMessages =
new ConcurrentQueue<string>();
119 private ConcurrentQueue<string> _errorMessages =
new ConcurrentQueue<string>();
123 private bool _sentBroadcastCommandsDisabled;
124 private readonly HashSet<string> _oneTimeCommandErrors =
new();
125 private readonly Dictionary<string, Func<CallbackCommand, bool?>> _registeredCommands =
new(StringComparer.InvariantCultureIgnoreCase);
128 private string _previousDebugMessage =
"";
129 private string _previousErrorMessage =
"";
142 private bool _checkedForOnDataSlice;
143 private Action<Slice> _onDataSlice;
146 private bool _userSetSecurityInitializer;
149 private TimeSpan? _warmupTimeSpan;
150 private int? _warmupBarCount;
151 private Dictionary<string, string> _parameters =
new Dictionary<string, string>();
164 Name = GetType().Name;
176 _startDate =
new DateTime(1998, 01, 01);
330 return _brokerageModel;
334 _brokerageModel = value;
337 BrokerageName = Brokerages.BrokerageModel.GetBrokerageName(_brokerageModel);
339 catch (ArgumentOutOfRangeException)
480 [Obsolete(
"OptionChainProvider property is will soon be deprecated. " +
481 "The new OptionChain() method should be used to fetch option chains, " +
482 "which will contain additional data per contract, like daily price data, implied volatility and greeks.")]
489 [Obsolete(
"FutureChainProvider property is will soon be deprecated. " +
490 "The new FuturesChain() method should be used to fetch futures chains, " +
491 "which will contain additional data per contract, like daily price data.")]
516 throw new InvalidOperationException(
"Cannot set algorithm name after it is initialized.");
519 if (!
string.IsNullOrEmpty(value))
530 public HashSet<string>
Tags
543 var tags = value.Where(x => !
string.IsNullOrEmpty(x?.Trim())).ToList();
545 if (tags.Count >
MaxTagsCount && !_tagsCollectionTruncatedLogSent)
547 Log($
"Warning: The tags collection cannot contain more than {MaxTagsCount} items. It will be truncated.");
548 _tagsCollectionTruncatedLogSent =
true;
578 get {
return _localTimeKeeper.
LocalTime; }
587 get {
return _timeKeeper.UtcTime; }
597 get {
return _localTimeKeeper.
TimeZone; }
655 return _algorithmMode;
666 return _deploymentTarget;
679 return _debugMessages;
683 _debugMessages = value;
700 _logMessages = value;
720 return _errorMessages;
724 _errorMessages = value;
764 throw new NotImplementedException(
"Please override the Initialize() method");
775 if (_endDate < _startDate)
777 throw new ArgumentException(
"Please select an algorithm end date greater than start date.");
781 if (portfolioConstructionModel !=
null)
791 portfolioConstructionModel.RebalanceOnInsightChanges
800 Debug(
"Warning: rebalance portfolio settings are set but not supported by the current IPortfolioConstructionModel type: " +
801 $
"{PortfolioConstruction.GetType()}");
819 securityBenchmark.Security.Symbol, securityBenchmark.Security.Type);
822 Log($
"QCAlgorithm.PostInitialize(): Warning: Using a security benchmark of a different timezone ({benchmarkTimeZone})" +
823 $
" than the algorithm TimeZone ({TimeZone}) may lead to skewed and incorrect statistics. Use a higher resolution than daily to minimize.");
827 if (TryGetWarmupHistoryStartTime(out var result))
838 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.");
863 return _parameters.TryGetValue(name, out var value) ? value : defaultValue;
876 return _parameters.TryGetValue(name, out var strValue) &&
int.TryParse(strValue, out var value) ? value : defaultValue;
889 return _parameters.TryGetValue(name, out var strValue) &&
890 double.TryParse(strValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) ? value : defaultValue;
903 return _parameters.TryGetValue(name, out var strValue) &&
904 decimal.TryParse(strValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) ? value : defaultValue;
913 return _parameters.ToReadOnlyDictionary();
924 _parameters = parameters.ToDictionary();
929 catch (Exception err)
931 Error(
"Error applying parameter values: " + err.Message);
942 if (availableDataTypes ==
null)
947 foreach (var dataFeed
in availableDataTypes)
964 throw new Exception(
"SetSecurityInitializer() cannot be called after algorithm initialization. " +
965 "When you use the SetSecurityInitializer() method it will apply to all universes and manually added securities.");
968 if (_userSetSecurityInitializer)
970 Debug(
"Warning: SetSecurityInitializer() has already been called, existing security initializers in all universes will be overwritten.");
974 _userSetSecurityInitializer =
true;
983 [Obsolete(
"This method is deprecated. Please use this overload: SetSecurityInitializer(Action<Security> securityInitializer)")]
1041 if (!_checkedForOnDataSlice)
1043 _checkedForOnDataSlice =
true;
1045 var method = GetType().GetMethods()
1046 .Where(x => x.Name ==
"OnData")
1047 .Where(x => x.DeclaringType != typeof(
QCAlgorithm))
1048 .Where(x => x.GetParameters().Length == 1)
1049 .FirstOrDefault(x => x.GetParameters()[0].ParameterType == typeof(
Slice));
1056 var
self = Expression.Constant(
this);
1057 var parameter = Expression.Parameter(typeof(
Slice),
"data");
1058 var call = Expression.Call(
self, method, parameter);
1059 var lambda = Expression.Lambda<Action<Slice>>(call, parameter);
1060 _onDataSlice = lambda.Compile();
1063 if (_onDataSlice !=
null)
1065 _onDataSlice(slice);
1140 [Obsolete(
"This method is deprecated and will be removed after August 2021. Please use this overload: OnEndOfDay(Symbol symbol)")]
1238 _timeKeeper.SetUtcDateTime(frontier);
1255 tz = DateTimeZoneProviders.Tzdb[timeZone];
1257 catch (DateTimeZoneNotFoundException)
1259 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");
1274 throw new InvalidOperationException(
"Algorithm.SetTimeZone(): Cannot change time zone after algorithm running.");
1277 if (timeZone ==
null)
throw new ArgumentNullException(nameof(timeZone));
1278 _timeKeeper.AddTimeZone(timeZone);
1279 _localTimeKeeper = _timeKeeper.GetLocalTimeKeeper(timeZone);
1290 _start = _startDate;
1297 SetLiveModeStartDate();
1322 if (!_userSetSecurityInitializer)
1330 var security = kvp.Value;
1335 var leverage = security.Leverage;
1340 security.SetLeverage(leverage);
1377 [Obsolete(
"Symbol implicit operator to string is provided for algorithm use only.")]
1385 throw new InvalidOperationException(
"Algorithm.SetBenchmark(): Cannot change Benchmark after algorithm initialized.");
1388 var market = GetMarket(
null, symbol, securityType, defaultMarket:
Market.
USA);
1413 symbol =
Securities.FirstOrDefault(x => x.Key.Value == ticker).Key;
1418 Debug($
"Warning: SetBenchmark({ticker}): no existing symbol found, benchmark security will be added with {SecurityType.Equity} type.");
1438 throw new InvalidOperationException(
"Algorithm.SetBenchmark(): Cannot change Benchmark after algorithm initialized.");
1457 throw new InvalidOperationException(
"Algorithm.SetBenchmark(): Cannot change Benchmark after algorithm initialized.");
1492 if (!
string.IsNullOrEmpty(tag?.Trim()))
1496 if (!_tagsLimitReachedLogSent)
1498 Log($
"Warning: AddTag({tag}): Unable to add tag. Tags are limited to a maximum of {MaxTagsCount}.");
1499 _tagsLimitReachedLogSent =
true;
1534 throw new InvalidOperationException(
"Algorithm.SetAccountCurrency(): " +
1535 "Cannot change AccountCurrency after algorithm initialized.");
1538 if (startingCash ==
null)
1540 Debug($
"Changing account currency from {AccountCurrency} to {accountCurrency}...");
1544 Debug($
"Changing account currency from {AccountCurrency} to {accountCurrency}, with a starting cash of {startingCash}...");
1547 Portfolio.SetAccountCurrency(accountCurrency, startingCash);
1559 SetCash((decimal)startingCash);
1571 SetCash((decimal)startingCash);
1588 throw new InvalidOperationException(
"Algorithm.SetCash(): Cannot change cash available after algorithm initialized.");
1599 public void SetCash(
string symbol, decimal startingCash, decimal conversionRate = 0)
1603 Portfolio.SetCash(symbol, startingCash, conversionRate);
1607 throw new InvalidOperationException(
"Algorithm.SetCash(): Cannot change cash available after algorithm initialized.");
1626 var start =
new DateTime(year, month, day);
1633 catch (Exception err)
1635 throw new ArgumentException($
"Date Invalid: {err.Message}");
1652 var end =
new DateTime(year, month, day);
1655 end = end.Date.AddDays(1).Subtract(TimeSpan.FromTicks(1));
1659 catch (Exception err)
1661 throw new ArgumentException($
"Date Invalid: {err.Message}");
1673 _algorithmId = algorithmId;
1686 if (_liveMode)
return;
1689 start = start.RoundDown(TimeSpan.FromDays(1));
1693 if (start < (
new DateTime(1900, 01, 01)))
1695 throw new ArgumentOutOfRangeException(nameof(start),
"Please select a start date after January 1st, 1900.");
1699 var todayInAlgorithmTimeZone = DateTime.UtcNow.ConvertFromUtc(
TimeZone).Date;
1700 if (start > todayInAlgorithmTimeZone)
1702 throw new ArgumentOutOfRangeException(nameof(start),
"Please select start date less than today");
1708 _start = _startDate = start;
1713 throw new InvalidOperationException(
"Algorithm.SetStartDate(): Cannot change start date after algorithm initialized.");
1727 if (_liveMode)
return;
1732 throw new InvalidOperationException(
"Algorithm.SetEndDate(): Cannot change end date after algorithm initialized.");
1737 var yesterdayInAlgorithmTimeZone = DateTime.UtcNow.ConvertFromUtc(
TimeZone).Date.AddDays(-1);
1738 if (end > yesterdayInAlgorithmTimeZone)
1740 end = yesterdayInAlgorithmTimeZone;
1744 _endDate = end.RoundDown(TimeSpan.FromDays(1)).AddDays(1).AddTicks(-1);
1785 SetLiveModeStartDate();
1799 _algorithmMode = algorithmMode;
1812 _deploymentTarget = deploymentTarget;
1841 return AddSecurity(securityType, ticker, resolution, fillForward,
Security.
NullLeverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1860 return AddSecurity(securityType, ticker, resolution,
null, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1882 return AddOption(ticker, resolution, market, fillForward, leverage);
1887 return AddFuture(ticker, resolution, market, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1892 market = GetMarket(market, ticker, securityType);
1896 symbol.ID.Market != market ||
1897 symbol.SecurityType != securityType)
1902 return AddSecurity(symbol, resolution, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1904 catch (Exception err)
1906 Error(
"Algorithm.AddSecurity(): " + err);
1929 var contractOffset = (uint)Math.Abs(contractDepthOffset);
1932 throw new ArgumentOutOfRangeException(nameof(contractDepthOffset), $
"'contractDepthOffset' current maximum value is {Futures.MaximumContractDepthOffset}." +
1933 $
" Front month (0) and only {Futures.MaximumContractDepthOffset} back month contracts are currently supported.");
1941 return AddOptionContract(symbol, resolution, fillForward, leverage, extendedMarketHours);
1944 var securityResolution = resolution;
1945 var securityFillForward = fillForward;
1950 securityFillForward =
false;
1953 var isFilteredSubscription = !isCanonical;
1954 List<SubscriptionDataConfig> configs;
1957 if (dataNormalizationMode.HasValue)
1961 securityFillForward,
1962 extendedMarketHours,
1963 isFilteredSubscription,
1964 dataNormalizationMode: dataNormalizationMode.
Value,
1965 contractDepthOffset: (uint)contractDepthOffset);
1971 securityFillForward,
1972 extendedMarketHours,
1973 isFilteredSubscription,
1974 contractDepthOffset: (uint)contractDepthOffset);
1988 var canonicalConfig = configs.First();
2003 GetResolution(symbol, resolution,
null), isCanonical:
false);
2006 ExtendedMarketHours = extendedMarketHours,
2009 ContractDepthOffset = (int)contractOffset,
2010 SubscriptionDataTypes = dataTypes,
2018 continuousContractSymbol.ID.Symbol,
2019 continuousContractSymbol.ID.SecurityType,
2020 security.Exchange.Hours);
2025 objectType: typeof(
Tick), extendedHours: extendedMarketHours)));
2035 return AddToUserDefinedUniverse(security, configs);
2053 return AddSecurity<Equity>(
SecurityType.Equity, ticker, resolution, market, fillForward, leverage, extendedMarketHours, normalizationMode: dataNormalizationMode);
2068 market = GetMarket(market, underlying,
SecurityType.Option);
2071 return AddOption(underlyingSymbol, resolution, market, fillForward, leverage);
2089 return AddOption(underlying,
null, resolution, market, fillForward, leverage);
2111 market = GetMarket(market, targetOption, optionType);
2116 if (!
string.IsNullOrEmpty(targetOption))
2118 alias = $
"?{targetOption}";
2122 alias = $
"?{underlying.Value}";
2125 canonicalSymbol.ID.Market != market ||
2126 !canonicalSymbol.SecurityType.IsOption())
2150 bool fillForward =
true, decimal leverage =
Security.
NullLeverage,
bool extendedMarketHours =
false,
2153 market = GetMarket(market, ticker,
SecurityType.Future);
2156 var alias =
"/" + ticker;
2158 canonicalSymbol.ID.Market != market ||
2164 return (
Future)
AddSecurity(canonicalSymbol, resolution, fillForward, leverage, extendedMarketHours, dataMappingMode: dataMappingMode,
2165 dataNormalizationMode: dataNormalizationMode, contractDepthOffset: contractDepthOffset);
2181 return (
Future)
AddSecurity(symbol, resolution, fillForward, leverage, extendedMarketHours);
2196 throw new ArgumentException(
"Symbol provided must be canonical (i.e. the Symbol returned from AddFuture(), not AddFutureContract().");
2218 throw new ArgumentException(
"Expected non-canonical Symbol (i.e. a Symbol representing a specific Future contract");
2221 return AddOptionContract(symbol, resolution, fillForward, leverage, extendedMarketHours);
2235 return AddIndexOption(underlying,
null, resolution, market, fillForward);
2264 throw new ArgumentException(
"Symbol provided must be of type SecurityType.Index");
2284 targetOption, resolution, fillForward);
2300 throw new ArgumentException(
"Symbol provided must be non-canonical and of type SecurityType.IndexOption");
2321 throw new ArgumentException($
"Unexpected option symbol {symbol}. " +
2322 $
"Please provide a valid option contract with it's underlying symbol set.");
2328 List<SubscriptionDataConfig> underlyingConfigs;
2333 underlyingSecurity =
AddSecurity(underlying, resolution, fillForward, leverage, extendedMarketHours);
2337 else if (underlyingSecurity !=
null && underlyingSecurity.IsDelisted)
2339 throw new ArgumentException($
"The underlying {underlying.SecurityType} asset ({underlying.Value}) is delisted " +
2340 $
"(current time is {Time})");
2347 var dataNormalizationMode = underlyingConfigs.DataNormalizationMode();
2352 throw new ArgumentException($
"The underlying {underlying.SecurityType} asset ({underlying.Value}) is set to " +
2353 $
"{dataNormalizationMode}, please change this to DataNormalizationMode.Raw with the " +
2354 "SetDataNormalization() method"
2365 underlyingSecurity.RefreshDataNormalizationModeProperty();
2377 Resolution = underlyingConfigs.GetHighestResolution(),
2378 ExtendedMarketHours = extendedMarketHours
2383 symbol: universeSymbol, objectType: typeof(
Tick), extendedHours: extendedMarketHours), settings));
2388 if (optionUniverse !=
null)
2390 foreach (var subscriptionDataConfig
in configs.Concat(underlyingConfigs))
2392 optionUniverse.
Add(subscriptionDataConfig);
2411 return AddSecurity<Forex>(
SecurityType.Forex, ticker, resolution, market, fillForward, leverage,
false);
2426 return AddSecurity<Cfd>(
SecurityType.Cfd, ticker, resolution, market, fillForward, leverage,
false);
2441 var index = AddSecurity<Index>(
SecurityType.Index, ticker, resolution, market, fillForward, 1,
false);
2457 return AddSecurity<Crypto>(
SecurityType.Crypto, ticker, resolution, market, fillForward, leverage,
false);
2472 return AddSecurity<CryptoFuture>(
SecurityType.CryptoFuture, ticker, resolution, market, fillForward, leverage,
false);
2508 if (security.Invested)
2518 foreach (var kvp
in UniverseManager.Where(x => x.Value.Configuration.Symbol == symbol
2521 var universe = kvp.Value;
2523 var otherUniverses =
UniverseManager.Select(ukvp => ukvp.Value).Where(u => !ReferenceEquals(u, universe)).ToList();
2527 if (!otherUniverses.Any(u => u.Members.ContainsKey(underlying.Symbol)))
2535 foreach (var child
in universe.Members.Values.OrderBy(security1 => security1.Symbol))
2537 if (!otherUniverses.Any(u => u.Members.ContainsKey(child.Symbol)) && !child.Symbol.IsCanonical())
2545 _universeSelectionUniverses.Remove(security.Symbol);
2550 lock (_pendingUniverseAdditionsLock)
2556 universe.Remove(symbol);
2559 _pendingUserDefinedUniverseSecurityAdditions.RemoveAll(addition => addition.Security.Symbol == symbol);
2581 return AddData<T>(ticker, resolution, fillForward:
false, leverage: 1m);
2600 return AddData<T>(underlying, resolution, fillForward:
false, leverage: 1m);
2618 return AddData<T>(ticker, resolution,
null, fillForward, leverage);
2635 return AddData<T>(underlying, resolution,
null, fillForward, leverage);
2652 return AddData(typeof(
T), ticker, resolution, timeZone, fillForward, leverage);
2669 return AddData(typeof(
T), underlying, resolution, timeZone, fillForward, leverage);
2691 SetDatabaseEntries(key, properties, exchangeHours);
2694 return AddData(typeof(
T), ticker, resolution,
null, fillForward, leverage);
2706 if (!_liveMode && (
string.IsNullOrEmpty(message) || _previousDebugMessage == message))
return;
2707 _debugMessages.Enqueue(message);
2708 _previousDebugMessage = message;
2720 Debug(message.ToStringInvariant());
2732 Debug(message.ToStringInvariant());
2744 Debug(message.ToStringInvariant());
2754 public void Log(
string message)
2756 if (!_liveMode &&
string.IsNullOrEmpty(message))
return;
2757 _logMessages.Enqueue(message);
2769 Log(message.ToStringInvariant());
2779 public void Log(
double message)
2781 Log(message.ToStringInvariant());
2791 public void Log(decimal message)
2793 Log(message.ToStringInvariant());
2805 if (!_liveMode && (
string.IsNullOrEmpty(message) || _previousErrorMessage == message))
return;
2806 _errorMessages.Enqueue(message);
2807 _previousErrorMessage = message;
2819 Error(message.ToStringInvariant());
2831 Error(message.ToStringInvariant());
2843 Error(message.ToStringInvariant());
2855 var message = error.Message;
2856 if (!_liveMode && (
string.IsNullOrEmpty(message) || _previousErrorMessage == message))
return;
2857 _errorMessages.Enqueue(message);
2858 _previousErrorMessage = message;
2866 public void Quit(
string message =
"")
2868 Debug(
"Quit(): " + message);
2917 private T AddSecurity<T>(
SecurityType securityType,
string ticker,
Resolution? resolution,
string market,
bool fillForward, decimal leverage,
bool extendedMarketHours,
2921 market = GetMarket(market, ticker, securityType);
2925 symbol.ID.Market != market ||
2926 symbol.SecurityType != securityType)
2936 return (
T)AddToUserDefinedUniverse(security, configs);
2943 [DocumentationAttribute(HistoricalData)]
2946 if (historyProvider ==
null)
2948 throw new ArgumentNullException(nameof(historyProvider),
"Algorithm.SetHistoryProvider(): Historical data provider cannot be null.");
2961 if (exception ==
null)
2963 throw new ArgumentNullException(nameof(exception),
"Algorithm.SetRunTimeError(): Algorithm.RunTimeError cannot be set to null.");
2987 public string Download(
string address) =>
Download(address, Enumerable.Empty<KeyValuePair<string, string>>());
2998 public string Download(
string address, IEnumerable<KeyValuePair<string, string>> headers) =>
Download(address, headers,
null,
null);
3011 public string Download(
string address, IEnumerable<KeyValuePair<string, string>> headers,
string userName,
string password)
3013 return _api.
Download(address, headers, userName, password);
3024 return Schedule.TrainingNow(trainingCode);
3037 return Schedule.Training(dateRule, timeRule, trainingCode);
3045 private void OnInsightsGenerated(
Insight[] insights)
3050 Log($
"{Time}: ALPHA: {string.Join(" |
", insights.Select(i => i.ToString()).OrderBy(i => i))}");
3062 [DocumentationAttribute(HandlingData)]
3114 var shortableQuantity = security.ShortableProvider.ShortableQuantity(symbol, security.LocalTime);
3115 if (shortableQuantity ==
null)
3122 order => order.Symbol == symbol && (!updateOrderId.HasValue || order.OrderId != updateOrderId.Value));
3124 var portfolioQuantity = security.Holdings.Quantity;
3127 if (portfolioQuantity + openOrderQuantity <= -shortableQuantity)
3132 shortQuantity = -Math.Abs(shortQuantity);
3133 return portfolioQuantity + shortQuantity + openOrderQuantity >= -shortableQuantity;
3147 return security.ShortableProvider.ShortableQuantity(symbol, security.LocalTime) ?? 0;
3163 return _securityDefinitionSymbolResolver.
ISIN(isin, GetVerifiedTradingDate(tradingDate));
3175 return _securityDefinitionSymbolResolver.
ISIN(symbol);
3195 return _securityDefinitionSymbolResolver.
CompositeFIGI(compositeFigi, GetVerifiedTradingDate(tradingDate));
3207 return _securityDefinitionSymbolResolver.
CompositeFIGI(symbol);
3223 return _securityDefinitionSymbolResolver.
CUSIP(cusip, GetVerifiedTradingDate(tradingDate));
3235 return _securityDefinitionSymbolResolver.
CUSIP(symbol);
3251 return _securityDefinitionSymbolResolver.
SEDOL(sedol, GetVerifiedTradingDate(tradingDate));
3263 return _securityDefinitionSymbolResolver.
SEDOL(symbol);
3279 return _securityDefinitionSymbolResolver.
CIK(cik, GetVerifiedTradingDate(tradingDate));
3291 return _securityDefinitionSymbolResolver.
CIK(symbol);
3315 return symbols.Select(symbol =>
Fundamentals(symbol)).ToList();
3338 return OptionChains(
new[] { symbol }, flatten).Values.SingleOrDefault() ??
3339 new OptionChain(GetCanonicalOptionSymbol(symbol),
Time.Date, flatten);
3357 var canonicalSymbols = symbols.Select(GetCanonicalOptionSymbol).ToList();
3358 var optionChainsData = GetChainsData<OptionUniverse>(canonicalSymbols);
3361 foreach (var (symbol, contracts) in optionChainsData)
3364 var optionChain =
new OptionChain(symbol, GetTimeInExchangeTimeZone(symbol).Date, contracts, symbolProperties, flatten);
3365 chains.Add(symbol, optionChain);
3404 return FuturesChains(
new[] { symbol }, flatten).Values.SingleOrDefault() ??
3441 var canonicalSymbols = symbols.Select(GetCanonicalFutureSymbol).ToList();
3442 var futureChainsData = GetChainsData<FutureUniverse>(canonicalSymbols);
3446 if (futureChainsData !=
null)
3448 foreach (var (symbol, contracts) in futureChainsData)
3450 var chain =
new FuturesChain(symbol, GetTimeInExchangeTimeZone(symbol).Date, contracts, flatten);
3451 chains.Add(symbol, chain);
3465 var typeName = command.GetType().Name;
3466 if (command is
Command || typeName.Contains(
"AnonymousType", StringComparison.InvariantCultureIgnoreCase))
3468 return CommandLink(typeName, command);
3471 throw new ArgumentException($
"Unexpected command type: {typeName}");
3482 var commandInstance = JsonConvert.DeserializeObject<
T>(command.Payload);
3483 return commandInstance.Run(
this);
3494 var typeName = command.GetType().Name;
3495 if (command is
Command || typeName.Contains(
"AnonymousType", StringComparison.InvariantCultureIgnoreCase))
3497 var serialized = JsonConvert.SerializeObject(command);
3498 var payload = JsonConvert.DeserializeObject<Dictionary<string, object>>(serialized);
3499 return SendBroadcast(typeName, payload);
3502 throw new ArgumentException($
"Unexpected command type: {typeName}");
3512 bool? result =
null;
3513 if (_registeredCommands.TryGetValue(command.
Type, out var target))
3517 result = target.Invoke(command);
3519 catch (Exception ex)
3522 if (_oneTimeCommandErrors.Add(command.
Type))
3524 Log($
"Unexpected error running command '{command.Type}' error: '{ex.Message}'");
3530 if (_oneTimeCommandErrors.Add(command.
Type))
3532 Log($
"Detected unregistered command type '{command.Type}', will be ignored");
3551 private string GetMarket(
string market,
string ticker,
SecurityType securityType,
string defaultMarket =
null)
3553 if (
string.IsNullOrEmpty(market))
3565 if (!
BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
3567 if (
string.IsNullOrEmpty(defaultMarket))
3569 throw new KeyNotFoundException($
"No default market set for security type: {securityType}");
3571 return defaultMarket;
3577 private string CommandLink(
string typeName,
object command)
3579 var payload =
new Dictionary<string, dynamic> { {
"projectId",
ProjectId }, {
"command", command } };
3580 if (_registeredCommands.ContainsKey(typeName))
3582 payload[
"command[$type]"] = typeName;
3587 private RestResponse SendBroadcast(
string typeName, Dictionary<string, object> payload)
3591 if (!_sentBroadcastCommandsDisabled)
3593 _sentBroadcastCommandsDisabled =
true;
3594 Debug(
"Warning: sending broadcast commands is disabled in backtesting");
3599 if (_registeredCommands.ContainsKey(typeName))
3601 payload[
"$type"] = typeName;
3608 private static Symbol GetCanonicalOptionSymbol(
Symbol symbol)
3611 if (symbol.SecurityType.HasOptions())
3616 if (symbol.SecurityType.IsOption())
3621 throw new ArgumentException($
"The symbol {symbol} is not an option or an underlying symbol.");
3624 private static Symbol GetCanonicalFutureSymbol(
Symbol symbol)
3637 throw new ArgumentException($
"The symbol {symbol} is neither a future nor a future option symbol.");
3665 private DateTime GetVerifiedTradingDate(DateTime? tradingDate)
3667 tradingDate ??=
Time.Date;
3668 if (tradingDate >
Time.Date)
3670 throw new ArgumentException($
"The trading date provided: \"{tradingDate:yyyy-MM-dd}\" is after the current algorithm's trading date: \"{Time:yyyy-MM-dd}\"");
3673 return tradingDate.Value;
3679 private void SetLiveModeStartDate()
3683 throw new InvalidOperationException(
"SetLiveModeStartDate should only be called during live trading!");
3685 _start = DateTime.UtcNow.ConvertFromUtc(
TimeZone);
3687 _startDate = _start.Date;
3697 if (_statisticsService ==
null)
3699 _statisticsService = statisticsService;
3707 private IEnumerable<KeyValuePair<Symbol, IEnumerable<T>>> GetChainsData<T>(IEnumerable<Symbol> canonicalSymbols)
3710 foreach (var symbol
in canonicalSymbols)
3718 while ((history ==
null || history.Count == 0) && periods <= 3)
3720 history =
History<T>([symbol], periods++).FirstOrDefault();
3723 var chain = history !=
null && history.Count > 0 ? history.Values.Single().Cast<
T>() : Enumerable.Empty<
T>();
3724 yield
return KeyValuePair.Create(symbol, chain);
3731 private DateTime GetTimeInExchangeTimeZone(
Symbol symbol)
3734 return UtcTime.ConvertFromUtc(exchange.TimeZone);