コード例 #1
0
        public void TestSP500EMiniExpiryDateFunction()
        {
            var june2017     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Indices.SP500EMini, Market.USA, new DateTime(2017, 6, 15));
            var june2017Func = FuturesExpiryFunctions.FuturesExpiryFunction(june2017.ID.Symbol);

            Assert.AreEqual(june2017Func(june2017.ID.Date), new DateTime(2017, 6, 16, 9, 30, 0));

            var september2017     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Indices.SP500EMini, Market.USA, new DateTime(2017, 9, 1));
            var september2017Func = FuturesExpiryFunctions.FuturesExpiryFunction(september2017.ID.Symbol);

            Assert.AreEqual(september2017Func(september2017.ID.Date), new DateTime(2017, 9, 15, 9, 30, 0));

            var december2017     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Indices.SP500EMini, Market.USA, new DateTime(2017, 12, 31));
            var december2017Func = FuturesExpiryFunctions.FuturesExpiryFunction(december2017.ID.Symbol);

            Assert.AreEqual(december2017Func(december2017.ID.Date), new DateTime(2017, 12, 15, 9, 30, 0));

            var march2018     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Indices.SP500EMini, Market.USA, new DateTime(2018, 3, 31));
            var march2018Func = FuturesExpiryFunctions.FuturesExpiryFunction(march2018.ID.Symbol);

            Assert.AreEqual(march2018Func(march2018.ID.Date), new DateTime(2018, 3, 16, 9, 30, 0));

            var june2018     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Indices.SP500EMini, Market.USA, new DateTime(2018, 3, 31));
            var june2018Func = FuturesExpiryFunctions.FuturesExpiryFunction(june2018.ID.Symbol);

            Assert.AreEqual(june2018Func(june2018.ID.Date), new DateTime(2018, 3, 16, 9, 30, 0));
        }
コード例 #2
0
        public void HongKongFutureFee(bool canonical)
        {
            var symbol = Symbols.CreateFutureSymbol(Futures.Indices.HangSeng, SecurityIdentifier.DefaultDate);

            if (!canonical)
            {
                symbol = Symbols.CreateFutureSymbol(Futures.Indices.HangSeng,
                                                    FuturesExpiryFunctions.FuturesExpiryFunction(symbol)(new DateTime(2021, 12, 1)));
            }
            var entry      = MarketHoursDatabase.FromDataFolder().GetEntry(symbol.ID.Market, symbol, symbol.SecurityType);
            var properties = SymbolPropertiesDatabase.FromDataFolder()
                             .GetSymbolProperties(symbol.ID.Market, symbol, symbol.SecurityType, null);
            var security = new Future(symbol, entry.ExchangeHours,
                                      new Cash(properties.QuoteCurrency, 0, 0),
                                      properties,
                                      ErrorCurrencyConverter.Instance,
                                      RegisteredSecurityDataTypesProvider.Null,
                                      new SecurityCache()
                                      );

            security.SetMarketPrice(new Tick(DateTime.UtcNow, security.Symbol, 100, 100));

            var fee = _feeModel.GetOrderFee(
                new OrderFeeParameters(
                    security,
                    new MarketOrder(security.Symbol, 1000, DateTime.UtcNow)
                    )
                );

            Assert.AreEqual(Currencies.HKD, fee.Value.Currency);
            Assert.AreEqual(1000 * 40m, fee.Value.Amount);
        }
コード例 #3
0
        public void TestGoldExpiryDateFunction()
        {
            var april2017     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Metals.Gold, Market.USA, new DateTime(2017, 4, 1));
            var april2017Func = FuturesExpiryFunctions.FuturesExpiryFunction(april2017.ID.Symbol);

            Assert.AreEqual(april2017Func(april2017.ID.Date), new DateTime(2017, 4, 26));

            var may2017     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Metals.Gold, Market.USA, new DateTime(2017, 5, 31));
            var may2017Func = FuturesExpiryFunctions.FuturesExpiryFunction(may2017.ID.Symbol);

            Assert.AreEqual(may2017Func(may2017.ID.Date), new DateTime(2017, 5, 26));

            var june2017     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Metals.Gold, Market.USA, new DateTime(2017, 6, 15));
            var june2017Func = FuturesExpiryFunctions.FuturesExpiryFunction(june2017.ID.Symbol);

            Assert.AreEqual(june2017Func(june2017.ID.Date), new DateTime(2017, 6, 28));

            var july2017     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Metals.Gold, Market.USA, new DateTime(2017, 7, 15));
            var july2017Func = FuturesExpiryFunctions.FuturesExpiryFunction(july2017.ID.Symbol);

            Assert.AreEqual(july2017Func(july2017.ID.Date), new DateTime(2017, 7, 27));

            var october2018     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Metals.Gold, Market.USA, new DateTime(2018, 10, 15));
            var october2018Func = FuturesExpiryFunctions.FuturesExpiryFunction(october2018.ID.Symbol);

            Assert.AreEqual(october2018Func(october2018.ID.Date), new DateTime(2018, 10, 29));

            var december2021     = Symbol.CreateFuture(QuantConnect.Securities.Futures.Metals.Gold, Market.USA, new DateTime(2021, 12, 15));
            var december2021Func = FuturesExpiryFunctions.FuturesExpiryFunction(december2021.ID.Symbol);

            Assert.AreEqual(december2021Func(december2021.ID.Date), new DateTime(2021, 12, 29));
        }
