/// <summary> /// Performs universe selection using the data specified /// </summary> /// <param name="utcTime">The current utc time</param> /// <param name="data">The symbols to remain in the universe</param> /// <returns>The data that passes the filter</returns> public override IEnumerable <Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data) { // date change detection needs to be done in exchange time zone var exchangeDate = data.Time.ConvertFromUtc(Option.Exchange.TimeZone).Date; if (_cacheDate == exchangeDate) { return(Unchanged); } var availableContracts = data.Data.Select(x => x.Symbol); // we will only update unique strikes when there is an exchange date change _optionFilterUniverse.Refresh(availableContracts, data.Underlying, _lastExchangeDate != exchangeDate); _lastExchangeDate = exchangeDate; var results = Option.ContractFilter.Filter(_optionFilterUniverse); // if results are not dynamic, we cache them and won't call filtering till the end of the day if (!results.IsDynamic) { _cacheDate = data.Time.ConvertFromUtc(Option.Exchange.TimeZone).Date; } // always prepend the underlying symbol return(_underlyingSymbol.Concat(results)); }
/// <summary> /// Gets <see cref="OptionHistory"/> object for a given symbol, date and resolution /// </summary> /// <param name="symbol">The symbol to retrieve historical option data for</param> /// <param name="start">The history request start time</param> /// <param name="end">The history request end time. Defaults to 1 day if null</param> /// <param name="resolution">The resolution to request</param> /// <returns>A <see cref="OptionHistory"/> object that contains historical option data.</returns> public OptionHistory GetOptionHistory(Symbol symbol, DateTime start, DateTime?end = null, Resolution?resolution = null) { if (!end.HasValue || end.Value == start) { end = start.AddDays(1); } // Load a canonical option Symbol if the user provides us with an underlying Symbol if (symbol.SecurityType != SecurityType.Option && symbol.SecurityType != SecurityType.FutureOption) { symbol = AddOption(symbol, resolution, symbol.ID.Market).Symbol; } IEnumerable <Symbol> symbols; if (symbol.IsCanonical()) { // canonical symbol, lets find the contracts var option = Securities[symbol] as Option; var resolutionToUseForUnderlying = resolution ?? SubscriptionManager.SubscriptionDataConfigService .GetSubscriptionDataConfigs(symbol) .GetHighestResolution(); if (!Securities.ContainsKey(symbol.Underlying)) { // only add underlying if not present AddEquity(symbol.Underlying.Value, resolutionToUseForUnderlying); } var allSymbols = new List <Symbol>(); for (var date = start; date < end; date = date.AddDays(1)) { if (option.Exchange.DateIsOpen(date)) { allSymbols.AddRange(OptionChainProvider.GetOptionContractList(symbol.Underlying, date)); } } var optionFilterUniverse = new OptionFilterUniverse(); var distinctSymbols = allSymbols.Distinct(); symbols = base.History(symbol.Underlying, start, end.Value, resolution) .SelectMany(x => { // the option chain symbols wont change so we can set 'exchangeDateChange' to false always optionFilterUniverse.Refresh(distinctSymbols, x, exchangeDateChange: false); return(option.ContractFilter.Filter(optionFilterUniverse)); }) .Distinct().Concat(new[] { symbol.Underlying }); } else { // the symbol is a contract symbols = new List <Symbol> { symbol }; } return(new OptionHistory(History(symbols, start, end.Value, resolution))); }
/// <summary> /// Performs universe selection using the data specified /// </summary> /// <param name="utcTime">The current utc time</param> /// <param name="data">The symbols to remain in the universe</param> /// <returns>The data that passes the filter</returns> public override IEnumerable <Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data) { var optionsUniverseDataCollection = data as OptionChainUniverseDataCollection; if (optionsUniverseDataCollection == null) { throw new ArgumentException($"Expected data of type '{typeof(OptionChainUniverseDataCollection).Name}'"); } // date change detection needs to be done in exchange time zone var exchangeDate = data.Time.ConvertFromUtc(Option.Exchange.TimeZone).Date; if (_cacheDate == exchangeDate) { return(Unchanged); } var availableContracts = optionsUniverseDataCollection.Data.Select(x => x.Symbol); // we will only update unique strikes when there is an exchange date change _optionFilterUniverse.Refresh(availableContracts, optionsUniverseDataCollection.Underlying, _lastExchangeDate != exchangeDate); _lastExchangeDate = exchangeDate; var results = Option.ContractFilter.Filter(_optionFilterUniverse); // if results are not dynamic, we cache them and won't call filtering till the end of the day if (!results.IsDynamic) { _cacheDate = data.Time.ConvertFromUtc(Option.Exchange.TimeZone).Date; } // always prepend the underlying symbol #if NETCORE var resultingSymbols = LinqExtensions.ToHashSet(_underlyingSymbol.Concat(results)); #else var resultingSymbols = _underlyingSymbol.Concat(results).ToHashSet(); #endif // we save off the filtered results to the universe data collection for later // population into the OptionChain. This is non-ideal and could be remedied by // the universe subscription emitting a special type after selection that could // be checked for in TimeSlice.Create, but for now this will do optionsUniverseDataCollection.FilteredContracts = resultingSymbols; return(resultingSymbols); }
/// <summary> /// Gets <see cref="OptionHistory"/> object for a given symbol, date and resolution /// </summary> /// <param name="symbol">The symbol to retrieve historical option data for</param> /// <param name="start">The history request start time</param> /// <param name="end">The history request end time. Defaults to 1 day if null</param> /// <param name="resolution">The resolution to request</param> /// <returns>A <see cref="OptionHistory"/> object that contains historical option data.</returns> public OptionHistory GetOptionHistory(Symbol symbol, DateTime start, DateTime?end = null, Resolution?resolution = null) { if (!end.HasValue || end.Value == start) { end = start.AddDays(1); } // Load a canonical option Symbol if the user provides us with an underlying Symbol if (!symbol.SecurityType.IsOption()) { var option = AddOption(symbol, resolution, symbol.ID.Market); // Allow 20 strikes from the money for futures. No expiry filter is applied // so that any future contract provided will have data returned. if (symbol.SecurityType == SecurityType.Future && symbol.IsCanonical()) { throw new ArgumentException("The Future Symbol provided is a canonical Symbol (i.e. a Symbol representing all Futures), which is not supported at this time. " + "If you are using the Symbol accessible from `AddFuture(...)`, use the Symbol from `AddFutureContract(...)` instead. " + "You can use `qb.FutureOptionChainProvider(canonicalFuture, datetime)` to get a list of futures contracts for a given date, and add them to your algorithm with `AddFutureContract(symbol, Resolution)`."); } if (symbol.SecurityType == SecurityType.Future && !symbol.IsCanonical()) { option.SetFilter(universe => universe.Strikes(-10, +10)); } symbol = option.Symbol; } IEnumerable <Symbol> symbols; if (symbol.IsCanonical()) { // canonical symbol, lets find the contracts var option = Securities[symbol] as Option; var resolutionToUseForUnderlying = resolution ?? SubscriptionManager.SubscriptionDataConfigService .GetSubscriptionDataConfigs(symbol) .GetHighestResolution(); if (!Securities.ContainsKey(symbol.Underlying)) { if (symbol.Underlying.SecurityType == SecurityType.Equity) { // only add underlying if not present AddEquity(symbol.Underlying.Value, resolutionToUseForUnderlying); } if (symbol.Underlying.SecurityType == SecurityType.Future && symbol.Underlying.IsCanonical()) { AddFuture(symbol.Underlying.ID.Symbol, resolutionToUseForUnderlying); } else if (symbol.Underlying.SecurityType == SecurityType.Future) { AddFutureContract(symbol.Underlying, resolutionToUseForUnderlying); } } var allSymbols = new List <Symbol>(); for (var date = start; date < end; date = date.AddDays(1)) { if (option.Exchange.DateIsOpen(date)) { allSymbols.AddRange(OptionChainProvider.GetOptionContractList(symbol.Underlying, date)); } } var optionFilterUniverse = new OptionFilterUniverse(); var distinctSymbols = allSymbols.Distinct(); symbols = base.History(symbol.Underlying, start, end.Value, resolution) .SelectMany(x => { // the option chain symbols wont change so we can set 'exchangeDateChange' to false always optionFilterUniverse.Refresh(distinctSymbols, x, exchangeDateChange: false); return(option.ContractFilter.Filter(optionFilterUniverse)); }) .Distinct().Concat(new[] { symbol.Underlying }); } else { // the symbol is a contract symbols = new List <Symbol> { symbol }; } return(new OptionHistory(History(symbols, start, end.Value, resolution))); }