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  };
54 
55  try
56  {
57  // import the brokerage data for the configured brokerage
58  var brokerageFactory = Composer.Instance.Single<IBrokerageFactory>(factory => factory.BrokerageType.MatchesTypeName(liveNodeConfiguration.Brokerage));
59  liveNodeConfiguration.BrokerageData = brokerageFactory.BrokerageData;
60  }
61  catch (InvalidOperationException error)
62  {
63  throw new InvalidOperationException($"{nameof(BrokerageDataDownloader)}.An error occurred while resolving brokerage data for a live job. Brokerage: {liveNodeConfiguration.Brokerage}.", error);
64  }
65 
66  _brokerage = Composer.Instance.GetExportedValueByTypeName<IBrokerage>(liveNodeConfiguration.Brokerage);
67 
68  _brokerage.Message += (object _, Brokerages.BrokerageMessageEvent e) =>
69  {
70  if (e.Type == Brokerages.BrokerageMessageType.Error)
71  {
72  Logging.Log.Error(e.Message);
73  }
74  else
75  {
76  Logging.Log.Trace(e.Message);
77  }
78  };
79 
80  ((IDataQueueHandler)_brokerage).SetJob(liveNodeConfiguration);
81  }
82 
83  /// <summary>
84  /// Get historical data enumerable for a single symbol, type and resolution given this start and end time (in UTC).
85  /// </summary>
86  /// <param name="dataDownloaderGetParameters">model class for passing in parameters for historical data</param>
87  /// <returns>Enumerable of base data for this symbol</returns>
88  public IEnumerable<BaseData>? Get(DataDownloaderGetParameters dataDownloaderGetParameters)
89  {
90  var symbol = dataDownloaderGetParameters.Symbol;
91  var resolution = dataDownloaderGetParameters.Resolution;
92  var startUtc = dataDownloaderGetParameters.StartUtc;
93  var endUtc = dataDownloaderGetParameters.EndUtc;
94  var tickType = dataDownloaderGetParameters.TickType;
95 
96  var dataType = LeanData.GetDataType(resolution, tickType);
97  var exchangeHours = _marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType);
98  var dataTimeZone = _marketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType);
99 
100  var symbols = new List<Symbol> { symbol };
101  if (symbol.IsCanonical())
102  {
103  symbols = GetChainSymbols(symbol, true).ToList();
104  }
105 
106  return symbols
107  .Select(symbol =>
108  {
109  var request = new Data.HistoryRequest(startUtc, endUtc, dataType, symbol, resolution, exchangeHours: exchangeHours, dataTimeZone: dataTimeZone, resolution,
110  includeExtendedMarketHours: true, false, DataNormalizationMode.Raw, tickType);
111 
112  var history = _brokerage.GetHistory(request);
113 
114  if (history == null)
115  {
116  Logging.Log.Trace($"{nameof(BrokerageDataDownloader)}.{nameof(Get)}: Ignoring history request for unsupported symbol {symbol}");
117  }
118 
119  return history;
120  })
121  .Where(history => history != null)
122  .SelectMany(history => history);
123  }
124 
125  /// <summary>
126  /// Returns an IEnumerable of Future/Option contract symbols for the given root ticker
127  /// </summary>
128  /// <param name="symbol">The Symbol to get futures/options chain for</param>
129  /// <param name="includeExpired">Include expired contracts</param>
130  private IEnumerable<Symbol> GetChainSymbols(Symbol symbol, bool includeExpired)
131  {
132  if (_brokerage is IDataQueueUniverseProvider universeProvider)
133  {
134  return universeProvider.LookupSymbols(symbol, includeExpired);
135  }
136  else
137  {
138  throw new InvalidOperationException($"{nameof(BrokerageDataDownloader)}.{nameof(GetChainSymbols)}: The current brokerage does not support fetching canonical symbols. Please ensure your brokerage instance supports this feature.");
139  }
140  }
141  }
142 }