コード例 #4
0
        /// <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));
        }
コード例 #5
0
        public void FuturesExpiryFunction_MissingSymbol_ShouldThrowArgumentException()
        {
            const string badSymbol = "AAAAA";

            Assert.Throws <ArgumentException>(() => { FuturesExpiryFunctions.FuturesExpiryFunction(badSymbol); },
                                              $"Expiry function not implemented for {badSymbol} in FuturesExpiryFunctions.FuturesExpiryDictionary");
        }
コード例 #6
0
        /// <summary>
        /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        /// </summary>
        /// <param name="data">Slice object keyed by symbol containing the stock data</param>
        public override void OnData(Slice data)
        {
            if (IsWarmingUp)
            {
                // warm up data
                _warmedUp = true;

                if (!_continuousContract.HasData)
                {
                    throw new Exception($"ContinuousContract did not get any data during warmup!");
                }

                var backMonthExpiration  = data.Keys.Single().Underlying.ID.Date;
                var frontMonthExpiration = FuturesExpiryFunctions.FuturesExpiryFunction(_continuousContract.Symbol)(Time.AddMonths(1));
                if (backMonthExpiration <= frontMonthExpiration.Date)
                {
                    throw new Exception($"Unexpected current mapped contract expiration {backMonthExpiration}" +
                                        $" @ {Time} it should be AFTER front month expiration {frontMonthExpiration}");
                }
            }
            if (data.Keys.Count != 1)
            {
                throw new Exception($"We are getting data for more than one symbols! {string.Join(",", data.Keys.Select(symbol => symbol))}");
            }

            if (!Portfolio.Invested)
            {
                Buy(_continuousContract.Symbol, 1);
            }
        }
コード例 #7
0
        /// <summary>
        /// Parses a contract for future with malformed data.
        /// Malformed data usually manifests itself by having "0" assigned to some values
        /// we expect, like the contract's expiry date. The contract is returned by IB
        /// like this, usually due to a high amount of data subscriptions that are active
        /// in an account, surpassing IB's imposed limit. Read more about this here: https://interactivebrokers.github.io/tws-api/rtd_fqa_errors.html#rtd_common_errors_maxmktdata
        ///
        /// We are provided a string in the Symbol in malformed contracts that can be
        /// parsed to construct the clean contract, which is done by this method.
        /// </summary>
        /// <param name="malformedContract">Malformed contract (for futures), i.e. a contract with invalid values ("0") in some of its fields</param>
        /// <param name="symbolPropertiesDatabase">The symbol properties database to use</param>
        /// <returns>Clean Contract for the future</returns>
        /// <remarks>
        /// The malformed contract returns data similar to the following when calling <see cref="InteractiveBrokersBrokerage.GetContractDetails"/>: ES       MAR2021
        /// </remarks>
        public Contract ParseMalformedContractFutureSymbol(Contract malformedContract, SymbolPropertiesDatabase symbolPropertiesDatabase)
        {
            Log.Trace($"InteractiveBrokersSymbolMapper.ParseMalformedContractFutureSymbol(): Parsing malformed contract: {InteractiveBrokersBrokerage.GetContractDescription(malformedContract)} with trading class: \"{malformedContract.TradingClass}\"");

            // capture any character except spaces, match spaces, capture any char except digits, capture digits
            var matches = Regex.Matches(malformedContract.Symbol, @"^(\S*)\s*(\D*)(\d*)");

            var match                   = matches[0].Groups;
            var contractSymbol          = match[1].Value;
            var contractMonthExpiration = DateTime.ParseExact(match[2].Value, "MMM", CultureInfo.CurrentCulture).Month;
            var contractYearExpiration  = match[3].Value;

            var    leanSymbol = GetLeanRootSymbol(contractSymbol);
            string market;

            if (!symbolPropertiesDatabase.TryGetMarket(leanSymbol, SecurityType.Future, out market))
            {
                market = InteractiveBrokersBrokerageModel.DefaultMarketMap[SecurityType.Future];
            }
            var canonicalSymbol   = Symbol.Create(leanSymbol, SecurityType.Future, market);
            var contractMonthYear = new DateTime(int.Parse(contractYearExpiration, CultureInfo.InvariantCulture), contractMonthExpiration, 1);
            // we get the expiration date using the FuturesExpiryFunctions
            var contractExpirationDate = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalSymbol)(contractMonthYear);

            return(new Contract
            {
                Symbol = contractSymbol,
                Multiplier = malformedContract.Multiplier,
                LastTradeDateOrContractMonth = $"{contractExpirationDate:yyyyMMdd}",
                Exchange = malformedContract.Exchange,
                SecType = malformedContract.SecType,
                IncludeExpired = false,
                Currency = malformedContract.Currency
            });
        }
