/// <summary> /// Gets the FOP's underlying Future. The underlying Future's contract month might not match /// the contract month of the Future Option when providing CBOT or COMEX based FOPs contracts to this method. /// </summary> /// <param name="futureOptionTicker">Future option ticker</param> /// <param name="market">Market of the Future Option</param> /// <param name="futureOptionExpiration">Expiration date of the future option</param> /// <param name="date">Date to search the future chain provider with. Optional, but required for CBOT based contracts</param> /// <returns>Symbol if there is an underlying for the FOP, null if there's no underlying found for the Future Option</returns> public static Symbol GetUnderlyingFutureFromFutureOption(string futureOptionTicker, string market, DateTime futureOptionExpiration, DateTime?date = null) { var futureTicker = FuturesOptionsSymbolMappings.MapFromOption(futureOptionTicker); var canonicalFuture = Symbol.Create(futureTicker, SecurityType.Future, market); // Get the contract month of the FOP to use when searching for the underlying. // If the FOP and Future share the same contract month, this is reused as the future's // contract month so that we can resolve the Future's expiry. var contractMonth = GetFutureContractMonthNoRulesApplied(canonicalFuture, futureOptionExpiration); if (_underlyingFuturesOptionsRules.ContainsKey(futureTicker)) { // The provided ticker follows some sort of rule. Let's figure out the underlying's contract month. var newFutureContractMonth = _underlyingFuturesOptionsRules[futureTicker](contractMonth, date); if (newFutureContractMonth == null) { // This will only happen when we search the Futures chain for a given contract and no // closest match could be made, i.e. there are no futures in the chain that come after the FOP's // contract month. return(null); } contractMonth = newFutureContractMonth.Value; } var futureExpiry = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFuture)(contractMonth); return(Symbol.CreateFuture(futureTicker, market, futureExpiry)); }
/// <summary> /// Gets the entry for the specified market/symbol/security-type /// </summary> /// <param name="market">The market the exchange resides in, i.e, 'usa', 'fxcm', ect...</param> /// <param name="symbol">The particular symbol being traded</param> /// <param name="securityType">The security type of the symbol</param> /// <returns>The entry matching the specified market/symbol/security-type</returns> public virtual Entry GetEntry(string market, string symbol, SecurityType securityType) { Entry entry; // Fall back on the Futures MHDB entry if the FOP lookup failed. // Some FOPs have the same symbol properties as their futures counterparts. // So, to save ourselves some space, we can fall back on the existing entries // so that we don't duplicate the information. if (!TryGetEntry(market, symbol, securityType, out entry) && !(securityType == SecurityType.FutureOption && TryGetEntry(market, FuturesOptionsSymbolMappings.MapFromOption(symbol), SecurityType.Future, out entry))) { var key = new SecurityDatabaseKey(market, symbol, securityType); var keys = string.Join(", ", _entries.Keys); Log.Error($"MarketHoursDatabase.GetExchangeHours(): Unable to locate exchange hours for {key}.Available keys: {keys}"); if (securityType == SecurityType.Future && market == Market.USA) { var exception = "Future.Usa market type is no longer supported as we mapped each ticker to its actual exchange. " + "Please find your specific market in the symbol-properties database."; if (SymbolPropertiesDatabase.FromDataFolder().TryGetMarket(symbol, SecurityType.Future, out market)) { // let's suggest a market exception += $" Suggested market based on the provided ticker 'Market.{market.ToUpperInvariant()}'."; } throw new ArgumentException(exception); } // there was nothing that really matched exactly throw new ArgumentException($"Unable to locate exchange hours for {key}"); } return(entry); }
/// <summary> /// Tries to get the entry for the specified market/symbol/security-type /// </summary> /// <param name="market">The market the exchange resides in, i.e, 'usa', 'fxcm', ect...</param> /// <param name="symbol">The particular symbol being traded</param> /// <param name="securityType">The security type of the symbol</param> /// <param name="entry">The entry found if any</param> /// <returns>True if the entry was present, else false</returns> public bool TryGetEntry(string market, string symbol, SecurityType securityType, out Entry entry) { return(_entries.TryGetValue(new SecurityDatabaseKey(market, symbol, securityType), out entry) // now check with null symbol key || _entries.TryGetValue(new SecurityDatabaseKey(market, null, securityType), out entry) // if FOP check for future || securityType == SecurityType.FutureOption && TryGetEntry(market, FuturesOptionsSymbolMappings.MapFromOption(symbol), SecurityType.Future, out entry) // if custom data type check for type specific entry || (securityType == SecurityType.Base && symbol.TryGetCustomDataType(out var customType) && _entries.TryGetValue(new SecurityDatabaseKey(market, $"TYPE.{customType}", securityType), out entry))); }
public void GetUnderlyingSymbolFromFutureOption(string futureTicker, string market, int year, int month, int day, int fopContractYear, int fopContractMonth, bool nullExpected) { var optionTicker = FuturesOptionsSymbolMappings.Map(futureTicker); var expectedFuture = Symbol.CreateFuture(futureTicker, market, new DateTime(year, month, day)); var canonicalFutureOption = Symbol.CreateOption(expectedFuture, market, default(OptionStyle), default(OptionRight), default(decimal), SecurityIdentifier.DefaultDate); var futureContractMonthDelta = FuturesExpiryUtilityFunctions.GetDeltaBetweenContractMonthAndContractExpiry(futureTicker, expectedFuture.ID.Date); var futureContractMonth = expectedFuture.ID.Date.AddMonths(futureContractMonthDelta); var futuresOptionsExpiration = FuturesOptionsExpiryFunctions.FuturesOptionExpiry(canonicalFutureOption, futureContractMonth); var actualFuture = FuturesOptionsUnderlyingMapper.GetUnderlyingFutureFromFutureOption(optionTicker, market, futuresOptionsExpiration, new DateTime(2021, 1, 1)); if (nullExpected) { // There were no futures that appeared on the or subsequent contract months from the future option. Assert.IsNull(actualFuture); } else { Assert.AreEqual(expectedFuture, actualFuture); } }
/// <summary> /// Generic generate method. This method should be used carefully as some parameters are not required and /// some parameters mean different things for different security types /// </summary> private static SecurityIdentifier Generate(DateTime date, string symbol, SecurityType securityType, string market, decimal strike = 0, OptionRight optionRight = 0, OptionStyle optionStyle = 0, SecurityIdentifier underlying = null, bool forceSymbolToUpper = true) { if ((ulong)securityType >= SecurityTypeWidth || securityType < 0) { throw new ArgumentOutOfRangeException(nameof(securityType), "securityType must be between 0 and 99"); } if ((int)optionRight > 1 || optionRight < 0) { throw new ArgumentOutOfRangeException(nameof(optionRight), "optionType must be either 0 or 1"); } // normalize input strings market = market.ToLowerInvariant(); symbol = forceSymbolToUpper ? symbol.LazyToUpper() : symbol; if (securityType == SecurityType.FutureOption) { // Futures options tickers might not match, so we need // to map the provided future Symbol to the actual future option Symbol. symbol = FuturesOptionsSymbolMappings.Map(symbol); } var marketIdentifier = QuantConnect.Market.Encode(market); if (!marketIdentifier.HasValue) { throw new ArgumentOutOfRangeException(nameof(market), "The specified market wasn't found in the markets lookup. " + $"Requested: {market}. You can add markets by calling QuantConnect.Market.AddMarket(string,ushort)" ); } var days = (ulong)date.ToOADate() * DaysOffset; var marketCode = (ulong)marketIdentifier * MarketOffset; ulong strikeScale; var strk = NormalizeStrike(strike, out strikeScale) * StrikeOffset; strikeScale *= StrikeScaleOffset; var style = (ulong)optionStyle * OptionStyleOffset; var putcall = (ulong)optionRight * PutCallOffset; var otherData = putcall + days + style + strk + strikeScale + marketCode + (ulong)securityType; var result = new SecurityIdentifier(symbol, otherData, underlying ?? Empty); // we already have these so lets set them switch (securityType) { case SecurityType.Base: case SecurityType.Equity: case SecurityType.Future: result._date = date; break; case SecurityType.Option: case SecurityType.FutureOption: result._date = date; result._strikePrice = strike; result._optionRight = optionRight; result._optionStyle = optionStyle; break; } return(result); }
/// <summary> /// Parses the specified path into a new instance of the <see cref="LeanDataPathComponents"/> class /// </summary> /// <param name="path">The path to be parsed</param> /// <returns>A new instance of the <see cref="LeanDataPathComponents"/> class representing the specified path</returns> public static LeanDataPathComponents Parse(string path) { //"../Data/equity/usa/hour/spy.zip" //"../Data/equity/usa/hour/spy/20160218_trade.zip" var fileinfo = new FileInfo(path); var filename = fileinfo.Name; var parts = path.Split('/', '\\'); // defines the offsets of the security relative to the end of the path const int LowResSecurityTypeOffset = 4; const int HighResSecurityTypeOffset = 5; // defines other offsets relative to the beginning of the substring produce by the above offsets const int MarketOffset = 1; const int ResolutionOffset = 2; const int TickerOffset = 3; if (parts.Length < LowResSecurityTypeOffset) { throw new FormatException($"Unexpected path format: {path}"); } var securityTypeOffset = LowResSecurityTypeOffset; SecurityType securityType; var rawValue = parts[parts.Length - securityTypeOffset]; if (!Enum.TryParse(rawValue, true, out securityType)) { securityTypeOffset = HighResSecurityTypeOffset; rawValue = parts[parts.Length - securityTypeOffset]; if (!Enum.TryParse(rawValue, true, out securityType)) { throw new FormatException($"Unexpected path format: {path}"); } } var market = parts[parts.Length - securityTypeOffset + MarketOffset]; var resolution = (Resolution)Enum.Parse(typeof(Resolution), parts[parts.Length - securityTypeOffset + ResolutionOffset], true); string ticker; if (securityTypeOffset == LowResSecurityTypeOffset) { ticker = Path.GetFileNameWithoutExtension(path); if (securityType == SecurityType.Option || securityType == SecurityType.FutureOption) { // ticker_trade_american var tickerWithoutStyle = ticker.Substring(0, ticker.LastIndexOfInvariant("_")); ticker = tickerWithoutStyle.Substring(0, tickerWithoutStyle.LastIndexOfInvariant("_")); } if (securityType == SecurityType.Future) { // ticker_trade ticker = ticker.Substring(0, ticker.LastIndexOfInvariant("_")); } if (securityType == SecurityType.Crypto && (resolution == Resolution.Daily || resolution == Resolution.Hour)) { // ticker_trade or ticker_quote ticker = ticker.Substring(0, ticker.LastIndexOfInvariant("_")); } } else { ticker = parts[parts.Length - securityTypeOffset + TickerOffset]; } var date = securityTypeOffset == LowResSecurityTypeOffset ? DateTime.MinValue : DateTime.ParseExact(filename.Substring(0, filename.IndexOf("_", StringComparison.Ordinal)), DateFormat.EightCharacter, null); Symbol symbol; if (securityType == SecurityType.Option) { var withoutExtension = Path.GetFileNameWithoutExtension(filename); rawValue = withoutExtension.Substring(withoutExtension.LastIndexOf("_", StringComparison.Ordinal) + 1); var style = (OptionStyle)Enum.Parse(typeof(OptionStyle), rawValue, true); symbol = Symbol.CreateOption(ticker, market, style, OptionRight.Call | OptionRight.Put, 0, SecurityIdentifier.DefaultDate); } else if (securityType == SecurityType.FutureOption) { var withoutExtension = Path.GetFileNameWithoutExtension(filename); rawValue = withoutExtension.Substring(withoutExtension.LastIndexOf("_", StringComparison.Ordinal) + 1); var style = (OptionStyle)Enum.Parse(typeof(OptionStyle), rawValue, true); var futureSymbol = QuantConnect.Symbol.Create(FuturesOptionsSymbolMappings.MapFromOption(ticker), SecurityType.Future, market); symbol = Symbol.CreateOption(futureSymbol, market, style, OptionRight.Call | OptionRight.Put, 0, SecurityIdentifier.DefaultDate); } else if (securityType == SecurityType.Future) { symbol = Symbol.CreateFuture(ticker, market, SecurityIdentifier.DefaultDate); } else { symbol = Symbol.Create(ticker, securityType, market); } var tickType = filename.Contains("_quote") ? TickType.Quote : (filename.Contains("_openinterest") ? TickType.OpenInterest : TickType.Trade); return(new LeanDataPathComponents(securityType, market, resolution, symbol, filename, date, tickType)); }
/// <summary> /// Creates a future option Symbol from the provided ticker /// </summary> /// <param name="ticker">The future option ticker, for example 'ESZ0 P3590'</param> /// <param name="strikeScale">Optional the future option strike scale factor</param> public static Symbol ParseFutureOptionSymbol(string ticker, int strikeScale = 1) { var split = ticker.Split(' '); if (split.Length != 2) { return(null); } var parsed = ParseFutureTicker(split[0]); if (parsed == null) { return(null); } ticker = parsed.Underlying; OptionRight right; if (split[1][0] == 'P' || split[1][0] == 'p') { right = OptionRight.Put; } else if (split[1][0] == 'C' || split[1][0] == 'c') { right = OptionRight.Call; } else { return(null); } var strike = split[1].Substring(1); if (parsed.ExpirationYearShort < 10) { parsed.ExpirationYearShort += 20; } var expirationYearParsed = 2000 + parsed.ExpirationYearShort; var expirationDate = new DateTime(expirationYearParsed, parsed.ExpirationMonth, 1); var strikePrice = decimal.Parse(strike, NumberStyles.Any, CultureInfo.InvariantCulture); var futureTicker = FuturesOptionsSymbolMappings.MapFromOption(ticker); if (!SymbolPropertiesDatabase.FromDataFolder().TryGetMarket(futureTicker, SecurityType.Future, out var market)) { Log.Debug($"SymbolRepresentation.ParseFutureOptionSymbol(): No market found for '{futureTicker}'"); return(null); } var canonicalFuture = Symbol.Create(futureTicker, SecurityType.Future, market); var futureExpiry = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFuture)(expirationDate); var future = Symbol.CreateFuture(futureTicker, market, futureExpiry); var futureOptionExpiry = FuturesOptionsExpiryFunctions.GetFutureOptionExpiryFromFutureExpiry(future); return(Symbol.CreateOption(future, market, OptionStyle.American, right, strikePrice / strikeScale, futureOptionExpiry)); }