26 using System.Collections.Generic;
28 using System.Collections.Concurrent;
43 private bool _customDataDownloadError;
44 private readonly ConcurrentDictionary<Symbol, Symbol> _marketHoursWarning =
new();
55 var dataDownloaderConfig =
Config.
Get(
"data-downloader");
56 if (!
string.IsNullOrEmpty(dataDownloaderConfig))
62 throw new ArgumentException(
"DownloaderDataProvider(): requires 'data-downloader' to be set with a valid type name");
71 _dataDownloader = dataDownloader;
79 public override Stream
Fetch(
string key)
83 if (
LeanData.
TryParsePath(key, out var symbol, out var date, out var resolution, out var tickType, out var dataType))
85 if (symbol.SecurityType == SecurityType.Base)
87 if (!_customDataDownloadError)
89 _customDataDownloadError = true;
91 Log.Trace($
"DownloaderDataProvider.Get(): custom data is not supported, requested: {symbol}");
99 entry = _marketHoursDatabase.GetEntry(symbol.ID.Market, symbol, symbol.SecurityType);
104 if (_marketHoursWarning.TryAdd(symbol, symbol))
107 Log.Trace($
"DownloaderDataProvider.Get(): failed to find market hours for {symbol}, skipping");
114 var exchangeTimeZone = entry.ExchangeHours.TimeZone;
115 DateTime startTimeUtc;
118 var endTimeUtcLimit = DateTime.UtcNow.Date.AddDays(-1);
122 startTimeUtc = date.ConvertToUtc(dataTimeZone);
124 endTimeUtc = date.AddDays(1).ConvertToUtc(dataTimeZone);
125 if (endTimeUtc > endTimeUtcLimit)
134 endTimeUtc = endTimeUtcLimit;
141 startTimeUtc = new DateTime(2009, 1, 1);
143 else if (symbol.SecurityType.IsOption() && symbol.SecurityType !=
SecurityType.FutureOption)
146 startTimeUtc = new DateTime(date.Year, 1, 1);
147 endTimeUtc = startTimeUtc.AddYears(1);
151 startTimeUtc = symbol.ID.Date;
154 catch (InvalidOperationException)
161 startTimeUtc = Time.Start;
164 if (endTimeUtc > endTimeUtcLimit)
166 endTimeUtc = endTimeUtcLimit;
174 var processingDate = date.ConvertToUtc(dataTimeZone);
180 var getParams =
new DataDownloaderGetParameters(symbol, resolution, startTimeUtc, endTimeUtc, tickType);
182 var downloaderDataParameters = getParams.GetDataDownloaderParameterForAllMappedSymbols(_mapFileProvider, exchangeTimeZone);
184 var downloadedData =
GetDownloadedData(downloaderDataParameters, symbol, exchangeTimeZone, dataTimeZone, dataType);
186 foreach (var dataPerSymbol
in downloadedData)
190 writer =
new LeanDataWriter(resolution, symbol, Globals.DataFolder, tickType, mapSymbol:
true, dataCacheProvider: _dataCacheProvider);
193 writer.
Write(dataPerSymbol);
215 IEnumerable<DataDownloaderGetParameters> downloaderDataParameters,
217 DateTimeZone exchangeTimeZone,
218 DateTimeZone dataTimeZone,
221 if (downloaderDataParameters.IsNullOrEmpty())
223 throw new ArgumentException($
"{nameof(DownloaderDataProvider)}.{nameof(GetDownloadedData)}: DataDownloaderGetParameters are empty or equal to null.");
226 foreach (var downloaderDataParameter
in downloaderDataParameters)
228 var downloadedData = _dataDownloader.Get(downloaderDataParameter);
230 if (downloadedData ==
null)
236 var groupedData = FilterAndGroupDownloadDataBySymbol(
242 downloaderDataParameter.StartUtc,
243 downloaderDataParameter.EndUtc);
245 foreach (var data
in groupedData)
257 if (
LeanData.
TryParsePath(key, out var symbol, out var date, out var resolution, out var _) && resolution >
Resolution.Minute && symbol.RequiresMapping())
260 return DiskSynchronizer.Execute(key, () =>
262 var baseStream = base.Fetch(key);
263 if (baseStream !=
null)
265 var result =
new MemoryStream();
266 baseStream.CopyTo(result);
267 baseStream.Dispose();
277 return base.Fetch(key);
289 || filePath.Contains(
"fine", StringComparison.InvariantCultureIgnoreCase) && filePath.Contains(
"fundamental", StringComparison.InvariantCultureIgnoreCase)
290 || filePath.Contains(
"map_files", StringComparison.InvariantCultureIgnoreCase)
291 || filePath.Contains(
"factor_files", StringComparison.InvariantCultureIgnoreCase)
292 || filePath.Contains(
"margins", StringComparison.InvariantCultureIgnoreCase) && filePath.Contains(
"future", StringComparison.InvariantCultureIgnoreCase))
299 return !File.Exists(filePath) || filePath.IsOutOfDate();
316 IEnumerable<BaseData> downloadData,
319 DateTimeZone exchangeTimeZone,
320 DateTimeZone dataTimeZone,
321 DateTime downloaderStartTimeUtc,
322 DateTime downloaderEndTimeUtc)
324 var startDateTimeInExchangeTimeZone = downloaderStartTimeUtc.ConvertFromUtc(exchangeTimeZone);
325 var endDateTimeInExchangeTimeZone = downloaderEndTimeUtc.ConvertFromUtc(exchangeTimeZone);
331 if (baseData.Time < startDateTimeInExchangeTimeZone || baseData.Time > endDateTimeInExchangeTimeZone)
339 baseData.Time = baseData.Time.ConvertTo(exchangeTimeZone, dataTimeZone);
340 baseData.EndTime = baseData.EndTime.ConvertTo(exchangeTimeZone, dataTimeZone);
346 .GroupBy(baseData => baseData.Symbol);