コード例 #8
0
        /// <summary>
        /// Helper method to parse and generate a future symbol from a given user friendly representation
        /// </summary>
        /// <param name="ticker">The future ticker, for example 'ESZ1'</param>
        /// <param name="futureYear">Clarifies the year for the current future</param>
        /// <returns>The future symbol or null if failed</returns>
        public static Symbol ParseFutureSymbol(string ticker, int?futureYear = null)
        {
            var disambiguatedFutureYear = futureYear ?? TodayUtc.Year;
            var parsed = ParseFutureTicker(ticker);

            if (parsed == null)
            {
                return(null);
            }

            var underlying          = parsed.Underlying;
            var expirationYearShort = parsed.ExpirationYearShort;
            var expirationMonth     = parsed.ExpirationMonth;
            var expirationYear      = GetExpirationYear(expirationYearShort, disambiguatedFutureYear);

            if (!SymbolPropertiesDatabase.FromDataFolder().TryGetMarket(underlying, SecurityType.Future, out var market))
            {
                Log.Debug($"SymbolRepresentation.ParseFutureSymbol(): Failed to get market for future '{ticker}' and underlying '{underlying}'");
                return(null);
            }

            var expiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(Symbol.Create(underlying, SecurityType.Future, market));
            var expiryDate = expiryFunc(new DateTime(expirationYear, expirationMonth, 1));

            return(Symbol.CreateFuture(underlying, market, expiryDate));
        }
コード例 #9
0
        public void LiveOptionChainProviderReturnsFutureOptionData()
        {
            var now             = DateTime.Now;
            var december        = new DateTime(now.Year, 12, 1);
            var canonicalFuture = Symbol.Create("ES", SecurityType.Future, Market.CME);
            var expiry          = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFuture)(december);

            // When the current year's december contract expires, the test starts failing.
            // This will happen around the last 10 days of December, but will start working
            // once we've crossed into the new year.
            // Let's try the next listed contract, which is in March of the next year if this is the case.
            if (now >= expiry)
            {
                expiry = now.AddMonths(-now.Month).AddYears(1).AddMonths(3);
            }

            var underlyingFuture = Symbol.CreateFuture("ES", Market.CME, expiry);
            var provider         = new LiveOptionChainProvider();
            var result           = provider.GetOptionContractList(underlyingFuture, now).ToList();

            Assert.AreNotEqual(0, result.Count);

            foreach (var symbol in result)
            {
                Assert.IsTrue(symbol.HasUnderlying);
                Assert.AreEqual(Market.CME, symbol.ID.Market);
                Assert.AreEqual(OptionStyle.American, symbol.ID.OptionStyle);
                Assert.GreaterOrEqual(symbol.ID.StrikePrice, 100m);
                Assert.Less(symbol.ID.StrikePrice, 30000m);
            }
        }
コード例 #10
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}.");
            }
        }
