Files
quantconnect--lean/Tests/Common/Securities/SecurityIdentifierTests.cs
T
2026-07-13 13:02:50 +08:00

689 lines
26 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 System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using NUnit.Framework;
using QuantConnect.Algorithm.CSharp;
using QuantConnect.Lean.Engine.DataFeeds;
using QuantConnect.Logging;
using QuantConnect.Util;
using QuantConnect.Securities;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.Custom.AlphaStreams;
using QuantConnect.Data.Custom.IconicTypes;
using QuantConnect.Data.Custom.Intrinio;
using QuantConnect.Data.Custom;
using QuantConnect.Data.Custom.Tiingo;
namespace QuantConnect.Tests.Common.Securities
{
[TestFixture]
public class SecurityIdentifierTests
{
private static SecurityIdentifier SPY
{
get { return SecurityIdentifier.GenerateEquity(new DateTime(1998, 01, 02), "SPY", Market.USA); }
}
// this is really not european style, but I'd prefer to test a value of 1 vs a value of 0
private readonly SecurityIdentifier SPY_Put_19550 = SecurityIdentifier.GenerateOption(new DateTime(2015, 09, 18), SPY, Market.USA, 195.50m, OptionRight.Put, OptionStyle.European);
// this is euro-dollar futures contract (for tests)
private readonly SecurityIdentifier ED_Dec_2020 = SecurityIdentifier.GenerateFuture(new DateTime(2020, 12, 15), "ED", Market.USA);
[TestCase("SPY", "SPY", "20230403")]
[TestCase("GOOG", "GOOG", "20140403")]
[TestCase("GOOG", "GOOCV", "20140402")]
public void Ticker(string symbol, string expectedTicker, string date)
{
var equity = Symbol.Create(symbol, SecurityType.Equity, Market.USA);
var ticker = SecurityIdentifier.Ticker(equity, Time.ParseDate(date));
Assert.AreEqual(expectedTicker, ticker);
}
[Test]
public void GenerateEquityProperlyResolvesFirstDate()
{
var spy = SecurityIdentifier.GenerateEquity("SPY", Market.USA);
Assert.AreEqual(new DateTime(1998, 01, 02), spy.Date);
}
[Test]
public void GenerateFailsOnInvalidDate()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
SecurityIdentifier.GenerateEquity(Time.BeginningOfTime.AddDays(-1), "SPY", Market.USA));
}
[Test]
public void GeneratesIdentifiersDeterministically()
{
var sid1 = SPY;
var sid2 = SPY;
Assert.AreEqual(sid1, sid2);
Log.Trace(sid1.ToString());
}
[Test]
public void GeneratesOptionSecurityIdentifier()
{
var spyPut = SPY_Put_19550;
// verify various values
Assert.AreEqual(OptionRight.Put, spyPut.OptionRight); // put
Assert.AreEqual(new DateTime(2015, 09, 18), spyPut.Date); // oa date 2015.09.18
Assert.AreEqual(OptionStyle.European, spyPut.OptionStyle); // option style
Assert.AreEqual(195.5m, spyPut.StrikePrice); // strike/scale
Assert.AreEqual(Market.USA, spyPut.Market); // market
Assert.AreEqual(SecurityType.Option, spyPut.SecurityType); // security type
Assert.AreEqual("SPY", spyPut.Symbol); // SPY in base36
Assert.IsTrue(spyPut.HasUnderlying);
Assert.AreEqual(SPY, spyPut.Underlying);
Log.Trace(SPY_Put_19550.ToString());
}
[Test]
public void GeneratesEquitySecurityIdentifier()
{
var sid1 = SecurityIdentifier.GenerateEquity(new DateTime(1998, 01, 02), "SPY", Market.USA);
// verify various values
Assert.AreEqual(new DateTime(1998, 01, 02), sid1.Date);
Assert.AreEqual(Market.USA, sid1.Market);
Assert.AreEqual(SecurityType.Equity, sid1.SecurityType);
Assert.AreEqual("SPY", sid1.Symbol);
Log.Trace(sid1.ToString());
}
[Test]
public void GeneratesForexSecurityIdentifier()
{
var eurusd = SecurityIdentifier.GenerateForex("EURUSD", Market.FXCM);
// verify various values
Assert.Throws<InvalidOperationException>(() => { var x = eurusd.Date; });
Assert.AreEqual(Market.FXCM, eurusd.Market);
Assert.AreEqual(SecurityType.Forex, eurusd.SecurityType);
Assert.AreEqual("EURUSD", eurusd.Symbol);
Log.Trace(eurusd.ToString());
}
[Test]
public void FuturesSecurityIdReturnsProperties()
{
// verify various values
Assert.AreEqual(new DateTime(2020, 12, 15), ED_Dec_2020.Date);
Assert.AreEqual(Market.USA, ED_Dec_2020.Market);
Assert.AreEqual(SecurityType.Future, ED_Dec_2020.SecurityType);
Assert.AreEqual("ED", ED_Dec_2020.Symbol);
Log.Trace(ED_Dec_2020.ToString());
}
[Test]
public void Generates12Character()
{
var sid1 = SecurityIdentifier.GenerateBase(null, "123456789012", Market.USA);
Assert.AreEqual("123456789012", sid1.Symbol);
Log.Trace(sid1.ToString());
}
[Test]
public void ParsedToStringEqualsValue()
{
var value = SPY_Put_19550.ToString();
Log.Trace(value);
var sid2 = SecurityIdentifier.Parse(value);
Assert.AreEqual(SPY_Put_19550, sid2);
}
[Test]
public void ToStringPipeDelimitsUnderlying()
{
var actual = SPY_Put_19550.ToString();
var parts = actual.Split('|');
var option = SecurityIdentifier.Parse(parts[0]);
// verify various values
Assert.AreEqual(OptionRight.Put, option.OptionRight); // put
Assert.AreEqual(new DateTime(2015, 09, 18), option.Date); // oa date 2015.09.18
Assert.AreEqual(OptionStyle.European, option.OptionStyle); // option style
Assert.AreEqual(195.5m, option.StrikePrice); // strike/scale
Assert.AreEqual(Market.USA, option.Market); // market
Assert.AreEqual(SecurityType.Option, option.SecurityType); // security type
Assert.AreEqual("SPY", option.Symbol); // SPY in base36
Assert.IsFalse(option.HasUnderlying);
Assert.Throws<InvalidOperationException>(() => { var x = option.Underlying; });
var equity = SecurityIdentifier.Parse(parts[1]);
Assert.AreEqual(SPY, equity);
}
[Test]
public void ReturnsCorrectMarket()
{
Assert.AreEqual(Market.USA, SPY.Market);
}
[Test]
public void ReturnsCorrectMarketWhenNotFound()
{
var sid = new SecurityIdentifier("some-symbol", 0357960000000009901);
Assert.AreEqual("99", sid.Market);
}
[Test]
public void InvalidSecurityType()
{
Assert.Throws<ArgumentException>(() =>
{
var sid = new SecurityIdentifier("some-symbol", 0357960000000009915);
}, $"The provided properties do not match with a valid {nameof(SecurityType)}");
}
[TestCaseSource(nameof(ValidSecurityTypes))]
public void ValidSecurityType(ulong properties)
{
Assert.DoesNotThrow(() =>
{
var sid = new SecurityIdentifier("some-symbol", properties);
});
}
[Test]
public void ReturnsCorrectOptionRight()
{
Assert.AreEqual(OptionRight.Put, SPY_Put_19550.OptionRight);
}
[Test]
public void OptionRightThrowsOnNonOptionSecurityType()
{
Assert.Throws<InvalidOperationException>(() =>
{
var OptionRight = SPY.OptionRight;
}, "OptionRight is only defined for SecurityType.Option");
}
[Test]
public void ReturnsCorrectSecurityType()
{
Assert.AreEqual(SecurityType.Equity, SPY.SecurityType);
Assert.AreEqual(SecurityType.Option, SPY_Put_19550.SecurityType);
}
[Test]
public void ReturnsCorrectSymbol()
{
Assert.AreEqual("SPY", SPY.Symbol);
}
[Test]
public void ReturnsCorrectStrikePrice()
{
Assert.AreEqual(195.50m, SPY_Put_19550.StrikePrice);
}
[Test]
public void ReturnsCorrectDate()
{
Assert.AreEqual(new DateTime(1998, 01, 02), SPY.Date);
Assert.AreEqual(new DateTime(2015, 09, 18), SPY_Put_19550.Date);
}
[Test]
public void ReturnsCorrectOptionStyle()
{
Assert.AreEqual(OptionStyle.European, SPY_Put_19550.OptionStyle);
}
[Test]
public void OptionStyleThrowsOnNonOptionSecurityType()
{
Assert.Throws<InvalidOperationException>(() =>
{
var optionStyle = SPY.OptionStyle;
}, "OptionStyle is only defined for SecurityType.Option");
}
[Test]
public void EmptyUsesEmptySymbol()
{
Assert.AreEqual(string.Empty, SecurityIdentifier.Empty.Symbol);
}
[Test]
public void PreviousEmptyFormatStillSupported()
{
Assert.AreEqual(SecurityIdentifier.Empty, SecurityIdentifier.Parse(" "));
}
[Test]
public void RoundTripEmptyParse()
{
Assert.AreEqual(SecurityIdentifier.Empty, SecurityIdentifier.Parse(SecurityIdentifier.Empty.ToString()));
}
[Test]
public void RoundTripNoneParse()
{
Assert.AreEqual(SecurityIdentifier.None, SecurityIdentifier.Parse(SecurityIdentifier.None.ToString()));
}
[Test]
public void UsedAsDictionaryKey()
{
var hash = new HashSet<SecurityIdentifier>();
Assert.IsTrue(hash.Add(SPY));
Assert.IsFalse(hash.Add(SPY));
}
[Test]
public void SerializesToSimpleString()
{
var sid = SPY;
var str = sid.ToString();
var serialized = JsonConvert.SerializeObject(sid);
Assert.AreEqual("\"" + str + "\"", serialized);
}
[Test]
public void DeserializesFromSimpleString()
{
var sid = SPY;
var str = "\"" + sid + "\"";
var deserialized = JsonConvert.DeserializeObject<SecurityIdentifier>(str);
Assert.AreEqual(sid, deserialized);
}
[Test]
public void DeserializesFromSimpleStringWithinContainerClass()
{
var sid = new Container{sid =SPY};
var str =
@"
{
'sid': '" + SPY + @"'
}";
var deserialized = JsonConvert.DeserializeObject<Container>(str);
Assert.AreEqual(sid.sid, deserialized.sid);
}
[Test]
public void ParsesFromStringCorrectly()
{
const string value = "SPY R735QTJ8XC9X";
SecurityIdentifier sid;
Assert.IsTrue(SecurityIdentifier.TryParse(value, out sid));
Assert.AreEqual(sid.ToString(), value);
}
[TestCase("SPY WhatEver")]
[TestCase("Sharpe ratio")]
public void TryParseFailsInvalidProperties(string value)
{
Assert.IsFalse(SecurityIdentifier.TryParse(value, out var _));
// On the second call, we test the cache to increase speed and remove redundant logging
Assert.IsFalse(SecurityIdentifier.TryParse(value, out var _));
}
[Test, Category("TravisExclude")]
public void ParsesFromStringFastEnough()
{
const string value = "SPY R735QTJ8XC9X";
var stopwatch = Stopwatch.StartNew();
for (var i = 0; i < 1000000; i++)
{
SecurityIdentifier sid;
SecurityIdentifier.TryParse(value, out sid);
}
stopwatch.Stop();
Log.Trace("Elapsed: " + stopwatch.Elapsed);
Assert.Less(stopwatch.Elapsed, TimeSpan.FromSeconds(2));
}
[Test]
public void SupportsSpecialCharactersInSymbol()
{
const string symbol = "~!@#$%^&*()_+¼»`ÆÜCⁿª▓G";
var sid = new SecurityIdentifier(symbol, 0);
Assert.AreEqual(sid.Symbol, symbol);
}
[Theory, TestCase("|"), TestCase(" ")]
public void ThrowsOnInvalidSymbolCharacters(string input)
{
Assert.Throws<ArgumentException>(() =>
{
new SecurityIdentifier(input, 0);
}, "must not contain the characters");
}
[Test]
public void GenerateEquityWithTickerUsingMapFile()
{
var expectedFirstDate = new DateTime(1998, 1, 2);
var sid = SecurityIdentifier.GenerateEquity("TWX", Market.USA, mapSymbol: true, mapFileProvider: TestGlobals.MapFileProvider);
Assert.AreEqual(sid.Date, expectedFirstDate);
Assert.AreEqual(sid.Symbol, "AOL");
}
[Test]
public void GenerateBaseDataWithTickerUsingMapFile()
{
var expectedFirstDate = new DateTime(1998, 1, 2);
var sid = SecurityIdentifier.GenerateBase(null, "TWX", Market.USA, mapSymbol: true);
Assert.AreEqual(sid.Date, expectedFirstDate);
Assert.AreEqual(sid.Symbol, "AOL");
}
[Test]
public void GenerateBase_SymbolAppendsDptTypeName_WhenBaseDataTypeIsNotNull()
{
var symbol = "BTC";
var expected = "BTC.Bitcoin";
var baseDataType = typeof(LiveTradingFeaturesAlgorithm.Bitcoin);
var sid = SecurityIdentifier.GenerateBase(baseDataType, symbol, Market.USA);
Assert.AreEqual(expected, sid.Symbol);
}
[Test]
public void GenerateBase_UsesProvidedSymbol_WhenBaseDataTypeIsNull()
{
var symbol = "BTC";
var expected = "BTC";
var baseDataType = (Type) null;
var sid = SecurityIdentifier.GenerateBase(baseDataType, symbol, Market.USA);
Assert.AreEqual(expected, sid.Symbol);
}
[Test]
public void DecimalStrikePriceRoundTrip()
{
var future = Symbol.CreateFuture(
"CL",
Market.NYMEX,
new DateTime(2020, 5, 20));
var option = Symbol.CreateOption(
future,
Market.NYMEX,
OptionStyle.American,
OptionRight.Call,
0.006425m,
new DateTime(2020, 4, 16));
Assert.AreEqual(0.006425m, option.ID.StrikePrice);
var newSid = SecurityIdentifier.Parse(option.ID.ToString());
Assert.AreEqual(0.006425m, newSid.StrikePrice);
var option2 = Symbol.CreateOption(
future,
Market.NYMEX,
OptionStyle.American,
OptionRight.Call,
0.0064m,
new DateTime(2020, 4, 16));
Assert.AreNotEqual(option2, option);
}
[Test]
public void NegativeStrikePriceRoundTrip()
{
var future = Symbol.CreateFuture(
"CL",
Market.NYMEX,
new DateTime(2020, 5, 20));
var option = Symbol.CreateOption(
future,
Market.NYMEX,
OptionStyle.American,
OptionRight.Call,
-50,
new DateTime(2020, 4, 16));
Assert.AreEqual(-50, option.ID.StrikePrice);
// Forces the reconstruction of the strike price to ensure that it's been properly parsed.
var newSid = SecurityIdentifier.Parse(option.ID.ToString());
Assert.AreEqual(-50, newSid.StrikePrice);
}
[TestCase(OptionStyle.American, OptionRight.Call, "AAPL XEOLB4YAUINA|AAPL R735QTJ8XC9X")]
[TestCase(OptionStyle.American, OptionRight.Put, "AAPL 31DSLGKXI4C12|AAPL R735QTJ8XC9X")]
[TestCase(OptionStyle.European, OptionRight.Call, "AAPL XEOOUQW0NLD2|AAPL R735QTJ8XC9X")]
[TestCase(OptionStyle.European, OptionRight.Put, "AAPL 31DSP06V7XEQU|AAPL R735QTJ8XC9X")]
public void SymbolHashForOptionsBackwardsCompatibilityWholeNumber(OptionStyle style, OptionRight right, string expected)
{
var equity = Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
var option = Symbol.CreateOption(
equity,
Market.USA,
style,
right,
100m,
new DateTime(2020, 5, 21));
Assert.AreEqual(expected, option.ID.ToString());
Assert.AreEqual(100m, option.ID.StrikePrice);
}
[TestCase(OptionStyle.American, OptionRight.Call, "AAPL XEOLB4YALY06|AAPL R735QTJ8XC9X")]
[TestCase(OptionStyle.American, OptionRight.Put, "AAPL 31DSLGKXHVRDY|AAPL R735QTJ8XC9X")]
[TestCase(OptionStyle.European, OptionRight.Call, "AAPL XEOOUQW0F0PY|AAPL R735QTJ8XC9X")]
[TestCase(OptionStyle.European, OptionRight.Put, "AAPL 31DSP06V7OU3Q|AAPL R735QTJ8XC9X")]
public void SymbolHashForOptionsBackwardsCompatibilityFractionalNumber(OptionStyle style, OptionRight right, string expected)
{
var equity = Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
var option = Symbol.CreateOption(
equity,
Market.USA,
style,
right,
0.01m, // strike decimal precision is limited to 4 decimal places only
new DateTime(2020, 5, 21));
Assert.AreEqual(expected, option.ID.ToString());
Assert.AreEqual(0.01m, option.ID.StrikePrice);
}
[Test]
public void SymbolHashForOptionsBackwardsCompatibilityLargeFractionalNumberDoesNotThrow()
{
Assert.DoesNotThrow(() =>
{
var equity = Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
var option = Symbol.CreateOption(
equity,
Market.USA,
OptionStyle.American,
OptionRight.Call,
3600.75m, // strike decimal precision is limited to 4 decimal places only
new DateTime(2020, 5, 21));
});
}
[TestCase("-475711")]
[TestCase("475711")]
[TestCase("47.5711")]
[TestCase("-47.5711")]
public void NumberStrikePriceApproachesBoundsWithoutOverflowingSid(string strikeStr)
{
var strike = decimal.Parse(strikeStr, CultureInfo.InvariantCulture);
var equity = Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
var option = Symbol.CreateOption(
equity,
Market.USA,
OptionStyle.American,
OptionRight.Call,
strike,
new DateTime(2020, 5, 21));
// The SID specification states that the total width for the properties value
// is at most 20 digits long. If we overflowed the SID, the strike price can and will
// eat from other slots, corrupting the data. If we have no overflow, the SID will
// be constructed properly without corrupting any data, even as we approach the bounds.
// We will assert that all properties contained within the _properties field are valid and not corrupted
var sid = SecurityIdentifier.Parse(option.ID.ToString());
Assert.AreEqual(new DateTime(2020, 5, 21), sid.Date);
Assert.AreEqual(strike, sid.StrikePrice);
Assert.AreEqual(OptionRight.Call, sid.OptionRight);
Assert.AreEqual(OptionStyle.American, sid.OptionStyle);
Assert.AreEqual(Market.USA, sid.Market);
Assert.AreEqual(SecurityType.Option, sid.SecurityType);
Assert.AreEqual(option.ID.Date,sid.Date);
Assert.AreEqual(option.ID.StrikePrice, sid.StrikePrice);
Assert.AreEqual(option.ID.OptionRight, sid.OptionRight);
Assert.AreEqual(option.ID.OptionStyle, sid.OptionStyle);
Assert.AreEqual(option.ID.Market, sid.Market);
Assert.AreEqual(option.ID.SecurityType, sid.SecurityType);
}
[TestCase(475712.0)]
[TestCase(47.5712)]
[TestCase(999999.0)]
[TestCase(-475712.0)]
[TestCase(-47.5712)]
[TestCase(-999999)]
public void HighPrecisionNumberThrows(double strike)
{
var equity = Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
Assert.Throws<ArgumentException>(() =>
{
Symbol.CreateOption(
equity,
Market.USA,
OptionStyle.American,
OptionRight.Call,
(decimal)strike, // strike decimal precision is limited to 4 decimal places only
new DateTime(2020, 5, 21));
});
}
[Test, Ignore("Requires complete option data to validate chain")]
public void ValidateAAPLOptionChainSecurityIdentifiers()
{
var chainProvider = new BacktestingOptionChainProvider();
chainProvider.Initialize(new(TestGlobals.MapFileProvider, TestGlobals.HistoryProvider));
var aapl = Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
var chains = new HashSet<Symbol>();
var expectedChains = File.ReadAllLines("TestData/aapl_chain.csv")
.Where(x => !string.IsNullOrWhiteSpace(x))
.ToDictionary(x => x, _ => false);
Assert.AreNotEqual(0, expectedChains.Count);
var start = new DateTime(2020, 1, 1);
var end = new DateTime(2020, 7, 1);
foreach (var date in Time.EachDay(start, end))
{
if (MarketHoursDatabase.FromDataFolder()
.GetEntry(Market.USA, (string)null, SecurityType.Equity)
.ExchangeHours
.Holidays.Contains(date) || date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday)
{
continue;
}
foreach (var symbol in chainProvider.GetOptionContractList(aapl, date))
{
chains.Add(symbol);
}
}
var fails = new HashSet<Symbol>();
foreach (var chain in chains)
{
if (expectedChains.ContainsKey(chain.ID.ToString()))
{
expectedChains[chain.ID.ToString()] = true;
continue;
}
fails.Add(chain);
}
Assert.AreEqual(0, fails.Count, $"The following option Symbols were not found in the expected chain: \n{string.Join("\n", fails.Select(x => x.ID.ToString()))}");
Assert.IsTrue(expectedChains.All(kvp => kvp.Value), $"The following option Symbols were not loaded: \n{string.Join("\n", expectedChains.Where(kvp => !kvp.Value).Select(x => x.Key))}");
}
[Test]
public void SortsAccordingToStringRepresentation()
{
var sids = Symbols.All.ToList(s => s.ID);
var expected = sids
.Select(sid => new {symbol = sid, str = sid.ToString()})
.OrderBy(item => item.str)
.ToList(item => item.symbol);
sids.Sort();
CollectionAssert.AreEqual(expected, sids);
}
[TestCaseSource(nameof(ReturnsExpectedCustomDataTypeTestCases))]
public void ReturnsExpectedCustomDataType(string symbol, Type expectedDataType)
{
SecurityIdentifier.GenerateBaseSymbol(expectedDataType, symbol.Split(".")[0]);
var result = SecurityIdentifier.TryGetCustomDataTypeInstance(symbol, out var obtainedDataType);
Assert.AreEqual(expectedDataType, obtainedDataType);
}
public static object[] ReturnsExpectedCustomDataTypeTestCases =
{
new object[] {"BTC.Bitcoin", typeof(CustomDataBitcoinAlgorithm.Bitcoin)},
new object[] {"AAPL.FundamentalUniverse", typeof(FundamentalUniverse)},
new object[] {"AAPL.PlaceHolder", typeof(PlaceHolder)},
new object[] {"AAPL.LinkedData", typeof(LinkedData)},
new object[] {"AAPL.UnlinkedData", typeof(UnlinkedData)},
new object[] {"AAPL.UnlinkedDataTradeBar", typeof(UnlinkedDataTradeBar)},
new object[] {"AAPL.IndexedLinkedData", typeof(IndexedLinkedData)},
new object[] {"AAPL.IndexedLinkedData2", typeof(IndexedLinkedData2)},
new object[] {"AAPL.IntrinioEconomicDataSources", typeof(IntrinioEconomicDataSources)},
new object[] {"AAPL.IntrinioEconomicData", typeof(IntrinioEconomicData)},
new object[] {"AAPL.FxcmVolume", typeof(FxcmVolume)},
new object[] {"AAPL.Tiingo", typeof(Tiingo)},
new object[] {"AAPL.TiingoDailyData", typeof(TiingoDailyData)},
new object[] {"AAPL.TiingoPrice", typeof(TiingoPrice)},
};
class Container
{
public SecurityIdentifier sid;
}
private static List<TestCaseData> ValidSecurityTypes =>
(from object value in Enum.GetValues(typeof(SecurityType)) select new TestCaseData((ulong)(0357960000000009900 + (int)value))).ToList();
}
}