From 6990dc3b930f55cbbb214f385570cc395f4cbed2 Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Tue, 12 May 2026 23:15:20 -0500 Subject: [PATCH] Add CBOE index entries to MHDB and SPDB --- Data/market-hours/market-hours-database.json | 392 ++++++++++++++++++ .../symbol-properties-database.csv | 2 + .../Securities/MarketHoursDatabaseTests.cs | 21 + .../SymbolPropertiesDatabaseTests.cs | 16 + 4 files changed, 431 insertions(+) diff --git a/Data/market-hours/market-hours-database.json b/Data/market-hours/market-hours-database.json index 507913acf45a..2698775da08b 100644 --- a/Data/market-hours/market-hours-database.json +++ b/Data/market-hours/market-hours-database.json @@ -98160,6 +98160,398 @@ "12/24/2026": "12:00:00" } }, + "Index-cboe-[*]": { + "dataTimeZone": "America/New_York", + "exchangeTimeZone": "America/Chicago", + "sunday": [], + "monday": [ + { + "start": "08:30:00", + "end": "15:15:00", + "state": "market" + } + ], + "tuesday": [ + { + "start": "08:30:00", + "end": "15:15:00", + "state": "market" + } + ], + "wednesday": [ + { + "start": "08:30:00", + "end": "15:15:00", + "state": "market" + } + ], + "thursday": [ + { + "start": "08:30:00", + "end": "15:15:00", + "state": "market" + } + ], + "friday": [ + { + "start": "08:30:00", + "end": "15:15:00", + "state": "market" + } + ], + "saturday": [], + "holidays": [ + "1/1/1998", + "1/1/1999", + "1/1/2001", + "1/1/2002", + "1/1/2003", + "1/1/2004", + "1/2/2006", + "1/1/2007", + "1/1/2008", + "1/1/2009", + "1/1/2010", + "1/1/2011", + "1/2/2012", + "1/1/2013", + "1/1/2014", + "1/1/2015", + "1/1/2016", + "1/2/2017", + "1/1/2018", + "1/1/2019", + "1/1/2020", + "1/1/2021", + "1/1/2022", + "1/1/2024", + "1/1/2025", + "1/1/2026", + "1/1/2027", + "1/2/2023", + "1/2/2007", + "1/9/2025", + "1/19/1998", + "1/18/1999", + "1/17/2000", + "1/15/2001", + "1/21/2002", + "1/20/2003", + "1/19/2004", + "1/17/2005", + "1/16/2006", + "1/15/2007", + "1/21/2008", + "1/19/2009", + "1/18/2010", + "1/17/2011", + "1/16/2012", + "1/21/2013", + "1/20/2014", + "1/19/2015", + "1/18/2016", + "1/16/2017", + "1/15/2018", + "1/21/2019", + "1/20/2020", + "1/18/2021", + "1/17/2022", + "1/16/2023", + "1/15/2024", + "1/20/2025", + "1/19/2026", + "1/18/2027", + "2/16/1998", + "2/15/1999", + "2/21/2000", + "2/19/2001", + "2/18/2002", + "2/17/2003", + "2/16/2004", + "2/21/2005", + "2/20/2006", + "2/19/2007", + "2/18/2008", + "2/16/2009", + "2/15/2010", + "2/21/2011", + "2/20/2012", + "2/18/2013", + "2/17/2014", + "2/16/2015", + "2/15/2016", + "2/20/2017", + "2/19/2018", + "2/18/2019", + "2/17/2020", + "2/15/2021", + "2/21/2022", + "2/20/2023", + "2/19/2024", + "2/17/2025", + "2/16/2026", + "2/15/2027", + "4/10/1998", + "4/2/1999", + "4/21/2000", + "4/13/2001", + "3/29/2002", + "4/18/2003", + "4/9/2004", + "3/25/2005", + "4/14/2006", + "4/6/2007", + "3/21/2008", + "4/10/2009", + "4/2/2010", + "4/22/2011", + "4/6/2012", + "3/29/2013", + "4/18/2014", + "4/3/2015", + "3/25/2016", + "4/14/2017", + "3/30/2018", + "4/19/2019", + "4/10/2020", + "4/2/2021", + "4/15/2022", + "4/7/2023", + "3/29/2024", + "4/18/2025", + "4/3/2026", + "3/26/2027", + "5/25/1998", + "5/31/1999", + "5/29/2000", + "5/28/2001", + "5/27/2002", + "5/26/2003", + "5/31/2004", + "5/30/2005", + "5/29/2006", + "5/28/2007", + "5/26/2008", + "5/25/2009", + "5/31/2010", + "5/30/2011", + "5/28/2012", + "5/27/2013", + "5/26/2014", + "5/25/2015", + "5/30/2016", + "5/29/2017", + "5/28/2018", + "5/27/2019", + "5/25/2020", + "5/31/2021", + "5/30/2022", + "5/29/2023", + "5/27/2024", + "5/26/2025", + "5/25/2026", + "5/31/2027", + "6/11/2004", + "6/20/2022", + "6/19/2023", + "6/19/2024", + "6/19/2025", + "6/19/2026", + "6/18/2027", + "7/3/1998", + "7/5/1999", + "7/4/2000", + "7/4/2001", + "7/4/2002", + "7/4/2003", + "7/5/2004", + "7/4/2005", + "7/4/2006", + "7/4/2007", + "7/4/2008", + "7/3/2009", + "7/5/2010", + "7/4/2011", + "7/4/2012", + "7/4/2013", + "7/4/2014", + "7/3/2015", + "7/4/2016", + "7/4/2017", + "7/4/2018", + "7/4/2019", + "7/3/2020", + "7/5/2021", + "7/4/2022", + "7/4/2023", + "7/4/2024", + "7/4/2025", + "7/3/2026", + "7/5/2027", + "9/7/1998", + "9/6/1999", + "9/4/2000", + "9/3/2001", + "9/2/2002", + "9/1/2003", + "9/6/2004", + "9/5/2005", + "9/4/2006", + "9/3/2007", + "9/1/2008", + "9/7/2009", + "9/6/2010", + "9/5/2011", + "9/3/2012", + "9/2/2013", + "9/1/2014", + "9/7/2015", + "9/5/2016", + "9/4/2017", + "9/3/2018", + "9/2/2019", + "9/7/2020", + "9/6/2021", + "9/5/2022", + "9/4/2023", + "9/2/2024", + "9/1/2025", + "9/7/2026", + "9/6/2027", + "9/11/2001", + "9/12/2001", + "9/13/2001", + "9/14/2001", + "10/29/2012", + "10/30/2012", + "11/26/1998", + "11/25/1999", + "11/23/2000", + "11/22/2001", + "11/28/2002", + "11/27/2003", + "11/25/2004", + "11/24/2005", + "11/23/2006", + "11/22/2007", + "11/27/2008", + "11/26/2009", + "11/25/2010", + "11/24/2011", + "11/22/2012", + "11/28/2013", + "11/27/2014", + "11/26/2015", + "11/24/2016", + "11/23/2017", + "11/22/2018", + "11/28/2019", + "11/26/2020", + "11/25/2021", + "11/24/2022", + "11/23/2023", + "11/28/2024", + "11/27/2025", + "11/26/2026", + "11/25/2027", + "12/05/2018", + "12/25/1998", + "12/24/1999", + "12/25/2000", + "12/25/2001", + "12/25/2002", + "12/25/2003", + "12/24/2004", + "12/26/2005", + "12/25/2006", + "12/25/2007", + "12/25/2008", + "12/25/2009", + "12/24/2010", + "12/26/2011", + "12/25/2012", + "12/25/2013", + "12/25/2014", + "12/25/2015", + "12/26/2016", + "12/25/2017", + "12/25/2018", + "12/25/2019", + "12/25/2020", + "12/24/2021", + "12/26/2022", + "12/25/2023", + "12/25/2024", + "12/25/2025", + "12/25/2026", + "12/24/2027" + ], + "earlyCloses": { + "7/3/2000": "12:00:00", + "7/3/2001": "12:00:00", + "7/5/2002": "12:00:00", + "7/3/2003": "12:00:00", + "7/3/2006": "12:00:00", + "7/3/2007": "12:00:00", + "7/3/2008": "12:00:00", + "7/3/2012": "12:00:00", + "7/3/2013": "12:00:00", + "7/3/2014": "12:00:00", + "7/3/2017": "12:00:00", + "7/3/2018": "12:00:00", + "7/3/2019": "12:00:00", + "7/3/2023": "12:00:00", + "7/3/2024": "12:00:00", + "7/3/2025": "12:00:00", + "11/26/1999": "12:00:00", + "11/24/2000": "12:00:00", + "11/23/2001": "12:00:00", + "11/29/2002": "12:00:00", + "11/28/2003": "12:00:00", + "11/26/2004": "12:00:00", + "11/25/2005": "12:00:00", + "11/24/2006": "12:00:00", + "11/23/2007": "12:00:00", + "11/28/2008": "12:00:00", + "11/27/2009": "12:00:00", + "11/26/2010": "12:00:00", + "11/25/2011": "12:00:00", + "11/23/2012": "12:00:00", + "11/29/2013": "12:00:00", + "11/28/2014": "12:00:00", + "11/27/2015": "12:00:00", + "11/25/2016": "12:00:00", + "11/24/2017": "12:00:00", + "11/23/2018": "12:00:00", + "11/29/2019": "12:00:00", + "11/27/2020": "12:00:00", + "11/26/2021": "12:00:00", + "11/25/2022": "12:00:00", + "11/24/2023": "12:00:00", + "11/29/2024": "12:00:00", + "11/28/2025": "12:00:00", + "11/27/2026": "12:00:00", + "11/26/2027": "12:00:00", + "12/24/2001": "12:00:00", + "12/24/2002": "12:00:00", + "12/24/2003": "12:00:00", + "12/26/2003": "12:00:00", + "12/24/2007": "12:00:00", + "12/24/2008": "12:00:00", + "12/24/2009": "12:00:00", + "12/24/2012": "12:00:00", + "12/24/2013": "12:00:00", + "12/24/2014": "12:00:00", + "12/24/2015": "12:00:00", + "12/24/2017": "12:00:00", + "12/24/2018": "12:00:00", + "12/24/2019": "12:00:00", + "12/24/2020": "12:00:00", + "12/24/2024": "12:00:00", + "12/24/2025": "12:00:00", + "12/24/2026": "12:00:00" + } + }, "Index-eurex-DAX": { "dataTimeZone": "Europe/Berlin", "exchangeTimeZone": "Europe/Berlin", diff --git a/Data/symbol-properties/symbol-properties-database.csv b/Data/symbol-properties/symbol-properties-database.csv index ef8d02d02d67..88695433c21a 100644 --- a/Data/symbol-properties/symbol-properties-database.csv +++ b/Data/symbol-properties/symbol-properties-database.csv @@ -210,6 +210,8 @@ usa,NQX,indexoption,Nasdaq-100 Reduced-Value Index Options,USD,100,0.05,1,,,,5 usa,RUT,index,,USD,1,0.001,1 usa,AEX,index,,EUR,1,0.01,1 +cboe,[*],index,,USD,1,0.01,1 + # for backwards compatibility, order here is important for futures, since we could have the same symbol for more than 1 market in which case Lean will use the first cfe,VX,future,VIX futures ,USD,1000.0,0.05,1.0 cbot,2YY,future,Micro 2-Year Yield Futures,USD,1000,0.001,1 diff --git a/Tests/Common/Securities/MarketHoursDatabaseTests.cs b/Tests/Common/Securities/MarketHoursDatabaseTests.cs index 33776cdeb9cd..3d38072068b7 100644 --- a/Tests/Common/Securities/MarketHoursDatabaseTests.cs +++ b/Tests/Common/Securities/MarketHoursDatabaseTests.cs @@ -460,6 +460,27 @@ public void CustomEntriesAreNotLostWhenReset(string ticker, SecurityType securit Assert.AreEqual(returnedEntry, entry); } + [TestCase("VIX3M")] + [TestCase("VVIX")] + [TestCase("TESTIDX")] + public void CorrectlyReadsCBOEIndexMarketHours(string ticker) + { + var db = MarketHoursDatabase.FromDataFolder(); + var symbol = Symbol.Create(ticker, SecurityType.Index, Market.CBOE); + + Assert.IsTrue(db.TryGetEntry(Market.CBOE, symbol, SecurityType.Index, out var entry)); + Assert.AreEqual(TimeZones.Chicago, entry.ExchangeHours.TimeZone); + Assert.AreEqual(TimeZones.NewYork, entry.DataTimeZone); + + var weekdays = new[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday }; + foreach (var day in weekdays) + { + var marketSegment = entry.ExchangeHours.MarketHours[day].Segments.First(s => s.State == MarketHoursState.Market); + Assert.AreEqual(new TimeSpan(8, 30, 0), marketSegment.Start); + Assert.AreEqual(new TimeSpan(15, 15, 0), marketSegment.End); + } + } + [Test] public void VerifyMarketHoursDataIntegrityForAllSymbols() { diff --git a/Tests/Common/Securities/SymbolPropertiesDatabaseTests.cs b/Tests/Common/Securities/SymbolPropertiesDatabaseTests.cs index 0b1eb6d1906b..9efee18eb883 100644 --- a/Tests/Common/Securities/SymbolPropertiesDatabaseTests.cs +++ b/Tests/Common/Securities/SymbolPropertiesDatabaseTests.cs @@ -538,6 +538,22 @@ public void HandlesEmptyOrderSizePriceMagnifierCorrectly() Assert.AreEqual(1, result.PriceMagnifier); } + [Test] + public void LoadsCBOEIndexSymbolProperties() + { + var db = SymbolPropertiesDatabase.FromDataFolder(); + + var entries = db.GetSymbolPropertiesList(Market.CBOE, SecurityType.Index).ToList(); + + Assert.IsNotEmpty(entries); + var wildcardEntry = entries.FirstOrDefault(e => e.Key.Symbol == SecurityDatabaseKey.Wildcard); + Assert.IsNotNull(wildcardEntry.Value); + Assert.AreEqual("USD", wildcardEntry.Value.QuoteCurrency); + Assert.AreEqual(1m, wildcardEntry.Value.ContractMultiplier); + Assert.AreEqual(0.01m, wildcardEntry.Value.MinimumPriceVariation); + Assert.AreEqual(1m, wildcardEntry.Value.LotSize); + } + private class TestingSymbolPropertiesDatabase : SymbolPropertiesDatabase { public TestingSymbolPropertiesDatabase(string file)