コード例 #11
0
        /// <summary>
        /// Creates a symbol from the specified zip entry name
        /// </summary>
        /// <param name="symbol">The root symbol of the output symbol</param>
        /// <param name="resolution">The resolution of the data source producing the zip entry name</param>
        /// <param name="zipEntryName">The zip entry name to be parsed</param>
        /// <returns>A new symbol representing the zip entry name</returns>
        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:
            case SecurityType.FutureOption:
            case SecurityType.IndexOption:
                if (isHourlyOrDaily)
                {
                    var style  = (OptionStyle)Enum.Parse(typeof(OptionStyle), parts[2], true);
                    var right  = (OptionRight)Enum.Parse(typeof(OptionRight), parts[3], true);
                    var strike = Parse.Decimal(parts[4]) / 10000m;
                    var expiry = Parse.DateTimeExact(parts[5], DateFormat.EightCharacter);
                    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 = Parse.Decimal(parts[6]) / 10000m;
                    var expiry = DateTime.ParseExact(parts[7], DateFormat.EightCharacter, CultureInfo.InvariantCulture);
                    return(Symbol.CreateOption(symbol.Underlying, symbol.ID.Market, style, right, strike, expiry));
                }

            case SecurityType.Future:
                if (isHourlyOrDaily)
                {
                    var expiryYearMonth  = Parse.DateTimeExact(parts[2], DateFormat.YearMonth);
                    var futureExpiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(symbol);
                    var futureExpiry     = futureExpiryFunc(expiryYearMonth);
                    return(Symbol.CreateFuture(parts[0], symbol.ID.Market, futureExpiry));
                }
                else
                {
                    var expiryYearMonth  = Parse.DateTimeExact(parts[4], DateFormat.YearMonth);
                    var futureExpiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(symbol);
                    var futureExpiry     = futureExpiryFunc(expiryYearMonth);
                    return(Symbol.CreateFuture(parts[1], symbol.ID.Market, futureExpiry));
                }

            default:
                throw new NotImplementedException(Invariant(
                                                      $"ReadSymbolFromZipEntry is not implemented for {symbol.ID.SecurityType} {symbol.ID.Market} {resolution}"
                                                      ));
            }
        }
コード例 #12
0
        /// <summary>
        /// Gets the theoretical (i.e. intermediate/naive) future contract month if we assumed a 1-1 mapping
        /// between FOPs contract months and Futures contract months, i.e. they share the same contract month.
        /// </summary>
        /// <param name="canonicalFutureSymbol">Canonical future Symbol</param>
        /// <param name="futureOptionExpirationDate">Future Option Expiration Date</param>
        /// <returns>Contract month assuming that the Future Option and Future share the same contract month</returns>
        private static DateTime GetFutureContractMonthNoRulesApplied(Symbol canonicalFutureSymbol, DateTime futureOptionExpirationDate)
        {
            var baseOptionExpiryMonthDate = new DateTime(futureOptionExpirationDate.Year, futureOptionExpirationDate.Month, 1);

            if (!_futuresOptionsExpiryDelta.ContainsKey(canonicalFutureSymbol.ID.Symbol))
            {
                // For contracts like CL, they have no expiry delta between the Futures and FOPs, so we hit this path.
                // However, it does have a delta between its expiry and contract month, which we adjust here before
                // claiming that `baseOptionExpiryMonthDate` is the future's contract month.
                var futuresExpiry = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFutureSymbol)(baseOptionExpiryMonthDate);
                var futuresDelta  = FuturesExpiryUtilityFunctions.GetDeltaBetweenContractMonthAndContractExpiry(canonicalFutureSymbol.ID.Symbol, futuresExpiry);

                return(baseOptionExpiryMonthDate.AddMonths(futuresDelta));
            }

            return(baseOptionExpiryMonthDate.AddMonths(_futuresOptionsExpiryDelta[canonicalFutureSymbol.ID.Symbol]));
        }
コード例 #13
0
        public void SoftsExpiryDateFunction_WithDifferentDates_ShouldFollowContract(string symbol)
        {
            Assert.IsTrue(_data.ContainsKey(symbol), "Symbol " + symbol + " not present in Test Data");
            foreach (var date in _data[symbol])
            {
                //Arrange
                var futureSymbol = GetFutureSymbol(symbol, date.ContractMonth);
                var func         = FuturesExpiryFunctions.FuturesExpiryFunction(GetFutureSymbol(symbol));

                //Act
                var actual   = func(futureSymbol.ID.Date);
                var expected = date.LastTrade;

                //Assert
                Assert.AreEqual(expected, actual, "Failed for symbol: " + symbol);
            }
        }
