Lean  $LEAN_TAG$
BrokerageDataDownloader.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using QuantConnect.Util;
17 using QuantConnect.Data;
18 using QuantConnect.Packets;
22 
24 {
25  /// <summary>
26  /// Class for downloading data from a brokerage.
27  /// </summary>
29  {
30  /// <summary>
31  /// Represents the Brokerage implementation.
32  /// </summary>
33  private IBrokerage _brokerage;
34 
35  /// <summary>
36  /// Provides access to exchange hours and raw data times zones in various markets
37  /// </summary>
38  private readonly MarketHoursDatabase _marketHoursDatabase = MarketHoursDatabase.FromDataFolder();
39 
40  /// <summary>
41  /// Initializes a new instance of the <see cref="BrokerageDataDownloader"/> class.
42  /// </summary>
44  {
45  var liveNodeConfiguration = new LiveNodePacket()
46  {
47  Brokerage = Config.Get("data-downloader-brokerage"),
48  UserToken = Globals.UserToken,
49  UserId = Globals.UserId,
50  ProjectId = Globals.ProjectId,
51  OrganizationId = Globals.OrganizationID,
52  Version = Globals.Version,
53  DeploymentTarget = DeploymentTarget.LocalPlatform
54  };
55 
56  try
57  {
58  // import the brokerage data for the configured brokerage
59  var brokerageFactory = Composer.Instance.Single<IBrokerageFactory>(factory => factory.BrokerageType.MatchesTypeName(liveNodeConfiguration.Brokerage));
60  liveNodeConfiguration.BrokerageData = brokerageFactory.BrokerageData;
61  }
62  catch (InvalidOperationException error)
63  {
64  throw new InvalidOperationException($"{nameof(BrokerageDataDownloader)}.An error occurred while resolving brokerage data for a live job. Brokerage: {liveNodeConfiguration.Brokerage}.", error);
65  }
66 
67  _brokerage = Composer.Instance.GetExportedValueByTypeName<IBrokerage>(liveNodeConfiguration.Brokerage);
68 
69  _brokerage.Message += (object _, Brokerages.BrokerageMessageEvent e) =>
70  {
71  if (e.Type == Brokerages.BrokerageMessageType.Error)
72  {
73  Logging.Log.Error(e.Message);
74  }
75  else
76  {
77  Logging.Log.Trace(e.Message);
78  }
79  };
80 
81  ((IDataQueueHandler)_brokerage).SetJob(liveNodeConfiguration);
82  }
83 
84  /// <summary>
85  /// Get historical data enumerable for a single symbol, type and resolution given this start and end time (in UTC).
86  /// </summary>
87  /// <param name="dataDownloaderGetParameters">model class for passing in parameters for historical data</param>
88  /// <returns>Enumerable of base data for this symbol</returns>
89  public IEnumerable<BaseData>? Get(DataDownloaderGetParameters dataDownloaderGetParameters)
90  {
91  var symbol = dataDownloaderGetParameters.Symbol;
92  var resolution = dataDownloaderGetParameters.Resolution;
93  var startUtc = dataDownloaderGetParameters.StartUtc;
94  var endUtc = dataDownloaderGetParameters.EndUtc;
95  var tickType = dataDownloaderGetParameters.TickType;
96 
97  var dataType = LeanData.GetDataType(resolution, tickType);
98  var exchangeHours = _marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType);
99  var dataTimeZone = _marketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType);
100 
101  var symbols = new List<Symbol> { symbol };
102  if (symbol.IsCanonical())
103  {
104  symbols = GetChainSymbols(symbol, true).ToList();
105  }
106 
107  return symbols
108  .Select(symbol =>
109  {
110  var request = new Data.HistoryRequest(startUtc, endUtc, dataType, symbol, resolution, exchangeHours: exchangeHours, dataTimeZone: dataTimeZone, resolution,
111  includeExtendedMarketHours: true, false, DataNormalizationMode.Raw, tickType);
112 
113  var history = _brokerage.GetHistory(request);
114 
115  if (history == null)
116  {
117  Logging.Log.Trace($"{nameof(BrokerageDataDownloader)}.{nameof(Get)}: Ignoring history request for unsupported symbol {symbol}");
118  }
119 
120  return history;
121  })
122  .Where(history => history != null)
123  .SelectMany(history => history);
124  }
125 
126  /// <summary>
127  /// Returns an IEnumerable of Future/Option contract symbols for the given root ticker
128  /// </summary>
129  /// <param name="symbol">The Symbol to get futures/options chain for</param>
130  /// <param name="includeExpired">Include expired contracts</param>
131  private IEnumerable<Symbol> GetChainSymbols(Symbol symbol, bool includeExpired)
132  {
133  if (_brokerage is IDataQueueUniverseProvider universeProvider)
134  {
135  return universeProvider.LookupSymbols(symbol, includeExpired);
136  }
137  else
138  {
139  throw new InvalidOperationException($"{nameof(BrokerageDataDownloader)}.{nameof(GetChainSymbols)}: The current brokerage does not support fetching canonical symbols. Please ensure your brokerage instance supports this feature.");
140  }
141  }
142  }
143 }