692 lines
29 KiB
C#
692 lines
29 KiB
C#
/*
|
|
* 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 Python.Runtime;
|
|
using QuantConnect.Data;
|
|
using QuantConnect.Data.Market;
|
|
using QuantConnect.Data.UniverseSelection;
|
|
using QuantConnect.Interfaces;
|
|
using QuantConnect.Orders;
|
|
using QuantConnect.Orders.Fees;
|
|
using QuantConnect.Orders.Fills;
|
|
using QuantConnect.Orders.OptionExercise;
|
|
using QuantConnect.Orders.Slippage;
|
|
using QuantConnect.Python;
|
|
using QuantConnect.Securities.Interfaces;
|
|
using QuantConnect.Util;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace QuantConnect.Securities.Option
|
|
{
|
|
/// <summary>
|
|
/// Option Security Object Implementation for Option Assets
|
|
/// </summary>
|
|
/// <seealso cref="Security"/>
|
|
public class Option : Security, IDerivativeSecurity, IOptionPrice
|
|
{
|
|
/// <summary>
|
|
/// The default number of days required to settle an equity sale
|
|
/// </summary>
|
|
public static int DefaultSettlementDays { get; set; } = 1;
|
|
|
|
/// <summary>
|
|
/// The default time of day for settlement
|
|
/// </summary>
|
|
public static readonly TimeSpan DefaultSettlementTime = new(6, 0, 0);
|
|
|
|
/// <summary>
|
|
/// Constructor for the option security
|
|
/// </summary>
|
|
/// <param name="exchangeHours">Defines the hours this exchange is open</param>
|
|
/// <param name="quoteCurrency">The cash object that represent the quote currency</param>
|
|
/// <param name="config">The subscription configuration for this security</param>
|
|
/// <param name="symbolProperties">The symbol properties for this security</param>
|
|
/// <param name="currencyConverter">Currency converter used to convert <see cref="CashAmount"/>
|
|
/// instances into units of the account currency</param>
|
|
/// <param name="registeredTypes">Provides all data types registered in the algorithm</param>
|
|
/// <param name="priceModelProvider">The option price model provider</param>
|
|
/// <remarks>Used in testing</remarks>
|
|
public Option(SecurityExchangeHours exchangeHours,
|
|
SubscriptionDataConfig config,
|
|
Cash quoteCurrency,
|
|
OptionSymbolProperties symbolProperties,
|
|
ICurrencyConverter currencyConverter,
|
|
IRegisteredSecurityDataTypesProvider registeredTypes,
|
|
IOptionPriceModelProvider priceModelProvider = null)
|
|
: this(config.Symbol,
|
|
quoteCurrency,
|
|
symbolProperties,
|
|
new OptionExchange(exchangeHours),
|
|
new OptionCache(),
|
|
new OptionPortfolioModel(),
|
|
new ImmediateFillModel(),
|
|
new InteractiveBrokersFeeModel(),
|
|
NullSlippageModel.Instance,
|
|
new ImmediateSettlementModel(),
|
|
Securities.VolatilityModel.Null,
|
|
new OptionMarginModel(),
|
|
new OptionDataFilter(),
|
|
new SecurityPriceVariationModel(),
|
|
currencyConverter,
|
|
registeredTypes,
|
|
null,
|
|
priceModelProvider)
|
|
{
|
|
AddData(config);
|
|
SetDataNormalizationMode(DataNormalizationMode.Raw);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor for the option security
|
|
/// </summary>
|
|
/// <param name="symbol">The symbol of the security</param>
|
|
/// <param name="exchangeHours">Defines the hours this exchange is open</param>
|
|
/// <param name="quoteCurrency">The cash object that represent the quote currency</param>
|
|
/// <param name="symbolProperties">The symbol properties for this security</param>
|
|
/// <param name="currencyConverter">Currency converter used to convert <see cref="CashAmount"/>
|
|
/// instances into units of the account currency</param>
|
|
/// <param name="registeredTypes">Provides all data types registered in the algorithm</param>
|
|
/// <param name="securityCache">Cache to store security information</param>
|
|
/// <param name="underlying">Future underlying security</param>
|
|
/// <param name="priceModelProvider">The option price model provider</param>
|
|
public Option(Symbol symbol,
|
|
SecurityExchangeHours exchangeHours,
|
|
Cash quoteCurrency,
|
|
OptionSymbolProperties symbolProperties,
|
|
ICurrencyConverter currencyConverter,
|
|
IRegisteredSecurityDataTypesProvider registeredTypes,
|
|
SecurityCache securityCache,
|
|
Security underlying,
|
|
IOptionPriceModelProvider priceModelProvider = null)
|
|
: this (symbol,
|
|
quoteCurrency,
|
|
symbolProperties,
|
|
new OptionExchange(exchangeHours),
|
|
securityCache,
|
|
new OptionPortfolioModel(),
|
|
new ImmediateFillModel(),
|
|
new InteractiveBrokersFeeModel(),
|
|
NullSlippageModel.Instance,
|
|
new ImmediateSettlementModel(),
|
|
Securities.VolatilityModel.Null,
|
|
new OptionMarginModel(),
|
|
new OptionDataFilter(),
|
|
new SecurityPriceVariationModel(),
|
|
currencyConverter,
|
|
registeredTypes,
|
|
underlying,
|
|
priceModelProvider)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates instance of the Option class.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Allows for the forwarding of the security configuration to the
|
|
/// base Security constructor
|
|
/// </remarks>
|
|
protected Option(Symbol symbol,
|
|
Cash quoteCurrency,
|
|
SymbolProperties symbolProperties,
|
|
SecurityExchange exchange,
|
|
SecurityCache cache,
|
|
ISecurityPortfolioModel portfolioModel,
|
|
IFillModel fillModel,
|
|
IFeeModel feeModel,
|
|
ISlippageModel slippageModel,
|
|
ISettlementModel settlementModel,
|
|
IVolatilityModel volatilityModel,
|
|
IBuyingPowerModel buyingPowerModel,
|
|
ISecurityDataFilter dataFilter,
|
|
IPriceVariationModel priceVariationModel,
|
|
ICurrencyConverter currencyConverter,
|
|
IRegisteredSecurityDataTypesProvider registeredTypesProvider,
|
|
Security underlying,
|
|
IOptionPriceModelProvider priceModelProvider
|
|
) : base(
|
|
symbol,
|
|
quoteCurrency,
|
|
symbolProperties,
|
|
exchange,
|
|
cache,
|
|
portfolioModel,
|
|
fillModel,
|
|
feeModel,
|
|
slippageModel,
|
|
settlementModel,
|
|
volatilityModel,
|
|
buyingPowerModel,
|
|
dataFilter,
|
|
priceVariationModel,
|
|
currencyConverter,
|
|
registeredTypesProvider,
|
|
Securities.MarginInterestRateModel.Null
|
|
)
|
|
{
|
|
ExerciseSettlement = SettlementType.PhysicalDelivery;
|
|
SetDataNormalizationMode(DataNormalizationMode.Raw);
|
|
OptionExerciseModel = new DefaultExerciseModel();
|
|
PriceModel = (priceModelProvider ?? QLOptionPriceModelProvider.Instance).GetOptionPriceModel(symbol);
|
|
Holdings = new OptionHolding(this, currencyConverter);
|
|
_symbolProperties = (OptionSymbolProperties)symbolProperties;
|
|
SetFilter(-1, 1, TimeSpan.Zero, TimeSpan.FromDays(35));
|
|
Underlying = underlying;
|
|
OptionAssignmentModel = new DefaultOptionAssignmentModel();
|
|
ScaledStrikePrice = StrikePrice * SymbolProperties.StrikeMultiplier;
|
|
}
|
|
|
|
// save off a strongly typed version of symbol properties
|
|
private readonly OptionSymbolProperties _symbolProperties;
|
|
|
|
/// <summary>
|
|
/// Returns true if this is the option chain security, false if it is a specific option contract
|
|
/// </summary>
|
|
public bool IsOptionChain => Symbol.IsCanonical();
|
|
|
|
/// <summary>
|
|
/// Returns true if this is a specific option contract security, false if it is the option chain security
|
|
/// </summary>
|
|
public bool IsOptionContract => !Symbol.IsCanonical();
|
|
|
|
/// <summary>
|
|
/// Gets the strike price
|
|
/// </summary>
|
|
public decimal StrikePrice => Symbol.ID.StrikePrice;
|
|
|
|
/// <summary>
|
|
/// Gets the strike price multiplied by the strike multiplier
|
|
/// </summary>
|
|
public decimal ScaledStrikePrice
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the expiration date
|
|
/// </summary>
|
|
public DateTime Expiry => Symbol.ID.Date;
|
|
|
|
/// <summary>
|
|
/// Gets the right being purchased (call [right to buy] or put [right to sell])
|
|
/// </summary>
|
|
public OptionRight Right => Symbol.ID.OptionRight;
|
|
|
|
/// <summary>
|
|
/// Gets the option style
|
|
/// </summary>
|
|
public OptionStyle Style => Symbol.ID.OptionStyle;
|
|
|
|
/// <summary>
|
|
/// Gets the most recent bid price if available
|
|
/// </summary>
|
|
public override decimal BidPrice => Cache.BidPrice;
|
|
|
|
/// <summary>
|
|
/// Gets the most recent ask price if available
|
|
/// </summary>
|
|
public override decimal AskPrice => Cache.AskPrice;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public int ContractUnitOfTrade
|
|
{
|
|
get
|
|
{
|
|
return _symbolProperties.ContractUnitOfTrade;
|
|
}
|
|
set
|
|
{
|
|
_symbolProperties.SetContractUnitOfTrade(value);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The contract multiplier for the option security
|
|
/// </summary>
|
|
public int ContractMultiplier
|
|
{
|
|
get
|
|
{
|
|
return (int)_symbolProperties.ContractMultiplier;
|
|
}
|
|
set
|
|
{
|
|
_symbolProperties.SetContractMultiplier(value);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public decimal GetAggregateExerciseAmount()
|
|
{
|
|
return StrikePrice * ContractMultiplier;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the directional quantity of underlying shares that are going to change hands on exercise/assignment of all
|
|
/// contracts held by this account, taking into account the contract's <see cref="Right"/> as well as the contract's current
|
|
/// <see cref="ContractUnitOfTrade"/>, which may have recently changed due to a split/reverse split in the underlying security.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Long option positions result in exercise while short option positions result in assignment. This function uses the term
|
|
/// exercise loosely to refer to both situations.
|
|
/// </remarks>
|
|
public decimal GetExerciseQuantity()
|
|
{
|
|
// negate Holdings.Quantity to match an equivalent order
|
|
return GetExerciseQuantity(-Holdings.Quantity);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the directional quantity of underlying shares that are going to change hands on exercise/assignment of the
|
|
/// specified <paramref name="exerciseOrderQuantity"/>, taking into account the contract's <see cref="Right"/> as well
|
|
/// as the contract's current <see cref="ContractUnitOfTrade"/>, which may have recently changed due to a split/reverse
|
|
/// split in the underlying security.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Long option positions result in exercise while short option positions result in assignment. This function uses the term
|
|
/// exercise loosely to refer to both situations.
|
|
/// </remarks>
|
|
/// <paramref name="exerciseOrderQuantity">The quantity of contracts being exercised as provided by the <see cref="OptionExerciseOrder"/>.
|
|
/// A negative value indicates exercise (we are long and the order quantity is negative to bring us (closer) to zero.
|
|
/// A positive value indicates assignment (we are short and the order quantity is positive to bring us (closer) to zero.</paramref>
|
|
public decimal GetExerciseQuantity(decimal exerciseOrderQuantity)
|
|
{
|
|
// when exerciseOrderQuantity > 0 [ we are short ]
|
|
// && right == call => we sell to contract holder => negative
|
|
// && right == put => we buy from contract holder => positive
|
|
|
|
// when exerciseOrderQuantity < 0 [ we are long ]
|
|
// && right == call => we buy from contract holder => positive
|
|
// && right == put => we sell to contract holder => negative
|
|
|
|
var sign = Right == OptionRight.Call ? -1 : 1;
|
|
return sign * exerciseOrderQuantity * ContractUnitOfTrade;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if option is eligible for automatic exercise on expiration
|
|
/// </summary>
|
|
public bool IsAutoExercised(decimal underlyingPrice)
|
|
{
|
|
return GetIntrinsicValue(underlyingPrice) >= 0.01m;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Intrinsic value function of the option
|
|
/// </summary>
|
|
public decimal GetIntrinsicValue(decimal underlyingPrice)
|
|
{
|
|
return OptionPayoff.GetIntrinsicValue(underlyingPrice, ScaledStrikePrice, Right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Option payoff function at expiration time
|
|
/// </summary>
|
|
/// <param name="underlyingPrice">The price of the underlying</param>
|
|
/// <returns></returns>
|
|
public decimal GetPayOff(decimal underlyingPrice)
|
|
{
|
|
return OptionPayoff.GetPayOff(underlyingPrice, ScaledStrikePrice, Right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Option out of the money function
|
|
/// </summary>
|
|
/// <param name="underlyingPrice">The price of the underlying</param>
|
|
/// <returns></returns>
|
|
public decimal OutOfTheMoneyAmount(decimal underlyingPrice)
|
|
{
|
|
return Math.Max(0, Right == OptionRight.Call ? ScaledStrikePrice - underlyingPrice : underlyingPrice - ScaledStrikePrice);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies if option contract has physical or cash settlement on exercise
|
|
/// </summary>
|
|
public SettlementType ExerciseSettlement
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the underlying security object.
|
|
/// </summary>
|
|
public Security Underlying
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a reduced interface of the underlying security object.
|
|
/// </summary>
|
|
ISecurityPrice IOptionPrice.Underlying => Underlying;
|
|
|
|
/// <summary>
|
|
/// For this option security object, evaluates the specified option
|
|
/// contract to compute a theoretical price, IV and greeks
|
|
/// </summary>
|
|
/// <param name="slice">The current data slice. This can be used to access other information
|
|
/// available to the algorithm</param>
|
|
/// <param name="contract">The option contract to evaluate</param>
|
|
/// <returns>An instance of <see cref="OptionPriceModelResult"/> containing the theoretical
|
|
/// price of the specified option contract</returns>
|
|
public OptionPriceModelResult EvaluatePriceModel(Slice slice, OptionContract contract)
|
|
{
|
|
return PriceModel.Evaluate(new OptionPriceModelParameters(this, slice, contract));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the price model for this option security
|
|
/// </summary>
|
|
public IOptionPriceModel PriceModel
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fill model used to produce fill events for this security
|
|
/// </summary>
|
|
public IOptionExerciseModel OptionExerciseModel
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The automatic option assignment model
|
|
/// </summary>
|
|
public IOptionAssignmentModel OptionAssignmentModel
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// When enabled, approximates Greeks if corresponding pricing model didn't calculate exact numbers
|
|
/// </summary>
|
|
[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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the contract filter
|
|
/// </summary>
|
|
public IDerivativeSecurityFilter<OptionUniverse> ContractFilter
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the automatic option assignment model
|
|
/// </summary>
|
|
/// <param name="pyObject">The option assignment model to use</param>
|
|
public void SetOptionAssignmentModel(PyObject pyObject)
|
|
{
|
|
OptionAssignmentModel = PythonUtil.CreateInstanceOrWrapper<IOptionAssignmentModel>(
|
|
pyObject,
|
|
py => new OptionAssignmentModelPythonWrapper(py)
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the automatic option assignment model
|
|
/// </summary>
|
|
/// <param name="optionAssignmentModel">The option assignment model to use</param>
|
|
public void SetOptionAssignmentModel(IOptionAssignmentModel optionAssignmentModel)
|
|
{
|
|
OptionAssignmentModel = optionAssignmentModel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the option exercise model
|
|
/// </summary>
|
|
/// <param name="pyObject">The option exercise model to use</param>
|
|
public void SetOptionExerciseModel(PyObject pyObject)
|
|
{
|
|
OptionExerciseModel = PythonUtil.CreateInstanceOrWrapper<IOptionExerciseModel>(
|
|
pyObject,
|
|
py => new OptionExerciseModelPythonWrapper(py)
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the option exercise model
|
|
/// </summary>
|
|
/// <param name="optionExerciseModel">The option exercise model to use</param>
|
|
public void SetOptionExerciseModel(IOptionExerciseModel optionExerciseModel)
|
|
{
|
|
OptionExerciseModel = optionExerciseModel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the <see cref="ContractFilter"/> 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.
|
|
/// </summary>
|
|
/// <param name="minStrike">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</param>
|
|
/// <param name="maxStrike">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</param>
|
|
public void SetFilter(int minStrike, int maxStrike)
|
|
{
|
|
SetFilterImp(universe => universe.Strikes(minStrike, maxStrike));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the <see cref="ContractFilter"/> to a new instance of the filter
|
|
/// using the specified min and max strike and expiration range values
|
|
/// </summary>
|
|
/// <param name="minExpiry">The minimum time until expiry to include, for example, TimeSpan.FromDays(10)
|
|
/// would exclude contracts expiring in less than 10 days</param>
|
|
/// <param name="maxExpiry">The maximum time until expiry to include, for example, TimeSpan.FromDays(10)
|
|
/// would exclude contracts expiring in more than 10 days</param>
|
|
public void SetFilter(TimeSpan minExpiry, TimeSpan maxExpiry)
|
|
{
|
|
SetFilterImp(universe => universe.Expiration(minExpiry, maxExpiry));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the <see cref="ContractFilter"/> to a new instance of the filter
|
|
/// using the specified min and max strike and expiration range values
|
|
/// </summary>
|
|
/// <param name="minStrike">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</param>
|
|
/// <param name="maxStrike">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</param>
|
|
/// <param name="minExpiry">The minimum time until expiry to include, for example, TimeSpan.FromDays(10)
|
|
/// would exclude contracts expiring in less than 10 days</param>
|
|
/// <param name="maxExpiry">The maximum time until expiry to include, for example, TimeSpan.FromDays(10)
|
|
/// would exclude contracts expiring in more than 10 days</param>
|
|
public void SetFilter(int minStrike, int maxStrike, TimeSpan minExpiry, TimeSpan maxExpiry)
|
|
{
|
|
SetFilterImp(universe => universe
|
|
.Strikes(minStrike, maxStrike)
|
|
.Expiration(minExpiry, maxExpiry));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the <see cref="ContractFilter"/> to a new instance of the filter
|
|
/// using the specified min and max strike and expiration range values
|
|
/// </summary>
|
|
/// <param name="minStrike">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</param>
|
|
/// <param name="maxStrike">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</param>
|
|
/// <param name="minExpiryDays">The minimum time, expressed in days, until expiry to include, for example, 10
|
|
/// would exclude contracts expiring in less than 10 days</param>
|
|
/// <param name="maxExpiryDays">The maximum time, expressed in days, until expiry to include, for example, 10
|
|
/// would exclude contracts expiring in more than 10 days</param>
|
|
public void SetFilter(int minStrike, int maxStrike, int minExpiryDays, int maxExpiryDays)
|
|
{
|
|
SetFilterImp(universe => universe
|
|
.Strikes(minStrike, maxStrike)
|
|
.Expiration(minExpiryDays, maxExpiryDays));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the <see cref="ContractFilter"/> to a new universe selection function
|
|
/// </summary>
|
|
/// <param name="universeFunc">new universe selection function</param>
|
|
public void SetFilter(Func<OptionFilterUniverse, OptionFilterUniverse> universeFunc)
|
|
{
|
|
ContractFilter = new FuncSecurityDerivativeFilter<OptionUniverse>(universe =>
|
|
{
|
|
var optionUniverse = universe as OptionFilterUniverse;
|
|
//A null result is allowed: filter methods modify the universe in place,
|
|
//returning it is only necessary for chaining
|
|
var result = universeFunc(optionUniverse) ?? optionUniverse;
|
|
return result.ApplyTypesFilter();
|
|
});
|
|
ContractFilter.Asynchronous = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the <see cref="ContractFilter"/> to a new universe selection function
|
|
/// </summary>
|
|
/// <param name="universeFunc">new universe selection function</param>
|
|
public void SetFilter(PyObject universeFunc)
|
|
{
|
|
ContractFilter = new FuncSecurityDerivativeFilter<OptionUniverse>(universe =>
|
|
{
|
|
var optionUniverse = universe as OptionFilterUniverse;
|
|
using (Py.GIL())
|
|
{
|
|
PyObject result = (universeFunc as dynamic)(optionUniverse);
|
|
|
|
//Try to convert it to the possible outcomes and process it
|
|
//Must try filter first, if it is a filter and you try and convert it to
|
|
//list, TryConvert() with catch an exception. Later Python algo will break on
|
|
//this exception because we are using Py.GIL() and it will see the error set
|
|
OptionFilterUniverse filter;
|
|
List<Symbol> list;
|
|
|
|
//A None result is allowed: filter methods modify the universe in place,
|
|
//returning it is only necessary for chaining
|
|
if (result == null || result.IsNone())
|
|
{
|
|
return optionUniverse.ApplyTypesFilter();
|
|
}
|
|
|
|
if ((result).TryConvert(out filter))
|
|
{
|
|
optionUniverse = filter;
|
|
}
|
|
else if ((result).TryConvert(out list))
|
|
{
|
|
optionUniverse = optionUniverse.WhereContains(list);
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException($"QCAlgorithm.SetFilter: result type {result.GetPythonType()} from " +
|
|
$"filter function is not a valid argument, please return either a OptionFilterUniverse or a list of symbols");
|
|
}
|
|
}
|
|
return optionUniverse.ApplyTypesFilter();
|
|
});
|
|
ContractFilter.Asynchronous = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the data normalization mode to be used by this security
|
|
/// </summary>
|
|
public override void SetDataNormalizationMode(DataNormalizationMode mode)
|
|
{
|
|
if (mode != DataNormalizationMode.Raw)
|
|
{
|
|
throw new ArgumentException("DataNormalizationMode.Raw must be used with options");
|
|
}
|
|
|
|
base.SetDataNormalizationMode(mode);
|
|
}
|
|
|
|
private void SetFilterImp(Func<OptionFilterUniverse, OptionFilterUniverse> universeFunc)
|
|
{
|
|
ContractFilter = new FuncSecurityDerivativeFilter<OptionUniverse>(universe =>
|
|
{
|
|
var optionUniverse = universe as OptionFilterUniverse;
|
|
var result = universeFunc(optionUniverse);
|
|
return result.ApplyTypesFilter();
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the option price model
|
|
/// </summary>
|
|
/// <param name="pyObject">The option price model to use</param>
|
|
public void SetPriceModel(PyObject pyObject)
|
|
{
|
|
PriceModel = PythonUtil.CreateInstanceOrWrapper<IOptionPriceModel>(
|
|
pyObject,
|
|
py => new OptionPriceModelPythonWrapper(py)
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the option price model
|
|
/// </summary>
|
|
/// <param name="priceModel">The option price model to use</param>
|
|
public void SetPriceModel(IOptionPriceModel priceModel)
|
|
{
|
|
PriceModel = priceModel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the symbol properties of this security
|
|
/// </summary>
|
|
internal override void UpdateSymbolProperties(SymbolProperties symbolProperties)
|
|
{
|
|
if (symbolProperties != null)
|
|
{
|
|
SymbolProperties = new OptionSymbolProperties(symbolProperties);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the securities symbol
|
|
/// </summary>
|
|
public static implicit operator Symbol(Option security) => security.Symbol;
|
|
}
|
|
}
|