コード例 #14
0
        public void DairyExpiryDateFunction_WithDifferentDates_ShouldFollowContract(string symbol, string dayTime)
        {
            Assert.IsTrue(_data.ContainsKey(symbol), "Symbol " + symbol + " not present in Test Data");
            foreach (var date in _data[symbol])
            {
                // Arrange
                var security = Symbol.CreateFuture(symbol, "usa", date.ContractMonth);
                var func     = FuturesExpiryFunctions.FuturesExpiryFunction(security.ID.Symbol);

                // Act
                var actual   = func(security.ID.Date);
                var expected = date.LastTrade + Parse.TimeSpan(dayTime);

                // Assert
                Assert.AreEqual(expected, actual, "Failed for symbol: " + symbol);
            }
        }
コード例 #15
0
        public void GrainsExpiryDateFunction_WithDifferentDates_ShouldFollowContract(string symbol)
        {
            Assert.IsTrue(_data.ContainsKey(symbol), "Symbol " + symbol + " not present in Test Data");
            foreach (var date in _data[symbol])
            {
                //Arrange
                var security = Symbol.CreateFuture(symbol, Market.USA, date.ContractMonth);
                var func     = FuturesExpiryFunctions.FuturesExpiryFunction(security.ID.Symbol);

                //Act
                var calculated = func(security.ID.Date);
                var actual     = date.LastTrade;

                //Assert
                Assert.AreEqual(calculated, actual, "Failed for symbol: " + symbol);
            }
        }
コード例 #16
0
        /// <summary>
        /// Gets the Futures Options' expiry for the given contract month.
        /// </summary>
        /// <param name="canonicalFutureOptionSymbol">Canonical Futures Options Symbol. Will be made canonical if not provided a canonical</param>
        /// <param name="futureContractMonth">Contract month of the underlying Future</param>
        /// <returns>Expiry date/time</returns>
        public static DateTime FuturesOptionExpiry(Symbol canonicalFutureOptionSymbol, DateTime futureContractMonth)
        {
            if (!canonicalFutureOptionSymbol.IsCanonical() || !canonicalFutureOptionSymbol.Underlying.IsCanonical())
            {
                canonicalFutureOptionSymbol = Symbol.CreateOption(
                    Symbol.Create(canonicalFutureOptionSymbol.Underlying.ID.Symbol, SecurityType.Future, canonicalFutureOptionSymbol.Underlying.ID.Market),
                    canonicalFutureOptionSymbol.ID.Market,
                    default(OptionStyle),
                    default(OptionRight),
                    default(decimal),
                    SecurityIdentifier.DefaultDate);
            }

            Func <DateTime, DateTime> expiryFunction;

            if (!_futuresOptionExpiryFunctions.TryGetValue(canonicalFutureOptionSymbol, out expiryFunction))
            {
                // No definition exists for this FOP. Let's default to futures expiry.
                return(FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFutureOptionSymbol.Underlying)(futureContractMonth));
            }

            return(expiryFunction(futureContractMonth));
        }
コード例 #17
0
        /// <summary>
        /// Creates a symbol from the specified zip entry name
        /// </summary>
        /// <param name="symbol">The root symbol of the output symbol</param>
        /// <param name="resolution">The resolution of the data source producing the zip entry name</param>
        /// <param name="zipEntryName">The zip entry name to be parsed</param>
        /// <returns>A new symbol representing the zip entry name</returns>
        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, Market.USA, 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, Market.USA, style, right, strike, expiry));
                }
                break;

            case SecurityType.Future:
                var expiryYearMonth  = DateTime.ParseExact(parts[4], DateFormat.YearMonth, null);
                var futureExpiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(parts[1]);
                var futureExpiry     = futureExpiryFunc(expiryYearMonth);
                return(Symbol.CreateFuture(parts[1], Market.USA, futureExpiry));

            default:
                throw new NotImplementedException("ReadSymbolFromZipEntry is not implemented for " + symbol.ID.SecurityType + " " + resolution);
            }
        }
コード例 #18
0
        public void FuturesExpiryFunctions_AllFutures_ShouldHaveExpiryFunction()
        {
            var missingFutures = new List <string>();

            var futuresSymbols = typeof(QuantConnect.Securities.Futures).GetNestedTypes()
                                 .SelectMany(x => x.GetFields())
                                 .Select(x => x.GetValue(null))                                        // null for obj in GetValue indicates static field
                                 .Cast <string>();

            foreach (var futuresSymbol in futuresSymbols)
            {
                try
                {
                    FuturesExpiryFunctions.FuturesExpiryFunction(futuresSymbol);
                }
                catch (ArgumentException)
                {
                    missingFutures.Add(futuresSymbol);
                }
            }

            Assert.IsEmpty(missingFutures,
                           $"The following symbols do not have an expiry function defined in FuturesExpiryFunction.FuturesExpiryDictionary: {string.Join(", ", missingFutures)}");
        }
