Overall Statistics |
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio -10.886 Tracking Error 0.143 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset |
#region imports from AlgorithmImports import * from datetime import datetime #endregion class OptionsUniverseSelectionModel(UniverseSelectionModel): def __init__(self, universeSelectionModel: UniverseSelectionModel, optionFilter: Optional[Callable[[OptionFilterUniverse], OptionFilterUniverse]] = None) -> None: self.__nextRefreshTimeUtc: datetime = datetime.max self.__universeSelectionModel: UniverseSelectionModel = universeSelectionModel self.__optionFilter: Optional[Callable[[OptionFilterUniverse], OptionFilterUniverse]] = optionFilter self.__fundamentalUniverses: Dict[Universe, List[Symbol]] = {} def GetNextRefreshTimeUtc(self) -> datetime: parentRefreshTime = self.__universeSelectionModel.GetNextRefreshTimeUtc() if parentRefreshTime <= self.__nextRefreshTimeUtc: self.__fundamentalUniverses = {} self.__nextRefreshTimeUtc = parentRefreshTime return self.__nextRefreshTimeUtc def CreateUniverses(self, algorithm: QCAlgorithm) -> List[Universe]: self.__nextRefreshTimeUtc = datetime.max if len(self.__fundamentalUniverses) <= 0: universes: List[Universe] = self.__universeSelectionModel.CreateUniverses(algorithm) for universe in universes: self.__fundamentalUniverses[universe] : List[Symbol] = [] universe.SelectionChanged += self.UniverseSelectionChanged allUniverses = [] for universe in self.__fundamentalUniverses: allUniverses.append(universe) for optionSymbol in self.__fundamentalUniverses[universe]: optionChainUniverse = self.CreateOptionChain(algorithm, optionSymbol, self.__optionFilter, universe.UniverseSettings) allUniverses.append(optionChainUniverse) return allUniverses def CreateOptionChainSecurity(self, algorithm: QCAlgorithm, symbol: Symbol, settings: UniverseSettings) -> Security: '''Creates the canonical option chain security for a given symbol Args: algorithm: The algorithm instance to create universes for symbol: Symbol of the option settings: Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed Returns Option for the given symbol''' config = algorithm.SubscriptionManager.SubscriptionDataConfigService.Add(symbol, settings.Resolution, settings.FillForward, settings.ExtendedMarketHours, False) security = algorithm.Securities.CreateSecurity(symbol, config, settings.Leverage, False) underlying = symbol.Underlying if not algorithm.Securities.ContainsKey(underlying): underlying_security = algorithm.AddSecurity(underlying.SecurityType, underlying.Value, settings.Resolution, underlying.ID.Market, False, 0, settings.ExtendedMarketHours) else: underlying_security = algorithm.Securities[underlying] self.ConfigureUnderlyingSecurity(algorithm, settings.Resolution, underlying_security) security.Underlying = underlying_security return security def CreateOptionChain(self, algorithm: QCAlgorithm, symbol: Symbol, optionFilter: Optional[Callable[[OptionFilterUniverse], OptionFilterUniverse]], universeSettings: UniverseSettings) -> OptionChainUniverse: '''Creates a OptionChainUniverse for a given symbol Args: algorithm: The algorithm instance to create universes for symbol: Symbol of the option Returns: OptionChainUniverse for the given symbol''' if not Extensions.IsOption(symbol.SecurityType): raise ValueError("CreateOptionChain requires an option symbol.") # rewrite non-canonical symbols to be canonical market = symbol.ID.Market underlying = symbol.Underlying if not symbol.IsCanonical(): alias = f"?{underlying.Value}" symbol = Symbol.Create(underlying.Value, SecurityType.Option, market, alias) # create canonical security object, but don't duplicate if it already exists securities = [s for s in algorithm.Securities if s.Key == symbol] if len(securities) == 0: optionChain = self.CreateOptionChainSecurity(algorithm, symbol, universeSettings) else: optionChain = securities[0] # set the option chain contract filter function optionChain.SetFilter(optionFilter) # force option chain security to not be directly tradable AFTER it's configured to ensure it's not overwritten optionChain.IsTradable = False return OptionChainUniverse(optionChain, universeSettings, algorithm.LiveMode) def UniverseSelectionChanged(self, sender: Object, args: EventArgs) -> None: self.__fundamentalUniverses[sender] = [ Symbol.CreateCanonicalOption(symbol, symbol.ID.Market) for symbol in args.CurrentSelection ] self.__nextRefreshTimeUtc = datetime.min def ConfigureUnderlyingSecurity(self, algorithm: QCAlgorithm, resolution: Resolution, security: Security) -> None: configs = algorithm.SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(security.Symbol) for config in configs: if config.DataNormalizationMode != DataNormalizationMode.Raw: security.SetDataNormalizationMode(DataNormalizationMode.Raw) security.RefreshDataNormalizationModeProperty() if security.VolatilityModel == VolatilityModel.Null: if resolution == Resolution.Daily: updateFrequency = timedelta(days=1) elif resolution == Resolution.Hour: updateFrequency = timedelta(hours=1) elif resolution == Resolution.Minute: updateFrequency = timedelta(minutes=1) else: updateFrequency = timedelta(second=1) security.VolatilityModel = StandardDeviationOfReturnsVolatilityModel(resolution, updateFrequency)
# region imports from AlgorithmImports import * from OptionsUniverseSelection import OptionsUniverseSelectionModel from QuantConnect.Securities.Option import OptionPriceModels # endregion class JumpingMagentaKitten(QCAlgorithm): def Initialize(self) -> None: self.SetStartDate(2021, 1, 19) # Set Start Date self.SetEndDate(2021, 1, 25) # Set End Date self.SetCash(100000) # Set Strategy Cash self.SetSecurityInitializer(self.CustomSecurityInitializer) self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverseSelection( OptionsUniverseSelectionModel( CoarseFundamentalUniverseSelectionModel(self.SelectCoarse), self.OptionFilterFunction ) ) # set the warm-up period for the pricing model self.SetWarmUp(TimeSpan.FromDays(4), self.UniverseSettings.Resolution) def CustomSecurityInitializer(self, security: Security) -> None: # set the pricing model for Greeks and volatility # find more pricing models https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/options-models/pricing if security.Type == SecurityType.Option: security.PriceModel = OptionPriceModels.CrankNicolsonFD() def OnData(self, data: Slice) -> None: if self.IsWarmingUp: return for chain in data.OptionChains: volatility = self.Securities[chain.Key.Underlying].VolatilityModel.Volatility for contract in chain.Value: self.Log("{0},Bid={1} Ask={2} Last={3} OI={4} sigma={5:.3f} NPV={6:.3f} \ delta={7:.3f} gamma={8:.3f} vega={9:.3f} beta={10:.2f} theta={11:.2f} IV={12:.2f}".format( contract.Symbol.Value, contract.BidPrice, contract.AskPrice, contract.LastPrice, contract.OpenInterest, volatility, contract.TheoreticalPrice, contract.Greeks.Delta, contract.Greeks.Gamma, contract.Greeks.Vega, contract.Greeks.Rho, contract.Greeks.Theta / 365, contract.ImpliedVolatility)) def SelectCoarse(self, coarse: List[CoarseFundamental]) -> List[Symbol]: selected = [c for c in coarse if c.HasFundamentalData] sorted_by_dollar_volume = sorted(selected, key=lambda c: c.DollarVolume, reverse=True) return [c.Symbol for c in sorted_by_dollar_volume[:100]] # Return most liquid assets w/ fundamentals def OptionFilterFunction(self, option_filter_universe: OptionFilterUniverse) -> OptionFilterUniverse: return option_filter_universe.Strikes(-2, +2).FrontMonth().CallsOnly()