diff --git a/Lean.DataSource.OptionsUniverseGenerator/GreeksIndicators.cs b/Lean.DataSource.OptionsUniverseGenerator/GreeksIndicators.cs deleted file mode 100644 index f9a3c6a..0000000 --- a/Lean.DataSource.OptionsUniverseGenerator/GreeksIndicators.cs +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.Market; -using QuantConnect.Data; -using QuantConnect.Indicators; - -namespace QuantConnect.DataSource.OptionsUniverseGenerator -{ - /// - /// Helper class that holds and updates the greeks indicators - /// - public class GreeksIndicators - { - private readonly static IRiskFreeInterestRateModel _interestRateProvider = new InterestRateProvider(); - - private readonly Symbol _optionSymbol; - private readonly Symbol _mirrorOptionSymbol; - - private readonly ImpliedVolatility _iv; - - private readonly Delta _delta; - private readonly Gamma _gamma; - private readonly Vega _vega; - private readonly Theta _theta; - private readonly Rho _rho; - - public decimal ImpliedVolatility => _iv; - - public decimal InterestRate => _delta.RiskFreeRate; - - public decimal DividendYield => _delta.DividendYield; - - public GreeksIndicators(Symbol optionSymbol, Symbol mirrorOptionSymbol, OptionPricingModelType? optionModel = null, - OptionPricingModelType? ivModel = null) - { - _optionSymbol = optionSymbol; - _mirrorOptionSymbol = mirrorOptionSymbol; - - IDividendYieldModel dividendYieldModel = optionSymbol.SecurityType != SecurityType.IndexOption - ? DividendYieldProvider.CreateForOption(_optionSymbol) - : new ConstantDividendYieldModel(0); - - _iv = new ImpliedVolatility(_optionSymbol, _interestRateProvider, dividendYieldModel, _mirrorOptionSymbol, ivModel); - _delta = new Delta(_optionSymbol, _interestRateProvider, dividendYieldModel, _mirrorOptionSymbol, optionModel, ivModel); - _gamma = new Gamma(_optionSymbol, _interestRateProvider, dividendYieldModel, _mirrorOptionSymbol, optionModel, ivModel); - _vega = new Vega(_optionSymbol, _interestRateProvider, dividendYieldModel, _mirrorOptionSymbol, optionModel, ivModel); - _theta = new Theta(_optionSymbol, _interestRateProvider, dividendYieldModel, _mirrorOptionSymbol, optionModel, ivModel); - _rho = new Rho(_optionSymbol, _interestRateProvider, dividendYieldModel, _mirrorOptionSymbol, optionModel, ivModel); - - _delta.ImpliedVolatility = _iv; - _gamma.ImpliedVolatility = _iv; - _vega.ImpliedVolatility = _iv; - _theta.ImpliedVolatility = _iv; - _rho.ImpliedVolatility = _iv; - } - - public void Update(IBaseDataBar data) - { - _iv.Update(data); - _delta.Update(data); - _gamma.Update(data); - _vega.Update(data); - _theta.Update(data); - _rho.Update(data); - } - - public Greeks GetGreeks() - { - return new GreeksHolder(_delta, _gamma, _vega, _theta, _rho); - } - - private class GreeksHolder : Greeks - { - public override decimal Delta { get; } - - public override decimal Gamma { get; } - - public override decimal Vega { get; } - - public override decimal Theta { get; } - - public override decimal Rho { get; } - - public override decimal Lambda { get; } - - public GreeksHolder(decimal delta, decimal gamma, decimal vega, decimal theta, decimal rho) - { - Delta = delta; - Gamma = gamma; - Vega = vega; - Theta = theta; - Rho = rho; - } - } - } -} \ No newline at end of file diff --git a/Lean.DataSource.OptionsUniverseGenerator/OptionUniverseEntry.cs b/Lean.DataSource.OptionsUniverseGenerator/OptionUniverseEntry.cs index c9dcdea..b92c731 100644 --- a/Lean.DataSource.OptionsUniverseGenerator/OptionUniverseEntry.cs +++ b/Lean.DataSource.OptionsUniverseGenerator/OptionUniverseEntry.cs @@ -17,6 +17,7 @@ using QuantConnect.Data; using QuantConnect.Data.Market; using QuantConnect.Data.UniverseSelection; +using QuantConnect.Indicators; namespace QuantConnect.DataSource.OptionsUniverseGenerator { @@ -30,12 +31,12 @@ public class OptionUniverseEntry : BaseContractUniverseFileEntry /// /// Option contract's implied volatility on the processing date. /// - public decimal? ImpliedVolatility => _greeksIndicators?.ImpliedVolatility; + public decimal? ImpliedVolatility => _greeksIndicators?.ImpliedVolatility?.Current?.Value; /// /// Option contract's greeks on the processing date. /// - public Greeks Greeks => _greeksIndicators?.GetGreeks(); + public Greeks Greeks => _greeksIndicators?.Greeks; /// /// Initializes a new instance of the class. @@ -46,9 +47,9 @@ public OptionUniverseEntry(Symbol symbol) { // Options universes contain a line for the underlying: we don't need greeks for it. // Future options don't have greeks either. - if (HasGreeks(symbol.SecurityType)) + if (HasGreeks(symbol.SecurityType) && !symbol.IsCanonical()) { - var mirrorOptionSymbol = OptionsUniverseGeneratorUtils.GetMirrorOptionSymbol(symbol); + var mirrorOptionSymbol = symbol.GetMirrorOptionSymbol(); _greeksIndicators = new GreeksIndicators(symbol, mirrorOptionSymbol); } } diff --git a/Lean.DataSource.OptionsUniverseGenerator/OptionsUniverseGenerator.cs b/Lean.DataSource.OptionsUniverseGenerator/OptionsUniverseGenerator.cs index d7d647b..b08c25c 100644 --- a/Lean.DataSource.OptionsUniverseGenerator/OptionsUniverseGenerator.cs +++ b/Lean.DataSource.OptionsUniverseGenerator/OptionsUniverseGenerator.cs @@ -1,176 +1,176 @@ -/* - * 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 System.Linq; -using QuantConnect.Data; -using QuantConnect.Util; -using QuantConnect.Securities; -using QuantConnect.DataSource.DerivativeUniverseGenerator; -using System.Collections.Generic; -using QuantConnect.Logging; -using QuantConnect.Interfaces; - -namespace QuantConnect.DataSource.OptionsUniverseGenerator -{ - /// - /// Options Universe generator - /// - public class OptionsUniverseGenerator : DerivativeUniverseGenerator.DerivativeUniverseGenerator - { - private static readonly SecurityType[] _supportedSecurityTypes = { SecurityType.Option, SecurityType.IndexOption, SecurityType.FutureOption }; - - /// - /// Initializes a new instance of the class. - /// - /// The processing date - /// Option security type to process - /// Market of data to process - /// Path to the data folder - /// Path to the output folder - /// The data provider to use - /// The data cache provider to use - /// The history provider to use - public OptionsUniverseGenerator(DateTime processingDate, SecurityType securityType, string market, string dataFolderRoot, - string outputFolderRoot, IDataProvider dataProvider, IDataCacheProvider dataCacheProvider, IHistoryProvider historyProvider) - : base(processingDate, securityType, market, dataFolderRoot, outputFolderRoot, dataProvider, dataCacheProvider, historyProvider) - { - if (!_supportedSecurityTypes.Contains(securityType)) - { - throw new ArgumentException($"Only {string.Join(", ", _supportedSecurityTypes)} are supported", nameof(securityType)); - } - } - - protected override IDerivativeUniverseFileEntry CreateUniverseEntry(Symbol symbol) - { - return new OptionUniverseEntry(symbol); - } - - protected override bool NeedsUnderlyingData() - { - // We don't need underlying data for future options, since they don't have greeks, so no need for underlying data for calculation - return OptionUniverseEntry.HasGreeks(_securityType); - } - - protected override Dictionary> FilterSymbols(Dictionary> symbols, - HashSet symbolsToProcess) - { - if (symbolsToProcess.IsNullOrEmpty()) - { - return symbols; - } - - if (_securityType == SecurityType.FutureOption) - { - return symbols.Where(kvp => symbolsToProcess.Contains(kvp.Key.Underlying.Canonical.Value.Replace("/", ""))).ToDictionary(); - } - - return symbols.Where(kvp => symbolsToProcess.Contains(kvp.Key.Underlying.Value)).ToDictionary(); - } - - /// - /// Adds a request for the mirror option symbol to the base list of requests. - /// - protected override HistoryRequest[] GetDerivativeHistoryRequests(Symbol symbol, DateTime start, DateTime end, MarketHoursDatabase.Entry marketHoursEntry) - { - var requests = base.GetDerivativeHistoryRequests(symbol, start, end, marketHoursEntry); - - var mirrorOptionSymbol = OptionsUniverseGeneratorUtils.GetMirrorOptionSymbol(symbol); - var mirrorOptionHistoryRequests = base.GetDerivativeHistoryRequests(mirrorOptionSymbol, start, end, marketHoursEntry); - - return requests.Concat(mirrorOptionHistoryRequests).ToArray(); - } - - /// - /// Generates and the derivative universe entries for the specified canonical symbol. - /// - protected override IEnumerable GenerateDerivativeEntries(Symbol canonicalSymbol, List symbols, - MarketHoursDatabase.Entry marketHoursEntry, List underlyingHistory, IDerivativeUniverseFileEntry underlyingEntry) - { - var generatedEntries = base.GenerateDerivativeEntries(canonicalSymbol, symbols, marketHoursEntry, underlyingHistory, underlyingEntry); - - if (!OptionUniverseEntry.HasGreeks(canonicalSymbol.SecurityType)) - { - return generatedEntries; - } - - var entries = new List(); - var entriesWithMissingIv = new List(); - // Enumerate the base entries to materialize them and check whether IVs are missing and need to be interpolated - foreach (OptionUniverseEntry entry in generatedEntries) - { - entries.Add(entry); - if (!entry.ImpliedVolatility.HasValue || entry.ImpliedVolatility == 0) - { - // We keep the entries with missing IVs to interpolate them later and avoid iterating through the whole list again - entriesWithMissingIv.Add(entry); - } - } - - if (entriesWithMissingIv.Count > 0) - { - // Interpolate missing IVs and re-generate greeks - ImpliedVolatilityInterpolator ivInterpolator = null; - try - { - ivInterpolator = ImpliedVolatilityInterpolator.Create(_processingDate, entries, - (underlyingEntry as OptionUniverseEntry).Close, entries.Count - entriesWithMissingIv.Count); - } - catch (Exception e) - { - Log.Error($"Failed to set up IV interpolator for {canonicalSymbol}. Error: {e.GetType()}: {e}"); - } - - if (ivInterpolator != null) - { - var failedInterpolationsCount = 0; - foreach (var entry in entriesWithMissingIv) - { - var interpolatedIv = 0m; - try - { - interpolatedIv = ivInterpolator.Interpolate(entry.Symbol.ID.StrikePrice, entry.Symbol.ID.Date); - } - catch - { - Log.Error($"Failed interpolating IV for {entry.Symbol.Value} :: Underlying price: {(underlyingEntry as OptionUniverseEntry).Close}"); - failedInterpolationsCount++; - } - - if (interpolatedIv != 0) - { - var updatedGreeks = ivInterpolator.GetUpdatedGreeksIndicators(entry.Symbol, interpolatedIv); - entry.SetGreeksIndicators(updatedGreeks); - } - } - - if (failedInterpolationsCount > 0) - { - Log.Error($"Failed interpolating IV for {failedInterpolationsCount} out of {entriesWithMissingIv.Count} contracts for {canonicalSymbol}."); - } - } - } - - return entries; - } - - private int _missingIvLogCount; - - /// - /// Overridden just for logging failed IV calculations in debug mode - /// +/* + * 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 System.Linq; +using QuantConnect.Data; +using QuantConnect.Util; +using QuantConnect.Securities; +using QuantConnect.DataSource.DerivativeUniverseGenerator; +using System.Collections.Generic; +using QuantConnect.Logging; +using QuantConnect.Interfaces; + +namespace QuantConnect.DataSource.OptionsUniverseGenerator +{ + /// + /// Options Universe generator + /// + public class OptionsUniverseGenerator : DerivativeUniverseGenerator.DerivativeUniverseGenerator + { + private static readonly SecurityType[] _supportedSecurityTypes = { SecurityType.Option, SecurityType.IndexOption, SecurityType.FutureOption }; + + /// + /// Initializes a new instance of the class. + /// + /// The processing date + /// Option security type to process + /// Market of data to process + /// Path to the data folder + /// Path to the output folder + /// The data provider to use + /// The data cache provider to use + /// The history provider to use + public OptionsUniverseGenerator(DateTime processingDate, SecurityType securityType, string market, string dataFolderRoot, + string outputFolderRoot, IDataProvider dataProvider, IDataCacheProvider dataCacheProvider, IHistoryProvider historyProvider) + : base(processingDate, securityType, market, dataFolderRoot, outputFolderRoot, dataProvider, dataCacheProvider, historyProvider) + { + if (!_supportedSecurityTypes.Contains(securityType)) + { + throw new ArgumentException($"Only {string.Join(", ", _supportedSecurityTypes)} are supported", nameof(securityType)); + } + } + + protected override IDerivativeUniverseFileEntry CreateUniverseEntry(Symbol symbol) + { + return new OptionUniverseEntry(symbol); + } + + protected override bool NeedsUnderlyingData() + { + // We don't need underlying data for future options, since they don't have greeks, so no need for underlying data for calculation + return OptionUniverseEntry.HasGreeks(_securityType); + } + + protected override Dictionary> FilterSymbols(Dictionary> symbols, + HashSet symbolsToProcess) + { + if (symbolsToProcess.IsNullOrEmpty()) + { + return symbols; + } + + if (_securityType == SecurityType.FutureOption) + { + return symbols.Where(kvp => symbolsToProcess.Contains(kvp.Key.Underlying.Canonical.Value.Replace("/", ""))).ToDictionary(); + } + + return symbols.Where(kvp => symbolsToProcess.Contains(kvp.Key.Underlying.Value)).ToDictionary(); + } + + /// + /// Adds a request for the mirror option symbol to the base list of requests. + /// + protected override HistoryRequest[] GetDerivativeHistoryRequests(Symbol symbol, DateTime start, DateTime end, MarketHoursDatabase.Entry marketHoursEntry) + { + var requests = base.GetDerivativeHistoryRequests(symbol, start, end, marketHoursEntry); + + var mirrorOptionSymbol = symbol.GetMirrorOptionSymbol(); + var mirrorOptionHistoryRequests = base.GetDerivativeHistoryRequests(mirrorOptionSymbol, start, end, marketHoursEntry); + + return requests.Concat(mirrorOptionHistoryRequests).ToArray(); + } + + /// + /// Generates and the derivative universe entries for the specified canonical symbol. + /// + protected override IEnumerable GenerateDerivativeEntries(Symbol canonicalSymbol, List symbols, + MarketHoursDatabase.Entry marketHoursEntry, List underlyingHistory, IDerivativeUniverseFileEntry underlyingEntry) + { + var generatedEntries = base.GenerateDerivativeEntries(canonicalSymbol, symbols, marketHoursEntry, underlyingHistory, underlyingEntry); + + if (!OptionUniverseEntry.HasGreeks(canonicalSymbol.SecurityType)) + { + return generatedEntries; + } + + var entries = new List(); + var entriesWithMissingIv = new List(); + // Enumerate the base entries to materialize them and check whether IVs are missing and need to be interpolated + foreach (OptionUniverseEntry entry in generatedEntries) + { + entries.Add(entry); + if (!entry.ImpliedVolatility.HasValue || entry.ImpliedVolatility == 0) + { + // We keep the entries with missing IVs to interpolate them later and avoid iterating through the whole list again + entriesWithMissingIv.Add(entry); + } + } + + if (entriesWithMissingIv.Count > 0) + { + // Interpolate missing IVs and re-generate greeks + ImpliedVolatilityInterpolator ivInterpolator = null; + try + { + ivInterpolator = ImpliedVolatilityInterpolator.Create(_processingDate, entries, + (underlyingEntry as OptionUniverseEntry).Close, entries.Count - entriesWithMissingIv.Count); + } + catch (Exception e) + { + Log.Error($"Failed to set up IV interpolator for {canonicalSymbol}. Error: {e.GetType()}: {e}"); + } + + if (ivInterpolator != null) + { + var failedInterpolationsCount = 0; + foreach (var entry in entriesWithMissingIv) + { + var interpolatedIv = 0m; + try + { + interpolatedIv = ivInterpolator.Interpolate(entry.Symbol.ID.StrikePrice, entry.Symbol.ID.Date); + } + catch + { + Log.Error($"Failed interpolating IV for {entry.Symbol.Value} :: Underlying price: {(underlyingEntry as OptionUniverseEntry).Close}"); + failedInterpolationsCount++; + } + + if (interpolatedIv != 0) + { + var updatedGreeks = ivInterpolator.GetUpdatedGreeksIndicators(entry.Symbol, interpolatedIv); + entry.SetGreeksIndicators(updatedGreeks); + } + } + + if (failedInterpolationsCount > 0) + { + Log.Error($"Failed interpolating IV for {failedInterpolationsCount} out of {entriesWithMissingIv.Count} contracts for {canonicalSymbol}."); + } + } + } + + return entries; + } + + private int _missingIvLogCount; + + /// + /// Overridden just for logging failed IV calculations in debug mode + /// protected override IDerivativeUniverseFileEntry GenerateDerivativeEntry(Symbol symbol, List history, List underlyingHistory) { var entry = base.GenerateDerivativeEntry(symbol, history, underlyingHistory); @@ -183,7 +183,7 @@ entry is OptionUniverseEntry optionEntry && { var underlyingPrice = underlyingHistory.LastOrDefault(x => x.Bars.ContainsKey(symbol.Underlying))?.Bars?.GetValue(symbol.Underlying); var optionPrice = history.LastOrDefault(x => x.QuoteBars.ContainsKey(symbol))?.QuoteBars?.GetValue(symbol); - var mirrorSymbol = OptionsUniverseGeneratorUtils.GetMirrorOptionSymbol(symbol); + var mirrorSymbol = symbol.GetMirrorOptionSymbol(); var mirrorPrice = history.LastOrDefault(x => x.QuoteBars.ContainsKey(mirrorSymbol))?.QuoteBars?.GetValue(mirrorSymbol); Log.Debug($"OptionsUniverseGenerator.GenerateDerivativeEntry(): IV is 0 for {symbol}.\n" + @@ -193,6 +193,6 @@ entry is OptionUniverseEntry optionEntry && } return entry; - } - } + } + } } \ No newline at end of file diff --git a/Lean.DataSource.OptionsUniverseGenerator/OptionsUniverseUtils.cs b/Lean.DataSource.OptionsUniverseGenerator/OptionsUniverseUtils.cs deleted file mode 100644 index 186c05f..0000000 --- a/Lean.DataSource.OptionsUniverseGenerator/OptionsUniverseUtils.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. -*/ - -namespace QuantConnect.DataSource.OptionsUniverseGenerator -{ - /// - /// Options Universe generator utils - /// - public static class OptionsUniverseGeneratorUtils - { - /// - /// Returns the mirror option symbol for the provided option symbol. - /// - public static Symbol GetMirrorOptionSymbol(Symbol symbol) - { - // This should not be called for non-option symbols, but let's be friendly/safe - if (!symbol.SecurityType.IsOption()) - { - return symbol; - } - - return Symbol.CreateOption(symbol.Underlying, - symbol.ID.Symbol, - symbol.ID.Market, - symbol.ID.OptionStyle, - symbol.ID.OptionRight == OptionRight.Call ? OptionRight.Put : OptionRight.Call, - symbol.ID.StrikePrice, - symbol.ID.Date); - } - } -} \ No newline at end of file diff --git a/QuantConnect.DataSource.DerivativeUniverseGeneratorTests/ImpliedVolatilityInterpolatorTests.cs b/QuantConnect.DataSource.DerivativeUniverseGeneratorTests/ImpliedVolatilityInterpolatorTests.cs index 7c657c8..3647c48 100644 --- a/QuantConnect.DataSource.DerivativeUniverseGeneratorTests/ImpliedVolatilityInterpolatorTests.cs +++ b/QuantConnect.DataSource.DerivativeUniverseGeneratorTests/ImpliedVolatilityInterpolatorTests.cs @@ -77,7 +77,7 @@ public void SetUp() foreach (var entry in _data) { - var mirrorSymbol = OptionsUniverseGeneratorUtils.GetMirrorOptionSymbol(entry.Symbol); + var mirrorSymbol = entry.Symbol.GetMirrorOptionSymbol(); var mirrorEntry = _data.SingleOrDefault(x => x.Symbol == mirrorSymbol); if (mirrorEntry == null || entry.Close == 0m || mirrorEntry.Close == 0m) continue; @@ -113,7 +113,7 @@ public void IvInterpolationAndGreeksGenerationTest() var greekIndicator = _interpolator.GetUpdatedGreeksIndicators(symbol, interpolatedIv, OptionPricingModelType.BlackScholes, OptionPricingModelType.BlackScholes); - var greeks = greekIndicator.GetGreeks(); + var greeks = greekIndicator.Greeks; Assert.NotZero(greeks.Delta); // Assert.NotZero(greeks.Gamma); // Gamma can be zero at very ITM options diff --git a/QuantConnect.DataSource.DerivativeUniverseGeneratorTests/OptionsUniverseGeneratorUtilsTests.cs b/QuantConnect.DataSource.DerivativeUniverseGeneratorTests/OptionsUniverseGeneratorUtilsTests.cs deleted file mode 100644 index 7092242..0000000 --- a/QuantConnect.DataSource.DerivativeUniverseGeneratorTests/OptionsUniverseGeneratorUtilsTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 NUnit.Framework; -using QuantConnect.DataSource.OptionsUniverseGenerator; -using QuantConnect.Interfaces; -using QuantConnect.Util; -using System; - -namespace QuantConnect.DataSource.DerivativeUniverseGeneratorTests -{ - [TestFixture] - public class OptionsUniverseGeneratorUtilsTests - { - private static TestCaseData[] MirrorOptionTestCases - { - get - { - var dataProvider = Composer.Instance.GetExportedValueByTypeName("DefaultDataProvider"); - - var mapFileProvider = Composer.Instance.GetExportedValueByTypeName("LocalDiskMapFileProvider"); - mapFileProvider.Initialize(dataProvider); - - var factorFileProvider = Composer.Instance.GetExportedValueByTypeName("LocalDiskFactorFileProvider"); - factorFileProvider.Initialize(mapFileProvider, dataProvider); - - var spy = Symbol.Create("SPY", SecurityType.Equity, Market.USA); - var spx = Symbol.Create("SPX", SecurityType.Index, Market.USA); - - var strike = 100m; - var expiry = new DateTime(2021, 1, 1); - - var spyCall = Symbol.CreateOption(spy, Market.USA, OptionStyle.American, OptionRight.Call, strike, expiry); - var spyPut = Symbol.CreateOption(spy, Market.USA, OptionStyle.American, OptionRight.Put, strike, expiry); - - var spxCall = Symbol.CreateOption(spx, Market.USA, OptionStyle.European, OptionRight.Call, strike, expiry); - var spxPut = Symbol.CreateOption(spx, Market.USA, OptionStyle.European, OptionRight.Put, strike, expiry); - - var spxwCall = Symbol.CreateOption(spx, "SPXW", Market.USA, OptionStyle.European, OptionRight.Call, strike, expiry); - var spxwPut = Symbol.CreateOption(spx, "SPXW", Market.USA, OptionStyle.European, OptionRight.Put, strike, expiry); - - return new[] - { - new TestCaseData(spyCall).Returns(spyPut), - new TestCaseData(spyPut).Returns(spyCall), - - new TestCaseData(spxCall).Returns(spxPut), - new TestCaseData(spxPut).Returns(spxCall), - - new TestCaseData(spxwCall).Returns(spxwPut), - new TestCaseData(spxwPut).Returns(spxwCall), - }; - } - } - - [TestCaseSource(nameof(MirrorOptionTestCases))] - public Symbol GetsCorrectMirrorOption(Symbol optionSymbol) - { - return OptionsUniverseGeneratorUtils.GetMirrorOptionSymbol(optionSymbol); - } - } -}