コード例 #19
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));
        }
コード例 #20
0
        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);
            }
        }
コード例 #21
0
ファイル: AlgoSeekFuturesReader.cs プロジェクト: zxbe/Lean
        /// <summary>
        /// Parse a string line into a future tick.
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        private Tick Parse(string line)
        {
            try
            {
                const int TradeMask        = 2;
                const int QuoteMask        = 1;
                const int OpenInterestMask = 11;
                const int MessageTypeMask  = 15;

                // parse csv check column count
                var csv = line.ToCsv();
                if (csv.Count - 1 < _columnsCount)
                {
                    return(null);
                }

                var ticker = csv[_columnTicker];

                // we filter out options and spreads
                if (ticker.IndexOfAny(new [] { ' ', '-' }) != -1)
                {
                    return(null);
                }

                ticker = ticker.Trim(new char[] { '"' });

                if (_symbolFilter != null && !_symbolFilter.Contains(ticker))
                {
                    return(null);
                }

                if (string.IsNullOrEmpty(ticker))
                {
                    return(null);
                }

                var parsed = SymbolRepresentation.ParseFutureTicker(ticker);

                if (parsed == null || !_symbolMultipliers.ContainsKey(parsed.Underlying))
                {
                    return(null);
                }

                // ignoring time zones completely -- this is all in the 'data-time-zone'
                var timeString = csv[_columnTimestamp];
                var time       = DateTime.ParseExact(timeString, "yyyyMMddHHmmssFFF", CultureInfo.InvariantCulture);

                var underlying          = parsed.Underlying;
                var expirationYearShort = parsed.ExpirationYearShort;
                var expirationMonth     = parsed.ExpirationMonth;
                var expirationYear      = GetExpirationYear(time, expirationYearShort);

                var expiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(underlying);
                var expiryDate = expiryFunc(new DateTime(expirationYear, expirationMonth, 1));
                var symbol     = Symbol.CreateFuture(underlying, Market.USA, expiryDate);

                // detecting tick type (trade or quote)
                TickType tickType;
                bool     isAsk = false;

                var type = csv[_columnType].ConvertInvariant <int>();
                if ((type & MessageTypeMask) == TradeMask)
                {
                    tickType = TickType.Trade;
                }
                else if ((type & MessageTypeMask) == OpenInterestMask)
                {
                    tickType = TickType.OpenInterest;
                }
                else if ((type & MessageTypeMask) == QuoteMask)
                {
                    tickType = TickType.Quote;

                    switch (csv[_columnSide])
                    {
                    case "B":
                        isAsk = false;
                        break;

                    case "S":
                        isAsk = true;
                        break;

                    default:
                    {
                        return(null);
                    }
                    }
                }
                else
                {
                    return(null);
                }

                // All futures but VIX are delivered with a scale factor of 10000000000.
                var scaleFactor = symbol.ID.Symbol == "VX" ? decimal.One : 10000000000m;

                var price    = csv[_columnPrice].ToDecimal() / scaleFactor;
                var quantity = csv[_columnQuantity].ToInt32();

                price *= _symbolMultipliers[underlying];

                switch (tickType)
                {
                case TickType.Quote:

                    var tick = new Tick
                    {
                        Symbol   = symbol,
                        Time     = time,
                        TickType = tickType,
                        Exchange = Market.USA,
                        Value    = price
                    };

                    if (isAsk)
                    {
                        tick.AskPrice = price;
                        tick.AskSize  = quantity;
                    }
                    else
                    {
                        tick.BidPrice = price;
                        tick.BidSize  = quantity;
                    }
                    return(tick);

                case TickType.Trade:

                    tick = new Tick
                    {
                        Symbol   = symbol,
                        Time     = time,
                        TickType = tickType,
                        Exchange = Market.USA,
                        Value    = price,
                        Quantity = quantity
                    };
                    return(tick);

                case TickType.OpenInterest:

                    tick = new Tick
                    {
                        Symbol   = symbol,
                        Time     = time,
                        TickType = tickType,
                        Exchange = Market.USA,
                        Value    = quantity
                    };
                    return(tick);
                }

                return(null);
            }
            catch (Exception err)
            {
                Log.Error(err);
                Log.Trace("Line: {0}", line);
                return(null);
            }
        }