/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using NodaTime;
using QuantConnect.Data;
using QuantConnect.Data.Auxiliary;
using QuantConnect.Data.Market;
using QuantConnect.Logging;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
namespace QuantConnect.Util
{
///
/// Provides methods for generating lean data file content
///
public static class LeanData
{
///
/// Converts the specified base data instance into a lean data file csv line.
/// This method takes into account the fake that base data instances typically
/// are time stamped in the exchange time zone, but need to be written to disk
/// in the data time zone.
///
public static string GenerateLine(IBaseData data, Resolution resolution, DateTimeZone exchangeTimeZone, DateTimeZone dataTimeZone)
{
var clone = data.Clone();
clone.Time = data.Time.ConvertTo(exchangeTimeZone, dataTimeZone);
return GenerateLine(clone, clone.Symbol.ID.SecurityType, resolution);
}
///
/// Converts the specified base data instance into a lean data file csv line
///
public static string GenerateLine(IBaseData data, SecurityType securityType, Resolution resolution)
{
var milliseconds = data.Time.TimeOfDay.TotalMilliseconds.ToString(CultureInfo.InvariantCulture);
var longTime = data.Time.ToString(DateFormat.TwelveCharacter);
switch (securityType)
{
case SecurityType.Equity:
switch (resolution)
{
case Resolution.Tick:
var tick = (Tick) data;
return ToCsv(milliseconds, Scale(tick.LastPrice), tick.Quantity, tick.Exchange, tick.SaleCondition, tick.Suspicious ? "1" : "0");
case Resolution.Minute:
case Resolution.Second:
var bar = (TradeBar) data;
return ToCsv(milliseconds, Scale(bar.Open), Scale(bar.High), Scale(bar.Low), Scale(bar.Close), bar.Volume);
case Resolution.Hour:
case Resolution.Daily:
var bigBar = (TradeBar) data;
return ToCsv(longTime, Scale(bigBar.Open), Scale(bigBar.High), Scale(bigBar.Low), Scale(bigBar.Close), bigBar.Volume);
}
break;
case SecurityType.Crypto:
switch (resolution)
{
case Resolution.Tick:
var tick = data as Tick;
if (tick == null) throw new NullReferenceException("Cryto tick could not be created");
if (tick.TickType == TickType.Trade)
{
return ToCsv(milliseconds, tick.LastPrice, tick.Quantity);
}
if (tick.TickType == TickType.Quote)
{
return ToCsv(milliseconds, tick.BidPrice, tick.BidSize, tick.AskPrice, tick.AskSize);
}
throw new ArgumentException("Cryto tick could not be created");
case Resolution.Second:
case Resolution.Minute:
var quoteBar = data as QuoteBar;
if (quoteBar != null)
{
return ToCsv(milliseconds,
ToNonScaledCsv(quoteBar.Bid), quoteBar.LastBidSize,
ToNonScaledCsv(quoteBar.Ask), quoteBar.LastAskSize);
}
var tradeBar = data as TradeBar;
if (tradeBar != null)
{
return ToCsv(milliseconds, tradeBar.Open, tradeBar.High, tradeBar.Low, tradeBar.Close, tradeBar.Volume);
}
throw new NullReferenceException("Cryto minute/second bar could not be created");
case Resolution.Hour:
case Resolution.Daily:
var bigQuoteBar = data as QuoteBar;
if (bigQuoteBar != null)
{
return ToCsv(longTime,
ToNonScaledCsv(bigQuoteBar.Bid), bigQuoteBar.LastBidSize,
ToNonScaledCsv(bigQuoteBar.Ask), bigQuoteBar.LastAskSize);
}
var bigTradeBar = data as TradeBar;
if (bigTradeBar != null)
{
return ToCsv(longTime,
bigTradeBar.Open,
bigTradeBar.High,
bigTradeBar.Low,
bigTradeBar.Close,
bigTradeBar.Volume);
}
throw new NullReferenceException("Cryto hour/daily bar could not be created");
}
break;
case SecurityType.Forex:
case SecurityType.Cfd:
switch (resolution)
{
case Resolution.Tick:
var tick = data as Tick;
if (tick == null) throw new NullReferenceException("tick");
return ToCsv(milliseconds, tick.BidPrice, tick.AskPrice);
case Resolution.Second:
case Resolution.Minute:
var bar = data as QuoteBar;
if (bar == null) throw new NullReferenceException("bar");
return ToCsv(milliseconds,
ToNonScaledCsv(bar.Bid), bar.LastBidSize,
ToNonScaledCsv(bar.Ask), bar.LastAskSize);
case Resolution.Hour:
case Resolution.Daily:
var bigBar = data as QuoteBar;
if (bigBar == null) throw new NullReferenceException("big bar");
return ToCsv(longTime,
ToNonScaledCsv(bigBar.Bid), bigBar.LastBidSize,
ToNonScaledCsv(bigBar.Ask), bigBar.LastAskSize);
}
break;
case SecurityType.Option:
switch (resolution)
{
case Resolution.Tick:
var tick = (Tick)data;
if (tick.TickType == TickType.Trade)
{
return ToCsv(milliseconds,
Scale(tick.LastPrice), tick.Quantity, tick.Exchange, tick.SaleCondition, tick.Suspicious ? "1" : "0");
}
if (tick.TickType == TickType.Quote)
{
return ToCsv(milliseconds,
Scale(tick.BidPrice), tick.BidSize, Scale(tick.AskPrice), tick.AskSize, tick.Exchange, tick.Suspicious ? "1" : "0");
}
if (tick.TickType == TickType.OpenInterest)
{
return ToCsv(milliseconds, tick.Value);
}
break;
case Resolution.Second:
case Resolution.Minute:
// option and future data can be quote or trade bars
var quoteBar = data as QuoteBar;
if (quoteBar != null)
{
return ToCsv(milliseconds,
ToScaledCsv(quoteBar.Bid), quoteBar.LastBidSize,
ToScaledCsv(quoteBar.Ask), quoteBar.LastAskSize);
}
var tradeBar = data as TradeBar;
if (tradeBar != null)
{
return ToCsv(milliseconds,
Scale(tradeBar.Open), Scale(tradeBar.High), Scale(tradeBar.Low), Scale(tradeBar.Close), tradeBar.Volume);
}
var openInterest = data as OpenInterest;
if (openInterest != null)
{
return ToCsv(milliseconds, openInterest.Value);
}
break;
case Resolution.Hour:
case Resolution.Daily:
// option and future data can be quote or trade bars
var bigQuoteBar = data as QuoteBar;
if (bigQuoteBar != null)
{
return ToCsv(longTime,
ToScaledCsv(bigQuoteBar.Bid), bigQuoteBar.LastBidSize,
ToScaledCsv(bigQuoteBar.Ask), bigQuoteBar.LastAskSize);
}
var bigTradeBar = data as TradeBar;
if (bigTradeBar != null)
{
return ToCsv(longTime, ToScaledCsv(bigTradeBar), bigTradeBar.Volume);
}
var bigOpenInterest = data as OpenInterest;
if (bigOpenInterest != null)
{
return ToCsv(milliseconds, bigOpenInterest.Value);
}
break;
default:
throw new ArgumentOutOfRangeException("resolution", resolution, null);
}
break;
case SecurityType.Future:
switch (resolution)
{
case Resolution.Tick:
var tick = (Tick)data;
if (tick.TickType == TickType.Trade)
{
return ToCsv(milliseconds,
tick.LastPrice, tick.Quantity, tick.Exchange, tick.SaleCondition, tick.Suspicious ? "1": "0");
}
if (tick.TickType == TickType.Quote)
{
return ToCsv(milliseconds,
tick.BidPrice, tick.BidSize, tick.AskPrice, tick.AskSize, tick.Exchange, tick.Suspicious ? "1" : "0");
}
if (tick.TickType == TickType.OpenInterest)
{
return ToCsv(milliseconds, tick.Value);
}
break;
case Resolution.Second:
case Resolution.Minute:
// option and future data can be quote or trade bars
var quoteBar = data as QuoteBar;
if (quoteBar != null)
{
return ToCsv(milliseconds,
ToNonScaledCsv(quoteBar.Bid), quoteBar.LastBidSize,
ToNonScaledCsv(quoteBar.Ask), quoteBar.LastAskSize);
}
var tradeBar = data as TradeBar;
if (tradeBar != null)
{
return ToCsv(milliseconds,
tradeBar.Open, tradeBar.High, tradeBar.Low, tradeBar.Close, tradeBar.Volume);
}
var openInterest = data as OpenInterest;
if (openInterest != null)
{
return ToCsv(milliseconds, openInterest.Value);
}
break;
case Resolution.Hour:
case Resolution.Daily:
// option and future data can be quote or trade bars
var bigQuoteBar = data as QuoteBar;
if (bigQuoteBar != null)
{
return ToCsv(longTime,
ToNonScaledCsv(bigQuoteBar.Bid), bigQuoteBar.LastBidSize,
ToNonScaledCsv(bigQuoteBar.Ask), bigQuoteBar.LastAskSize);
}
var bigTradeBar = data as TradeBar;
if (bigTradeBar != null)
{
return ToCsv(longTime, ToNonScaledCsv(bigTradeBar), bigTradeBar.Volume);
}
var bigOpenInterest = data as OpenInterest;
if (bigOpenInterest != null)
{
return ToCsv(longTime, bigOpenInterest.Value);
}
break;
default:
throw new ArgumentOutOfRangeException("resolution", resolution, null);
}
break;
default:
throw new ArgumentOutOfRangeException("securityType", securityType, null);
}
throw new NotImplementedException("LeanData.GenerateLine has not yet been implemented for security type: " + securityType + " at resolution: " + resolution);
}
///
/// Gets the data type required for the specified combination of resolution and tick type
///
/// The resolution, if Tick, the Type returned is always Tick
/// The that primarily dictates the type returned
/// The Type used to create a subscription
public static Type GetDataType(Resolution resolution, TickType tickType)
{
if (resolution == Resolution.Tick) return typeof(Tick);
if (tickType == TickType.OpenInterest) return typeof(OpenInterest);
if (tickType == TickType.Quote) return typeof(QuoteBar);
return typeof(TradeBar);
}
///
/// Determines if the Type is a 'common' type used throughout lean
/// This method is helpful in creating
///
/// The Type to check
/// A bool indicating whether the type is of type
/// or
public static bool IsCommonLeanDataType(Type baseDataType)
{
if (baseDataType == typeof(TradeBar) ||
baseDataType == typeof(QuoteBar) ||
baseDataType == typeof(OpenInterest))
{
return true;
}
return false;
}
///
/// Generates the full zip file path rooted in the
///
public static string GenerateZipFilePath(string dataDirectory, Symbol symbol, DateTime date, Resolution resolution, TickType tickType)
{
return Path.Combine(dataDirectory, GenerateRelativeZipFilePath(symbol, date, resolution, tickType));
}
///
/// Generates the full zip file path rooted in the
///
public static string GenerateZipFilePath(string dataDirectory, string symbol, SecurityType securityType, string market, DateTime date, Resolution resolution)
{
return Path.Combine(dataDirectory, GenerateRelativeZipFilePath(symbol, securityType, market, date, resolution));
}
///
/// Generates the relative zip directory for the specified symbol/resolution
///
public static string GenerateRelativeZipFileDirectory(Symbol symbol, Resolution resolution)
{
var isHourOrDaily = resolution == Resolution.Hour || resolution == Resolution.Daily;
var securityType = symbol.ID.SecurityType.SecurityTypeToLower();
var market = symbol.ID.Market.ToLower();
var res = resolution.ResolutionToLower();
var directory = Path.Combine(securityType, market, res);
switch (symbol.ID.SecurityType)
{
case SecurityType.Base:
case SecurityType.Equity:
case SecurityType.Forex:
case SecurityType.Cfd:
case SecurityType.Crypto:
return !isHourOrDaily ? Path.Combine(directory, symbol.Value.ToLower()) : directory;
case SecurityType.Option:
// options uses the underlying symbol for pathing
return !isHourOrDaily ? Path.Combine(directory, symbol.Underlying.Value.ToLower()) : directory;
case SecurityType.Future:
return !isHourOrDaily ? Path.Combine(directory, symbol.ID.Symbol.ToLower()) : directory;
case SecurityType.Commodity:
default:
throw new ArgumentOutOfRangeException();
}
}
///
/// Generates relative factor file paths for equities
///
public static string GenerateRelativeFactorFilePath(Symbol symbol)
{
return Path.Combine(Globals.DataFolder,
"equity",
symbol.ID.Market,
"factor_files",
symbol.Value.ToLower() + ".csv");
}
///
/// Generates the relative zip file path rooted in the /Data directory
///
public static string GenerateRelativeZipFilePath(Symbol symbol, DateTime date, Resolution resolution, TickType tickType)
{
return Path.Combine(GenerateRelativeZipFileDirectory(symbol, resolution), GenerateZipFileName(symbol, date, resolution, tickType));
}
///
/// Generates the relative zip file path rooted in the /Data directory
///
public static string GenerateRelativeZipFilePath(string symbol, SecurityType securityType, string market, DateTime date, Resolution resolution)
{
var directory = Path.Combine(securityType.SecurityTypeToLower(), market.ToLower(), resolution.ResolutionToLower());
if (resolution != Resolution.Daily && resolution != Resolution.Hour)
{
directory = Path.Combine(directory, symbol.ToLower());
}
return Path.Combine(directory, GenerateZipFileName(symbol, securityType, date, resolution));
}
///
/// Generate's the zip entry name to hold the specified data.
///
public static string GenerateZipEntryName(Symbol symbol, DateTime date, Resolution resolution, TickType tickType)
{
var formattedDate = date.ToString(DateFormat.EightCharacter);
var isHourOrDaily = resolution == Resolution.Hour || resolution == Resolution.Daily;
switch (symbol.ID.SecurityType)
{
case SecurityType.Base:
case SecurityType.Equity:
case SecurityType.Forex:
case SecurityType.Cfd:
case SecurityType.Crypto:
if (resolution == Resolution.Tick && symbol.SecurityType == SecurityType.Equity)
{
return string.Format("{0}_{1}_{2}_{3}.csv",
formattedDate,
symbol.Value.ToLower(),
tickType,
resolution
);
}
if (isHourOrDaily)
{
return string.Format("{0}.csv",
symbol.Value.ToLower()
);
}
return string.Format("{0}_{1}_{2}_{3}.csv",
formattedDate,
symbol.Value.ToLower(),
resolution.ResolutionToLower(),
tickType.TickTypeToLower()
);
case SecurityType.Option:
if (isHourOrDaily)
{
return string.Join("_",
symbol.Underlying.Value.ToLower(), // underlying
tickType.TickTypeToLower(),
symbol.ID.OptionStyle.ToLower(),
symbol.ID.OptionRight.ToLower(),
Scale(symbol.ID.StrikePrice),
symbol.ID.Date.ToString(DateFormat.EightCharacter)
) + ".csv";
}
return string.Join("_",
formattedDate,
symbol.Underlying.Value.ToLower(), // underlying
resolution.ResolutionToLower(),
tickType.TickTypeToLower(),
symbol.ID.OptionStyle.ToLower(),
symbol.ID.OptionRight.ToLower(),
Scale(symbol.ID.StrikePrice),
symbol.ID.Date.ToString(DateFormat.EightCharacter)
) + ".csv";
case SecurityType.Future:
var expiryDate = symbol.ID.Date;
var contractYearMonth = FuturesExpiryUtilityFunctions.ExpiresInPreviousMonth(symbol.ID.Symbol)
? expiryDate.AddMonths(1).ToString(DateFormat.YearMonth)
: expiryDate.ToString(DateFormat.YearMonth);
if (isHourOrDaily)
{
return string.Join("_",
symbol.ID.Symbol.ToLower(),
tickType.TickTypeToLower(),
contractYearMonth,
expiryDate.ToString(DateFormat.EightCharacter)
) + ".csv";
}
return string.Join("_",
formattedDate,
symbol.ID.Symbol.ToLower(),
resolution.ResolutionToLower(),
tickType.TickTypeToLower(),
contractYearMonth,
expiryDate.ToString(DateFormat.EightCharacter)
) + ".csv";
case SecurityType.Commodity:
default:
throw new ArgumentOutOfRangeException();
}
}
///
/// Generates the zip file name for the specified date of data.
///
public static string GenerateZipFileName(Symbol symbol, DateTime date, Resolution resolution, TickType tickType)
{
var tickTypeString = tickType.TickTypeToLower();
var formattedDate = date.ToString(DateFormat.EightCharacter);
var isHourOrDaily = resolution == Resolution.Hour || resolution == Resolution.Daily;
switch (symbol.ID.SecurityType)
{
case SecurityType.Base:
case SecurityType.Equity:
case SecurityType.Forex:
case SecurityType.Cfd:
if (isHourOrDaily)
{
return string.Format("{0}.zip",
symbol.Value.ToLower()
);
}
return string.Format("{0}_{1}.zip",
formattedDate,
tickTypeString
);
case SecurityType.Crypto:
if (isHourOrDaily)
{
return string.Format("{0}_{1}.zip",
symbol.Value.ToLower(),
tickTypeString
);
}
return string.Format("{0}_{1}.zip",
formattedDate,
tickTypeString
);
case SecurityType.Option:
if (isHourOrDaily)
{
return string.Format("{0}_{1}_{2}.zip",
symbol.Underlying.Value.ToLower(), // underlying
tickTypeString,
symbol.ID.OptionStyle.ToLower()
);
}
return string.Format("{0}_{1}_{2}.zip",
formattedDate,
tickTypeString,
symbol.ID.OptionStyle.ToLower()
);
case SecurityType.Future:
if (isHourOrDaily)
{
return string.Format("{0}_{1}.zip",
symbol.ID.Symbol.ToLower(),
tickTypeString);
}
return string.Format("{0}_{1}.zip",
formattedDate,
tickTypeString);
case SecurityType.Commodity:
default:
throw new ArgumentOutOfRangeException();
}
}
///
/// Creates the zip file name for a QC zip data file
///
public static string GenerateZipFileName(string symbol, SecurityType securityType, DateTime date, Resolution resolution, TickType? tickType = null)
{
if (resolution == Resolution.Hour || resolution == Resolution.Daily)
{
return symbol.ToLower() + ".zip";
}
var zipFileName = date.ToString(DateFormat.EightCharacter);
tickType = tickType ?? (securityType == SecurityType.Forex || securityType == SecurityType.Cfd ? TickType.Quote : TickType.Trade);
var suffix = string.Format("_{0}.zip", tickType.Value.TickTypeToLower());
return zipFileName + suffix;
}
///
/// Gets the tick type most commonly associated with the specified security type
///
/// The security type
/// The most common tick type for the specified security type
public static TickType GetCommonTickType(SecurityType securityType)
{
if (securityType == SecurityType.Forex || securityType == SecurityType.Cfd || securityType == SecurityType.Crypto)
{
return TickType.Quote;
}
return TickType.Trade;
}
///
/// Creates a symbol from the specified zip entry name
///
/// The root symbol of the output symbol
/// The resolution of the data source producing the zip entry name
/// The zip entry name to be parsed
/// A new symbol representing the zip entry name
public static Symbol ReadSymbolFromZipEntry(Symbol symbol, Resolution resolution, string zipEntryName)
{
var isHourlyOrDaily = resolution == Resolution.Hour || resolution == Resolution.Daily;
var parts = zipEntryName.Replace(".csv", string.Empty).Split('_');
switch (symbol.ID.SecurityType)
{
case SecurityType.Option:
if (isHourlyOrDaily)
{
var style = (OptionStyle)Enum.Parse(typeof(OptionStyle), parts[2], true);
var right = (OptionRight)Enum.Parse(typeof(OptionRight), parts[3], true);
var strike = decimal.Parse(parts[4]) / 10000m;
var expiry = DateTime.ParseExact(parts[5], DateFormat.EightCharacter, null);
return Symbol.CreateOption(symbol.Underlying, symbol.ID.Market, style, right, strike, expiry);
}
else
{
var style = (OptionStyle)Enum.Parse(typeof(OptionStyle), parts[4], true);
var right = (OptionRight)Enum.Parse(typeof(OptionRight), parts[5], true);
var strike = decimal.Parse(parts[6]) / 10000m;
var expiry = DateTime.ParseExact(parts[7], DateFormat.EightCharacter, null);
return Symbol.CreateOption(symbol.Underlying, symbol.ID.Market, style, right, strike, expiry);
}
case SecurityType.Future:
if (isHourlyOrDaily)
{
var expiryYearMonth = DateTime.ParseExact(parts[2], DateFormat.YearMonth, null);
var futureExpiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(parts[1]);
var futureExpiry = futureExpiryFunc(expiryYearMonth);
return Symbol.CreateFuture(parts[0], symbol.ID.Market, futureExpiry);
}
else
{
var expiryYearMonth = DateTime.ParseExact(parts[4], DateFormat.YearMonth, null);
var futureExpiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(parts[1]);
var futureExpiry = futureExpiryFunc(expiryYearMonth);
return Symbol.CreateFuture(parts[1], symbol.ID.Market, futureExpiry);
}
default:
throw new NotImplementedException($"ReadSymbolFromZipEntry is not implemented for {symbol.ID.SecurityType} {symbol.ID.Market} {resolution}");
}
}
///
/// Scale and convert the resulting number to deci-cents int.
///
private static long Scale(decimal value)
{
return (long)(value*10000);
}
///
/// Create a csv line from the specified arguments
///
private static string ToCsv(params object[] args)
{
// use culture neutral formatting for decimals
for (var i = 0; i < args.Length; i++)
{
var value = args[i];
if (value is decimal)
{
args[i] = ((decimal) value).Normalize().ToString(CultureInfo.InvariantCulture);
}
}
return string.Join(",", args);
}
///
/// Creates a scaled csv line for the bar, if null fills in empty strings
///
private static string ToScaledCsv(IBar bar)
{
if (bar == null)
{
return ToCsv(string.Empty, string.Empty, string.Empty, string.Empty);
}
return ToCsv(Scale(bar.Open), Scale(bar.High), Scale(bar.Low), Scale(bar.Close));
}
///
/// Creates a non scaled csv line for the bar, if null fills in empty strings
///
private static string ToNonScaledCsv(IBar bar)
{
if (bar == null)
{
return ToCsv(string.Empty, string.Empty, string.Empty, string.Empty);
}
return ToCsv(bar.Open, bar.High, bar.Low, bar.Close);
}
///
/// Get the for common Lean data types.
/// If not a Lean common data type, return a TickType of Trade.
///
/// A Type used to determine the TickType
/// The SecurityType used to determine the TickType
/// A TickType corresponding to the type
public static TickType GetCommonTickTypeForCommonDataTypes(Type type, SecurityType securityType)
{
if (type == typeof(TradeBar))
{
return TickType.Trade;
}
if (type == typeof(QuoteBar))
{
return TickType.Quote;
}
if (type == typeof(OpenInterest))
{
return TickType.OpenInterest;
}
if (type == typeof(ZipEntryName))
{
return TickType.Quote;
}
if (type == typeof(Tick))
{
if (securityType == SecurityType.Forex || securityType == SecurityType.Cfd || securityType == SecurityType.Crypto)
{
return TickType.Quote;
}
}
return TickType.Trade;
}
///
/// Parses file name into a and DateTime
///
/// File name to be parsed
/// The symbol as parsed from the fileName
/// Date of data in the file path. Only returned if the resolution is lower than Hourly
/// The resolution of the symbol as parsed from the filePath
public static bool TryParsePath(string fileName, out Symbol symbol, out DateTime date, out Resolution resolution)
{
symbol = null;
resolution = Resolution.Daily;
date = default(DateTime);
var pathSeparators = new[] { '/', '\\'};
var securityTypes = Enum.GetNames(typeof(SecurityType)).Select(x => x.ToLower()).ToList();
try
{
// Removes file extension
fileName = fileName.Replace(fileName.GetExtension(), "");
// remove any relative file path
while (fileName.First() == '.' || pathSeparators.Any(x => x == fileName.First()))
{
fileName = fileName.Remove(0, 1);
}
// split path into components
var info = fileName.Split(pathSeparators, StringSplitOptions.RemoveEmptyEntries).ToList();
// find where the useful part of the path starts - i.e. the securityType
var startIndex = info.FindIndex(x => securityTypes.Contains(x.ToLower()));
// Gather components useed to create the security
var market = info[startIndex + 1];
var ticker = info[startIndex + 3];
resolution = (Resolution)Enum.Parse(typeof(Resolution), info[startIndex + 2], true);
var securityType = (SecurityType)Enum.Parse(typeof(SecurityType), info[startIndex], true);
// If resolution is Daily or Hour, we do not need to set the date and tick type
if (resolution < Resolution.Hour)
{
date = DateTime.ParseExact(info[startIndex + 4].Substring(0, 8), DateFormat.EightCharacter, null);
}
if (securityType == SecurityType.Crypto)
{
ticker = ticker.Split('_').First();
}
symbol = Symbol.Create(ticker, securityType, market);
}
catch (Exception ex)
{
Log.Error("LeanData.TryParsePath(): Error encountered while parsing the path {0}. Error: {1}", fileName, ex.GetBaseException());
return false;
}
return true;
}
}
}