Unsupported SecurityType 'Option' for symbol '?SPY'
@Romazes 已经在做这个了。
开始于 2025年3月4日。
评估
这个 Issue 还没有评估数据。
描述
Problem Description
This is likely an issue caused by file-based universe selection, which has been mentioned here: https://github.com/QuantConnect/Lean.DataSource.Polygon/issues/19
Option universe is now file based after https://github.com/QuantConnect/Lean/pull/8212
Add a logging statement to the line in this plugin, it will tell that:
20250222 21:42:29.014 TRACE:: ThetaDataProvider.GetHistory: [DEBUG] ?SPY - Daily - Quote - 2/21/2025 5:00:00 AM - 2/22/2025 9:42:29 PM
20250222 21:42:29.014 TRACE:: ThetaDataProvider.GetHistory: Unsupported SecurityType 'Option' for symbol '?SPY'
which was yield by the following block:
// QuantConnect.ThetaData/ThetaDataHistoryProvider.cs
...
Log.Trace($"{nameof(ThetaDataProvider)}.{nameof(GetHistory)}: [DEBUG] {historyRequest.Symbol} - {historyRequest.Resolution} - {historyRequest.TickType} - {startDateTimeUtc} - {historyRequest.EndTimeUtc}");
if (!CanSubscribe(historyRequest.Symbol))
{
if (!_invalidSecurityTypeWarningFired)
{
_invalidSecurityTypeWarningFired = true;
Log.Trace($"{nameof(ThetaDataProvider)}.{nameof(GetHistory)}: Unsupported SecurityType '{historyRequest.Symbol.SecurityType}' for symbol '{historyRequest.Symbol}'");
}
return null;
}
It is clear that it tries to pass ?SPY into the GetHistory method, however, GetHistory is intended for fetching data for individual contracts, and not for fetching the entire option chain, thus causing this issue. And if it didn't directly return null inside from this if-block, the code will then subsequently invoke the GetHistoricalQuoteData methed (issue #11 is trying to resolve how GetHistoricalQuoteData behaves when there's no valid quote bar for construction, but that would not resolve this issue, since this if-block will directly return null when we pass in a ?SPY instead of the individual contract symbols).
From my observation and experiment, in live trading, this GetHistory method was invoked by OptionChain method defined in Lean/Algorithm/QCAlgorithm.cs:
// Lean/Algorithm/QCAlgorithm.cs
...
public OptionChains OptionChains(IEnumerable<Symbol> symbols, bool flatten = false) {
...
var optionChainsData = History(optionCanonicalSymbols, 1).GetUniverseData()
.Select(x => (x.Keys.Single(), x.Values.Single().Cast<OptionUniverse>()));
...
}
namely the file-based universe selection process, which was introduced starting here: https://github.com/QuantConnect/Lean/commit/16c425934218954082d97b1e2ea03228cddf4783 .
However, even then, it still tries to get the universe content via a network request, instead of retrieving directly from the universe csv file on that day, which should be the correct way if we are using Lean CLI to do live trading.
Expected Behavior
As long as we have built the Universe according to the sample universe format given by https://github.com/QuantConnect/Lean/blob/master/Data/option/usa/universes/spy/20240109.csv , we should be able to avoid network request for fetching the option chain from the data provider.
Currently it is doing extra work here (the local universe has been located and loaded before this redundant request), and it is doing it incorrectly.
Additionally, even if it is going to fetch the most recent market price for all the contracts, individual requests over 10k contracts are not acceptable (SetFilter right now is not working as expected in my experiment with ThetaData, I will investigate and open an issue for Lean main repository if it is involved), currently this plugin hasn't utilized bulk request to get whole universe data.
However, this is not an urgent issue. Won't affect the behavior in live trading.
Some code snippets that might be helpful for debugging
Code:
// Lean/Algorithm/QCAlgorithm.cs
...
[DocumentationAttribute(AddingData)]
public OptionChains OptionChains(IEnumerable<Symbol> symbols, bool flatten = false)
{
Log($"OptionChains: received {symbols.Count()} symbols: {string.Join(", ", symbols.Select(x => x.Value))}");
var canonicalSymbols = symbols.Select(GetCanonicalOptionSymbol).ToList();
var optionCanonicalSymbols = canonicalSymbols.Where(x => x.SecurityType != SecurityType.FutureOption);
var futureOptionCanonicalSymbols = canonicalSymbols.Where(x => x.SecurityType == SecurityType.FutureOption);
// var optionChainsData = History(optionCanonicalSymbols, 1).GetUniverseData()
// .Select(x => (x.Keys.Single(), x.Values.Single().Cast<OptionUniverse>()));
// TODO: why do we need to make a historical request here, especially this will yield a Daily resolution request on the quote data
// I cannot see the point for options here. For options, we only cares about the contracts list, all data should be from OnData method
Log($"OptionChains: requesting history for Resolution={GetResolution(optionCanonicalSymbols.First(), null, typeof(QuoteBar))}");
var historyData = History(optionCanonicalSymbols, 1);
Log($"HistoryData type: {historyData.GetType().FullName}");
Log($"History retrieved for canonical symbols: {string.Join(", ", optionCanonicalSymbols.Select(x => x.Value))}");
Log($"History length: {historyData.Count()}");
var universeData = historyData.GetUniverseData();
Log($"UniverseData type: {universeData.GetType().FullName}");
Log("Extracted universe data from history.");
foreach (var entry in universeData)
{
var key = entry.Keys.FirstOrDefault();
var values = entry.Values.FirstOrDefault();
if (key != null)
{
var valueTypes = values != null
? string.Join(", ", values.Select(v => v.GetType().Name).Distinct())
: "no values";
int count = values?.Count() ?? 0;
Log($"UniverseData entry - Key: {key}, Count: {count}, Value Types: {valueTypes}");
var firstFew = values.Take(5);
foreach (var item in firstFew)
{
Log($" ItemType: {item.GetType().Name}, Item: {item}");
}
}
else
{
Log("UniverseData entry with no key.");
}
}
var optionChainsData = universeData.Select(dataEntry =>
{
var canonicalOptionSymbol = dataEntry.Keys.Single();
var optionUniverseCollection = dataEntry.Values.Single().Cast<OptionUniverse>();
Log($"Processing universe data for canonical symbol: {canonicalOptionSymbol}");
Log($"Option universe collection size: {optionUniverseCollection.Count()}");
return (canonicalOptionSymbol, optionUniverseCollection);
});
// TODO: For FOPs, we fall back to the option chain provider until OptionUniverse supports them
var futureOptionChainsData = futureOptionCanonicalSymbols.Select(symbol =>
{
var optionChainData = OptionChainProvider.GetOptionContractList(symbol, Time)
.Select(contractSymbol => new OptionUniverse()
{
Symbol = contractSymbol,
EndTime = Time.Date,
});
return (symbol, optionChainData);
});
var time = Time.Date;
var chains = new OptionChains(time, flatten);
foreach (var (symbol, contracts) in optionChainsData.Concat(futureOptionChainsData))
{
var symbolProperties = SymbolPropertiesDatabase.GetSymbolProperties(symbol.ID.Market, symbol, symbol.SecurityType, AccountCurrency);
if (symbolProperties != null)
{
Log("SymbolProperties type: " + symbolProperties.GetType().FullName);
Log("SymbolProperties content: " + symbolProperties);
}
var optionChain = new OptionChain(symbol, time, contracts, symbolProperties, flatten);
chains.Add(symbol, optionChain);
}
return chains;
}
Output:
20250222 21:42:30.199 TRACE:: Log: OptionChains: received 1 symbols: ?SPY
20250222 21:42:30.199 TRACE:: Log: OptionChains: requesting history for Resolution=Daily
20250222 21:42:30.199 TRACE:: Log: HistoryData type: QuantConnect.Util.MemoizingEnumerable`1[[QuantConnect.Data.Slice, QuantConnect.Common, Version=2.5.0.0, Culture=neutral, PublicKeyToken=null]]
20250222 21:42:30.199 TRACE:: Log: History retrieved for canonical symbols: ?SPY
20250222 21:42:30.199 TRACE:: Log: History length: 1
20250222 21:42:30.199 TRACE:: Log: UniverseData type: System.Linq.Enumerable+IteratorSelectIterator`2[[QuantConnect.Data.BaseData, QuantConnect.Common, Version=2.5.0.0, Culture=neutral,
PublicKeyToken=null],[QuantConnect.Data.Market.DataDictionary`1[[QuantConnect.Data.UniverseSelection.BaseDataCollection, QuantConnect.Common, Version=2.5.0.0, Culture=neutral, PublicKeyToken=null]], QuantConnect.Common,
Version=2.5.0.0, Culture=neutral, PublicKeyToken=null]]
20250222 21:42:30.199 TRACE:: Log: Extracted universe data from history.
20250222 21:42:30.199 TRACE:: Log: UniverseData entry - Key: ?SPY, Count: 9542, Value Types: OptionUniverse
20250222 21:42:30.199 TRACE:: Log: ItemType: OptionUniverse, Item: SPY 33HG3ZAVVP5YE|SPY R735QTJ8XC9X: ¤0.00
20250222 21:42:30.199 TRACE:: Log: ItemType: OptionUniverse, Item: SPY 32SK364QUWYUE|SPY R735QTJ8XC9X: ¤0.00
20250222 21:42:30.199 TRACE:: Log: ItemType: OptionUniverse, Item: SPY 3300W7N23EWW6|SPY R735QTJ8XC9X: ¤0.00
20250222 21:42:30.199 TRACE:: Log: ItemType: OptionUniverse, Item: SPY YUKGCKEM9KO6|SPY R735QTJ8XC9X: ¤0.00
20250222 21:42:30.199 TRACE:: Log: ItemType: OptionUniverse, Item: SPY YU7NJA4SQMUE|SPY R735QTJ8XC9X: ¤0.00
20250222 21:42:30.199 TRACE:: Log: Processing universe data for canonical symbol: ?SPY
20250222 21:42:30.199 TRACE:: Log: Option universe collection size: 9542
20250222 21:42:30.199 TRACE:: Log: SymbolProperties type: QuantConnect.Securities.SymbolProperties
20250222 21:42:30.199 TRACE:: Log: SymbolProperties content: ,USD,100,0.01,1,,,
- 主要语言
- C#
- 星标
- 24
- 派生
- 16
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
我们还没有检查这个项目的环境配置文件。先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
QuantConnect/Lean.DataSource.ThetaData 的其他 Issue
-
History Request: Option: missed empty bars可能重新可做 @Romazes 于 584 天前认领,目前没有进行中的 PR。 未关闭bug
QuantConnect/Lean.DataSource.ThetaData#11 · 已指派 1 人 ·
-
Empty Option Contracts Returned if Invoked inside the Lean Environment (both Backtest and Research)可能重新可做 @Romazes 于 588 天前认领,目前没有进行中的 PR。 未关闭
QuantConnect/Lean.DataSource.ThetaData#9 · 4 条评论 · 已指派 1 人 ·
查看 QuantConnect/Lean.DataSource.ThetaData 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 62/100
builtbybel/CrapFixer#112 ·
-
area-ai untriaged
难度 2/5 1-3 小时 新手友好度 85/100
dotnet/extensions#7790 ·
维护者通常 1 天内回复
-
Beginner Friendly T: Bugfix
难度 2/5 1-3 小时 新手友好度 82/100
space-wizards/space-station-14#46220 ·
维护者通常 1 天内回复
-
P2 testing
难度 1/5 1 小时以内 新手友好度 90/100
维护者通常 1 天内回复
-
area-Infrastructure-coreclr os-ios os-maccatalyst os-tvos untriaged
难度 2/5 1-3 小时 新手友好度 78/100
dotnet/runtime#134766 · 3 条评论 ·
维护者通常 1 天内回复