Example #1
0
        public void ExpiryFunctionsReturnExpectedResults(string futureTicker, string market, DateTime expected)
        {
            var future       = Symbol.Create(futureTicker, SecurityType.Future, market);
            var futureOption = Symbol.CreateOption(future, market, default(OptionStyle), default(OptionRight), default(decimal), SecurityIdentifier.DefaultDate);

            var december = new DateTime(2020, 12, 1);
            var actual   = FuturesOptionsExpiryFunctions.FuturesOptionExpiry(futureOption, december);

            Assert.AreEqual(expected, actual);
        }
Example #2
0
        /// <summary>
        /// Converts an InteractiveBrokers symbol to a Lean symbol instance
        /// </summary>
        /// <param name="brokerageSymbol">The InteractiveBrokers symbol</param>
        /// <param name="securityType">The security type</param>
        /// <param name="market">The market</param>
        /// <param name="expirationDate">Expiration date of the security(if applicable)</param>
        /// <param name="strike">The strike of the security (if applicable)</param>
        /// <param name="optionRight">The option right of the security (if applicable)</param>
        /// <returns>A new Lean Symbol instance</returns>
        public Symbol GetLeanSymbol(string brokerageSymbol, SecurityType securityType, string market, DateTime expirationDate = default(DateTime), decimal strike = 0, OptionRight optionRight = 0)
        {
            if (string.IsNullOrWhiteSpace(brokerageSymbol))
            {
                throw new ArgumentException("Invalid symbol: " + brokerageSymbol);
            }

            if (securityType != SecurityType.Forex &&
                securityType != SecurityType.Equity &&
                securityType != SecurityType.Option &&
                securityType != SecurityType.Future &&
                securityType != SecurityType.FutureOption)
            {
                throw new ArgumentException("Invalid security type: " + securityType);
            }

            try
            {
                switch (securityType)
                {
                case SecurityType.Future:
                    return(Symbol.CreateFuture(GetLeanRootSymbol(brokerageSymbol), market, expirationDate));

                case SecurityType.Option:
                    return(Symbol.CreateOption(brokerageSymbol, market, OptionStyle.American, optionRight, strike, expirationDate));

                case SecurityType.FutureOption:
                    var canonicalFutureSymbol = Symbol.Create(GetLeanRootSymbol(brokerageSymbol), SecurityType.Future, market);
                    var futureContractMonth   = FuturesOptionsExpiryFunctions.GetFutureContractMonth(canonicalFutureSymbol, expirationDate);
                    var futureExpiry          = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFutureSymbol)(futureContractMonth);

                    return(Symbol.CreateOption(
                               Symbol.CreateFuture(
                                   brokerageSymbol,
                                   market,
                                   futureExpiry),
                               market,
                               OptionStyle.American,
                               optionRight,
                               strike,
                               expirationDate));

                case SecurityType.Equity:
                    brokerageSymbol = brokerageSymbol.Replace(" ", ".");
                    break;
                }

                return(Symbol.Create(brokerageSymbol, securityType, market));
            }
            catch (Exception)
            {
                throw new ArgumentException($"Invalid symbol: {brokerageSymbol}, security type: {securityType}, market: {market}.");
            }
        }
Example #3
0
        [TestCase("GC", Market.COMEX, 11, 1)] // No mapping is done for this Symbol as expected, although rules exist.
        public void FutureContractMonthDelta(string futureTicker, string market, int expiryMonth, int expectedDelta)
        {
            var contractMonth = new DateTime(2020, 12, 1);

            var future = Symbol.Create(futureTicker, SecurityType.Future, market);
            var option = Symbol.CreateOption(
                future,
                market,
                default(OptionStyle),
                default(OptionRight),
                default(decimal),
                SecurityIdentifier.DefaultDate);

            var futureOptionExpiry = FuturesOptionsExpiryFunctions.FuturesOptionExpiry(option, contractMonth);

            Assert.AreEqual(expectedDelta, contractMonth.Month - futureOptionExpiry.Month);
        }
