/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using QuantConnect.Data; using QuantConnect.Orders.Fees; using QuantConnect.Orders.Fills; using QuantConnect.Orders.Slippage; using QuantConnect.Orders.OptionExercise; using Python.Runtime; using QuantConnect.Data.Market; using QuantConnect.Interfaces; using QuantConnect.Util; namespace QuantConnect.Securities.Option { /// /// Option Security Object Implementation for Option Assets /// /// public class Option : Security, IDerivativeSecurity, IOptionPrice { /// /// The default number of days required to settle an equity sale /// public const int DefaultSettlementDays = 1; /// /// The default time of day for settlement /// public static readonly TimeSpan DefaultSettlementTime = new TimeSpan(8, 0, 0); /// /// Constructor for the option security /// /// Defines the hours this exchange is open /// The cash object that represent the quote currency /// The subscription configuration for this security /// The symbol properties for this security /// Currency converter used to convert /// instances into units of the account currency public Option(SecurityExchangeHours exchangeHours, SubscriptionDataConfig config, Cash quoteCurrency, OptionSymbolProperties symbolProperties, ICurrencyConverter currencyConverter) : base(config, quoteCurrency, symbolProperties, new OptionExchange(exchangeHours), new OptionCache(), new OptionPortfolioModel(), new ImmediateFillModel(), new InteractiveBrokersFeeModel(), new ConstantSlippageModel(0), new ImmediateSettlementModel(), Securities.VolatilityModel.Null, new OptionMarginModel(), new OptionDataFilter(), new SecurityPriceVariationModel(), currencyConverter ) { ExerciseSettlement = SettlementType.PhysicalDelivery; SetDataNormalizationMode(DataNormalizationMode.Raw); OptionExerciseModel = new DefaultExerciseModel(); PriceModel = new CurrentPriceOptionPriceModel(); Holdings = new OptionHolding(this, currencyConverter); _symbolProperties = symbolProperties; SetFilter(-1, 1, TimeSpan.Zero, TimeSpan.FromDays(35)); } /// /// Constructor for the option security /// /// The symbol of the security /// Defines the hours this exchange is open /// The cash object that represent the quote currency /// The symbol properties for this security /// Currency converter used to convert /// instances into units of the account currency public Option(Symbol symbol, SecurityExchangeHours exchangeHours, Cash quoteCurrency, OptionSymbolProperties symbolProperties, ICurrencyConverter currencyConverter) : base(symbol, quoteCurrency, symbolProperties, new OptionExchange(exchangeHours), new OptionCache(), new OptionPortfolioModel(), new ImmediateFillModel(), new InteractiveBrokersFeeModel(), new ConstantSlippageModel(0), new ImmediateSettlementModel(), Securities.VolatilityModel.Null, new OptionMarginModel(), new OptionDataFilter(), new SecurityPriceVariationModel(), currencyConverter ) { ExerciseSettlement = SettlementType.PhysicalDelivery; SetDataNormalizationMode(DataNormalizationMode.Raw); OptionExerciseModel = new DefaultExerciseModel(); PriceModel = new CurrentPriceOptionPriceModel(); Holdings = new OptionHolding(this, currencyConverter); _symbolProperties = symbolProperties; SetFilter(-1, 1, TimeSpan.Zero, TimeSpan.FromDays(35)); } // save off a strongly typed version of symbol properties private readonly OptionSymbolProperties _symbolProperties; /// /// Returns true if this is the option chain security, false if it is a specific option contract /// public bool IsOptionChain => Symbol.IsCanonical(); /// /// Returns true if this is a specific option contract security, false if it is the option chain security /// public bool IsOptionContract => !Symbol.IsCanonical(); /// /// Gets the strike price /// public decimal StrikePrice { get { return Symbol.ID.StrikePrice; } } /// /// Gets the expiration date /// public DateTime Expiry { get { return Symbol.ID.Date; } } /// /// Gets the right being purchased (call [right to buy] or put [right to sell]) /// public OptionRight Right { get { return Symbol.ID.OptionRight; } } /// /// Gets the option style /// public OptionStyle Style { get { return Symbol.ID.OptionStyle; } } /// /// When the holder of an equity option exercises one contract, or when the writer of an equity option is assigned /// an exercise notice on one contract, this unit of trade, usually 100 shares of the underlying security, changes hands. /// public int ContractUnitOfTrade { get { return _symbolProperties.ContractUnitOfTrade; } set { _symbolProperties.SetContractUnitOfTrade(value); } } /// /// The contract multiplier for the option security /// public int ContractMultiplier { get { return (int)_symbolProperties.ContractMultiplier; } set { _symbolProperties.SetContractMultiplier(value); } } /// /// Aggregate exercise amount or aggregate contract value. It is the total amount of cash one will pay (or receive) for the shares of the /// underlying stock if he/she decides to exercise (or is assigned an exercise notice). This amount is not the premium paid or received for an equity option. /// public decimal GetAggregateExerciseAmount() { return StrikePrice * ContractMultiplier; } /// /// Returns the actual number of the underlying shares that are going to change hands on exercise. For instance, after reverse split /// we may have 1 option contract with multiplier of 100 with right to buy/sell only 50 shares of underlying stock. /// /// public decimal GetExerciseQuantity(decimal quantity) { return quantity * ContractUnitOfTrade; } /// /// Checks if option is eligible for automatic exercise on expiration /// public bool IsAutoExercised(decimal underlyingPrice) { return GetIntrinsicValue(underlyingPrice) >= 0.01m; } /// /// Intrinsic value function of the option /// public decimal GetIntrinsicValue(decimal underlyingPrice) { return Math.Max(0.0m, GetPayOff(underlyingPrice)); } /// /// Option payoff function at expiration time /// /// The price of the underlying /// public decimal GetPayOff(decimal underlyingPrice) { return Right == OptionRight.Call ? underlyingPrice - StrikePrice : StrikePrice - underlyingPrice; } /// /// Specifies if option contract has physical or cash settlement on exercise /// public SettlementType ExerciseSettlement { get; set; } /// /// Gets or sets the underlying security object. /// public Security Underlying { get; set; } /// /// Gets a reduced interface of the underlying security object. /// ISecurityPrice IOptionPrice.Underlying => Underlying; /// /// For this option security object, evaluates the specified option /// contract to compute a theoretical price, IV and greeks /// /// The current data slice. This can be used to access other information /// available to the algorithm /// The option contract to evaluate /// An instance of containing the theoretical /// price of the specified option contract public OptionPriceModelResult EvaluatePriceModel(Slice slice, OptionContract contract) { return PriceModel.Evaluate(this, slice, contract); } /// /// Gets or sets the price model for this option security /// public IOptionPriceModel PriceModel { get; set; } /// /// Fill model used to produce fill events for this security /// public IOptionExerciseModel OptionExerciseModel { get; set; } /// /// When enabled, approximates Greeks if corresponding pricing model didn't calculate exact numbers /// [Obsolete("This property has been deprecated. Please use QLOptionPriceModel.EnableGreekApproximation instead.")] public bool EnableGreekApproximation { get { var model = PriceModel as QLOptionPriceModel; if (model != null) { return model.EnableGreekApproximation; } return false; } set { var model = PriceModel as QLOptionPriceModel; if (model != null) { model.EnableGreekApproximation = value; } } } /// /// Gets or sets the contract filter /// public IDerivativeSecurityFilter ContractFilter { get; set; } /// /// Sets the to a new instance of the filter /// using the specified min and max strike values. Contracts with expirations further than 35 /// days out will also be filtered. /// /// The min strike rank relative to market price, for example, -1 would put /// a lower bound of one strike under market price, where a +1 would put a lower bound of one strike /// over market price /// The max strike rank relative to market place, for example, -1 would put /// an upper bound of on strike under market price, where a +1 would be an upper bound of one strike /// over market price public void SetFilter(int minStrike, int maxStrike) { SetFilter(universe => universe.Strikes(minStrike, maxStrike)); } /// /// Sets the to a new instance of the filter /// using the specified min and max strike and expiration range values /// /// The minimum time until expiry to include, for example, TimeSpan.FromDays(10) /// would exclude contracts expiring in less than 10 days /// The maxmium time until expiry to include, for example, TimeSpan.FromDays(10) /// would exclude contracts expiring in more than 10 days public void SetFilter(TimeSpan minExpiry, TimeSpan maxExpiry) { SetFilter(universe => universe.Expiration(minExpiry, maxExpiry)); } /// /// Sets the to a new instance of the filter /// using the specified min and max strike and expiration range values /// /// The min strike rank relative to market price, for example, -1 would put /// a lower bound of one strike under market price, where a +1 would put a lower bound of one strike /// over market price /// The max strike rank relative to market place, for example, -1 would put /// an upper bound of on strike under market price, where a +1 would be an upper bound of one strike /// over market price /// The minimum time until expiry to include, for example, TimeSpan.FromDays(10) /// would exclude contracts expiring in less than 10 days /// The maxmium time until expiry to include, for example, TimeSpan.FromDays(10) /// would exclude contracts expiring in more than 10 days public void SetFilter(int minStrike, int maxStrike, TimeSpan minExpiry, TimeSpan maxExpiry) { SetFilter(universe => universe .Strikes(minStrike, maxStrike) .Expiration(minExpiry, maxExpiry)); } /// /// Sets the to a new universe selection function /// /// new universe selection function public void SetFilter(Func universeFunc) { ContractFilter = new FuncSecurityDerivativeFilter(universe => { var optionUniverse = universe as OptionFilterUniverse; var result = universeFunc(optionUniverse); return result.ApplyOptionTypesFilter(); }); } /// /// Sets the to a new universe selection function /// /// new universe selection function public void SetFilter(PyObject universeFunc) { var pyUniverseFunc = PythonUtil.ToFunc(universeFunc); SetFilter(pyUniverseFunc); } /// /// Sets the data normalization mode to be used by this security /// public override void SetDataNormalizationMode(DataNormalizationMode mode) { if (mode != DataNormalizationMode.Raw) { throw new ArgumentException("DataNormalizationMode.Raw must be used with options"); } base.SetDataNormalizationMode(mode); } } }