/*
* 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 QuantConnect.Data;
using QuantConnect.Logging;
using QuantConnect.Securities;
using QuantConnect.Securities.Option;
namespace QuantConnect.Indicators
{
///
/// Provides an implementation of that uses QuantConnect indicators
/// to provide a theoretical price for the option contract.
///
public class IndicatorBasedOptionPriceModel : OptionPriceModel
{
private readonly OptionPricingModelType? _optionPricingModelType;
private readonly OptionPricingModelType? _ivModelType;
private IDividendYieldModel _dividendYieldModel;
private readonly IRiskFreeInterestRateModel _riskFreeInterestRateModel;
private readonly bool _userSpecifiedDividendYieldModel;
private readonly bool _useMirrorContract;
private readonly SecurityManager _securityProvider;
///
/// Creates a new instance of the class
///
/// The option pricing model type to be used by the indicators
/// The option pricing model type to be used by the implied volatility indicator
/// The dividend yield model to be used by the indicators
/// The risk free interest rate model to be used by the indicators
/// Whether to use the mirror contract when possible
/// The security provider used to fetch the mirror contract
public IndicatorBasedOptionPriceModel(OptionPricingModelType? optionModel = null,
OptionPricingModelType? ivModel = null, IDividendYieldModel dividendYieldModel = null,
IRiskFreeInterestRateModel riskFreeInterestRateModel = null, bool useMirrorContract = true,
SecurityManager securityProvider = null)
{
_optionPricingModelType = optionModel;
_ivModelType = ivModel;
_dividendYieldModel = dividendYieldModel;
_riskFreeInterestRateModel = riskFreeInterestRateModel;
_useMirrorContract = useMirrorContract;
_userSpecifiedDividendYieldModel = dividendYieldModel != null;
_securityProvider = securityProvider;
}
///
/// Creates a new containing the theoretical price based on
/// QuantConnect indicators.
///
/// The evaluation parameters
///
/// An instance of containing the theoretical
/// price of the specified option contract.
///
public override OptionPriceModelResult Evaluate(OptionPriceModelParameters parameters)
{
var contract = parameters.Contract;
// expired options have no price
if (contract.Time.Date > contract.Expiry.Date)
{
if (Log.DebuggingEnabled)
{
Log.Debug($"IndicatorBasedOptionPriceModel.Evaluate(). Expired {contract.Symbol}. Time > Expiry: {contract.Time.Date} > {contract.Expiry.Date}");
}
return OptionPriceModelResult.None;
}
var option = parameters.Security as Option;
var underlying = option.Underlying;
if (option.Price == 0)
{
if (Log.DebuggingEnabled)
{
Log.Debug($"IndicatorBasedOptionPriceModel.Evaluate(). Missing data for the option security {option.Symbol}.");
}
return OptionPriceModelResult.None;
}
if (underlying.Price == 0)
{
if (Log.DebuggingEnabled)
{
Log.Debug($"IndicatorBasedOptionPriceModel.Evaluate(). Missing data for the underlying security {underlying.Symbol}.");
}
return OptionPriceModelResult.None;
}
var contractSymbol = contract.Symbol;
Symbol mirrorContractSymbol = null;
if (!_userSpecifiedDividendYieldModel)
{
_dividendYieldModel = GreeksIndicators.GetDividendYieldModel(contractSymbol);
}
if (_useMirrorContract)
{
mirrorContractSymbol = contractSymbol.GetMirrorOptionSymbol();
}
if (!_securityProvider.TryGetValue(mirrorContractSymbol, out var mirrorOption) || mirrorOption.Price == 0)
{
if (Log.DebuggingEnabled)
{
if (mirrorOption == null)
{
Log.Debug($"IndicatorBasedOptionPriceModel.Evaluate(). Mirror contract {mirrorContractSymbol} not found. Using contract symbol only.");
}
else
{
Log.Debug($"IndicatorBasedOptionPriceModel.Evaluate(). Missing data for the mirror option contract {mirrorContractSymbol}. Using contract symbol only.");
}
}
// Null so that the indicators don't consider the mirror option and don't expect data for it
mirrorContractSymbol = null;
mirrorOption = null;
}
var indicators = new GreeksIndicators(contractSymbol, mirrorContractSymbol, _optionPricingModelType, _ivModelType,
_dividendYieldModel, _riskFreeInterestRateModel);
var time = option.LocalTime;
indicators.Update(new IndicatorDataPoint(underlying.Symbol, time, underlying.Price));
indicators.Update(new IndicatorDataPoint(option.Symbol, time, option.Price));
if (mirrorOption != null)
{
indicators.Update(new IndicatorDataPoint(mirrorOption.Symbol, time, mirrorOption.Price));
}
return indicators.CurrentResult;
}
}
}