Example #4
0
        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);
            }
        }
        private IEnumerable <Symbol> GetFutureOptionContractList(Symbol futureContractSymbol, DateTime date)
        {
            var symbols    = new List <Symbol>();
            var retries    = 0;
            var maxRetries = 5;

            while (++retries <= maxRetries)
            {
                try
                {
                    _rateGate.WaitToProceed();

                    var productResponse = _client.GetAsync(CMEProductSlateURL.Replace(CMESymbolReplace, futureContractSymbol.ID.Symbol))
                                          .SynchronouslyAwaitTaskResult();

                    productResponse.EnsureSuccessStatusCode();

                    var productResults = JsonConvert.DeserializeObject <CMEProductSlateV2ListResponse>(productResponse.Content
                                                                                                       .ReadAsStringAsync()
                                                                                                       .SynchronouslyAwaitTaskResult());

                    productResponse.Dispose();

                    // We want to gather the future product to get the future options ID
                    var futureProductId = productResults.Products.Where(p => p.Globex == futureContractSymbol.ID.Symbol && p.GlobexTraded && p.Cleared == "Futures")
                                          .Select(p => p.Id)
                                          .Single();


                    var optionsTradesAndExpiries = CMEOptionsTradeDateAndExpirations.Replace(CMEProductCodeReplace, futureProductId.ToStringInvariant());

                    _rateGate.WaitToProceed();

                    var optionsTradesAndExpiriesResponse = _client.GetAsync(optionsTradesAndExpiries).SynchronouslyAwaitTaskResult();
                    optionsTradesAndExpiriesResponse.EnsureSuccessStatusCode();

                    var tradesAndExpiriesResponse = JsonConvert.DeserializeObject <List <CMEOptionsTradeDatesAndExpiration> >(optionsTradesAndExpiriesResponse.Content
                                                                                                                              .ReadAsStringAsync()
                                                                                                                              .SynchronouslyAwaitTaskResult());

                    optionsTradesAndExpiriesResponse.Dispose();

                    // For now, only support American options on CME
                    var selectedOption = tradesAndExpiriesResponse
                                         .FirstOrDefault(x => !x.Daily && !x.Weekly && !x.Sto && x.OptionType == "AME");

                    if (selectedOption == null)
                    {
                        Log.Error($"LiveOptionChainProvider.GetFutureOptionContractList(): Found no matching future options for contract {futureContractSymbol}");
                        yield break;
                    }

                    // Gather the month code and the year's last number to query the next API, which expects an expiration as `<MONTH_CODE><YEAR_LAST_NUMBER>`
                    var canonicalFuture = Symbol.Create(futureContractSymbol.ID.Symbol, SecurityType.Future, futureContractSymbol.ID.Market);
                    var expiryFunction  = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFuture);

                    var futureContractExpiration = selectedOption.Expirations
                                                   .Select(x => new KeyValuePair <CMEOptionsExpiration, DateTime>(x, expiryFunction(new DateTime(x.Expiration.Year, x.Expiration.Month, 1))))
                                                   .FirstOrDefault(x => x.Value.Year == futureContractSymbol.ID.Date.Year && x.Value.Month == futureContractSymbol.ID.Date.Month)
                                                   .Key;

                    if (futureContractExpiration == null)
                    {
                        Log.Error($"LiveOptionChainProvider.GetFutureOptionContractList(): Found no future options with matching expiry year and month for contract {futureContractSymbol}");
                        yield break;
                    }

                    var futureContractMonthCode = futureContractExpiration.Expiration.Code;

                    _rateGate.WaitToProceed();

                    // Subtract one day from now for settlement API since settlement may not be available for today yet
                    var optionChainQuotesResponseResult = _client.GetAsync(CMEOptionChainQuotesURL
                                                                           .Replace(CMEProductCodeReplace, selectedOption.ProductId.ToStringInvariant())
                                                                           .Replace(CMEProductExpirationReplace, futureContractMonthCode)
                                                                           + Math.Floor((DateTime.UtcNow - _epoch).TotalMilliseconds).ToStringInvariant());

                    optionChainQuotesResponseResult.Result.EnsureSuccessStatusCode();

                    var futureOptionChain = JsonConvert.DeserializeObject <CMEOptionChainQuotes>(optionChainQuotesResponseResult.Result.Content
                                                                                                 .ReadAsStringAsync()
                                                                                                 .SynchronouslyAwaitTaskResult())
                                            .Quotes
                                            .DistinctBy(s => s.StrikePrice)
                                            .ToList();

                    optionChainQuotesResponseResult.Dispose();

                    // Each CME contract can have arbitrary scaling applied to the strike price, so we normalize it to the
                    // underlying's price via static entries.
                    var optionStrikePriceScaleFactor = CMEStrikePriceScalingFactors.GetScaleFactor(futureContractSymbol);
                    var canonicalOption = Symbol.CreateOption(
                        futureContractSymbol,
                        futureContractSymbol.ID.Market,
                        futureContractSymbol.SecurityType.DefaultOptionStyle(),
                        default(OptionRight),
                        default(decimal),
                        SecurityIdentifier.DefaultDate);

                    foreach (var optionChainEntry in futureOptionChain)
                    {
                        var futureOptionExpiry = FuturesOptionsExpiryFunctions.GetFutureOptionExpiryFromFutureExpiry(futureContractSymbol, canonicalOption);
                        var scaledStrikePrice  = optionChainEntry.StrikePrice / optionStrikePriceScaleFactor;

                        // Calls and puts share the same strike, create two symbols per each to avoid iterating twice.
                        symbols.Add(Symbol.CreateOption(
                                        futureContractSymbol,
                                        futureContractSymbol.ID.Market,
                                        OptionStyle.American,
                                        OptionRight.Call,
                                        scaledStrikePrice,
                                        futureOptionExpiry));

                        symbols.Add(Symbol.CreateOption(
                                        futureContractSymbol,
                                        futureContractSymbol.ID.Market,
                                        OptionStyle.American,
                                        OptionRight.Put,
                                        scaledStrikePrice,
                                        futureOptionExpiry));
                    }

                    break;
                }
                catch (HttpRequestException err)
                {
                    if (retries != maxRetries)
                    {
                        Log.Error(err, $"Failed to retrieve futures options chain from CME, retrying ({retries} / {maxRetries})");
                        continue;
                    }

                    Log.Error(err, $"Failed to retrieve futures options chain from CME, returning empty result ({retries} / {retries})");
                }
            }

            foreach (var symbol in symbols)
            {
                yield return(symbol);
            }
        }
Example #6
0
        /// <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));
        }