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