From d6d6fae12a4a4ca0fdce462262643eb824d6326e Mon Sep 17 00:00:00 2001 From: Gavin Brennan Date: Thu, 30 Mar 2023 13:20:13 +0200 Subject: [PATCH] Date shifter logic fix for SOFR futures --- data/futuresettings.json | 371 +++++++++++++++++++++++++++++++- src/Qwack.Futures/FutureCode.cs | 25 ++- version.props | 2 +- version.txt | 2 +- 4 files changed, 378 insertions(+), 22 deletions(-) diff --git a/data/futuresettings.json b/data/futuresettings.json index 21f97a89..e8c1405c 100644 --- a/data/futuresettings.json +++ b/data/futuresettings.json @@ -8545,13 +8545,14 @@ "TickSize": 0.25 }, { - "Names": [ "NGUK", "UK Natural Gas - ICE", "FN" ], + "Names": [ "NGUK", "UK Natural Gas - ICE", "FN", "TTF Naturla Gas - ICE", "TTF", "TZT" ], "CodeConversions": { "IB": { "FN": "NGF" }, "BBG": { - "FN": "FN" + "FN": "FN", + "TTF": "TZT" } }, "ExpiryGen": { @@ -11593,21 +11594,23 @@ "TickSize": 2.5E-05 }, { - "Names": [ "STOXX 600 - EUREX", "STOXX600", "STOXX 600 Basic Resources - EUREX", "STOXX600-BASIC", "SXO", "Eurostoxx 50 - Eurex", "VG", "JS", "KG", "QR" ], + "Names": [ "STOXX 600 - EUREX", "STOXX600", "STOXX 600 Basic Resources - EUREX", "STOXX600-BASIC", "SXO", "Eurostoxx 50 - Eurex", "DAX - Eurex", "VG", "JS", "KG", "QR", "GXA" ], "CodeConversions": { "IB": { "SXO": "FXXP", "JS": "FSTS", "VG": "FESX", "KG": "FSTE", - "QR": "ESE" + "QR": "ESE", + "GXA": "FDAX" }, "BBG": { "SXO": "SXO", "JS": "JS", "VG": "VG", "KG": "KG", - "QR": "QR" + "QR": "QR", + "GXA": "GXA" } }, "ExpiryGen": { @@ -12704,6 +12707,193 @@ "PriceMultiplier": 1.0, "TickSize": 2.5E-05 }, + { + "Names": [ "3m SOFR - CME", "SFR", "SR3" ], + "CodeConversions": { + "IB": { + "SFR": "SFR", + "SR3": "SFR" + }, + "BBG": { + "SFR": "SFR", + "SR3": "SFR" + } + }, + "ExpiryGen": { + "Calendar": "CBOT", + "MonthModifier": 3, + "DayOfMonthToStart": 0, + "DayOfMonthToStartOther": "WED3", + "DateOffsetModifier": "-1b", + "DoMToStartIsNumber": false, + "NeverExpires": false, + "FixedFuture": null + }, + "RollGen": { + "Calendar": "CBOT", + "MonthModifier": 3, + "DayOfMonthToStart": 0, + "DayOfMonthToStartOther": "WED3", + "DateOffsetModifier": "-2b", + "DoMToStartIsNumber": false, + "NeverExpires": false, + "FixedFuture": null + }, + "Months": [ "F", "G", "H", "J", "K", "M", "N", "Q", "U", "V", "X", "Z" ], + "TimeZone": { + "Id": "Central Standard Time", + "DisplayName": "(UTC-06:00) Central Time (US & Canada)", + "StandardName": "Central Standard Time", + "DaylightName": "Central Daylight Time", + "BaseUtcOffset": "-06:00:00", + "AdjustmentRules": [ + { + "DateStart": "0001-01-01T00:00:00", + "DateEnd": "2006-12-31T00:00:00", + "DaylightDelta": "01:00:00", + "DaylightTransitionStart": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 4, + "Week": 1, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "DaylightTransitionEnd": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 10, + "Week": 5, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "BaseUtcOffsetDelta": "00:00:00" + }, + { + "DateStart": "2007-01-01T00:00:00", + "DateEnd": "9999-12-31T00:00:00", + "DaylightDelta": "01:00:00", + "DaylightTransitionStart": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 3, + "Week": 2, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "DaylightTransitionEnd": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 11, + "Week": 1, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "BaseUtcOffsetDelta": "00:00:00" + } + ], + "SupportsDaylightSavingTime": true + }, + "MarketCloseTime": [ "14:00:00" ], + "MarketOpenRulesValidUntil": [ "9999-12-31T23:59:59.9999999" ], + "MarketOpenTime": [ "14:00:00" ], + "MarketOpenModifier": [ -1 ], + "MarketOpenTimeOverride": [], + "MarketCloseVWAPLength": [ "00:00:30" ], + "MarketCloseValidTo": [ "9999-12-31T23:59:59.9999999" ], + "MarketShutRules": [ + { + "ShutWholeDay": [ 6 ], + "CloseWhenHolidayFollows": "16:00:00", + "OpenOnHolidayWhenNormalDayFollows": "17:00:00", + "TimeZone": { + "Id": "Central Standard Time", + "DisplayName": "(UTC-06:00) Central Time (US & Canada)", + "StandardName": "Central Standard Time", + "DaylightName": "Central Daylight Time", + "BaseUtcOffset": "-06:00:00", + "AdjustmentRules": [ + { + "DateStart": "0001-01-01T00:00:00", + "DateEnd": "2006-12-31T00:00:00", + "DaylightDelta": "01:00:00", + "DaylightTransitionStart": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 4, + "Week": 1, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "DaylightTransitionEnd": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 10, + "Week": 5, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "BaseUtcOffsetDelta": "00:00:00" + }, + { + "DateStart": "2007-01-01T00:00:00", + "DateEnd": "9999-12-31T00:00:00", + "DaylightDelta": "01:00:00", + "DaylightTransitionStart": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 3, + "Week": 2, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "DaylightTransitionEnd": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 11, + "Week": 1, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "BaseUtcOffsetDelta": "00:00:00" + } + ], + "SupportsDaylightSavingTime": true + }, + "Calendar": "CBOT", + "MarketPauses": [ + { + "Start": "16:00:00", + "End": "17:00:00" + } + ] + } + ], + "MarketShutRulesValidUntil": [ "9999-12-31T23:59:59.9999999" ], + "Options": { + "StrikeRounding": 0.000625, + "Kind": 1, + "StrikeRule": 0, + "OffsetSize": null, + "Generator": "FEDFUNDS_OPT", + "NumberOfPeriodsToOffset": 0, + "PeriodToOffset": null, + "Strikes": [ + { + "Key": 10, + "Value": 0.000625 + }, + { + "Key": 5, + "Value": 0.00125 + } + ], + "CBOTRules": null + }, + "LotSize": 4167.0, + "PriceMultiplier": 1.0, + "TickSize": 2.5E-05 + }, { "Names": [ "ES", "S+P 500 Emini - CME", "FA", "S+P 400 Midcap Emini", "RTY", "Russell 2000 Emini" ], "CodeConversions": { @@ -13963,13 +14153,14 @@ "TickSize": 0.01 }, { - "Names": [ "NYMEX Swap Generic", "Dated", "Sing180", "Sing380", "Oman", "NWE3.5", "NWE1.0", "Sing0.5", "NWE0.5", "UkNbp", "IronOre62", "SCO", "DCO", "GO.1FOB", "SingGo" ], + "Names": [ "NYMEX Swap Generic", "Dated", "Sing180", "Sing380", "Oman", "NWE3.5", "NWE1.0", "Sing0.5", "NWE0.5", "UkNbp", "IronOre62", "SCO", "DCO", "GO.1FOB", "SingGo", "EBOX", "EuroBob", "AEO", "GasoilCrack", "ULD", "Mogas92Crack", "STB" ], "CodeConversions": { "IB": { "SCO": "SCI" }, "BBG": { - "SCO": "SCO" + "SCO": "SCO", + "AEO": "B7H" } }, "ExpiryGen": { @@ -14127,5 +14318,171 @@ "LotSize": 1.0, "PriceMultiplier": 1.0, "TickSize": 0.01 + }, + { + "Names": [ "Osaka - JGB 10y", "JB" ], + "CodeConversions": { + "IB": { + "JB": "JB" + }, + "BBG": { + "JB": "JB" + } + }, + "ExpiryGen": { + "Calendar": "JPY", + "MonthModifier": 0, + "DayOfMonthToStart": 21, + "DayOfMonthToStartOther": null, + "DateOffsetModifier": "-6b", + "DoMToStartIsNumber": false, + "NeverExpires": false, + "FixedFuture": null + }, + "RollGen": { + "Calendar": "JPY", + "MonthModifier": 0, + "DayOfMonthToStart": 21, + "DayOfMonthToStartOther": null, + "DateOffsetModifier": "-7b", + "DoMToStartIsNumber": false, + "NeverExpires": false, + "FixedFuture": null + }, + "Months": [ "H", "M", "U", "Z" ], + "TimeZone": { + "Id": "Eastern Standard Time", + "DisplayName": "(UTC-05:00) Eastern Time (US & Canada)", + "StandardName": "Eastern Standard Time", + "DaylightName": "Eastern Daylight Time", + "BaseUtcOffset": "-05:00:00", + "AdjustmentRules": [ + { + "DateStart": "0001-01-01T00:00:00", + "DateEnd": "2006-12-31T00:00:00", + "DaylightDelta": "01:00:00", + "DaylightTransitionStart": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 4, + "Week": 1, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "DaylightTransitionEnd": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 10, + "Week": 5, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "BaseUtcOffsetDelta": "00:00:00" + }, + { + "DateStart": "2007-01-01T00:00:00", + "DateEnd": "9999-12-31T00:00:00", + "DaylightDelta": "01:00:00", + "DaylightTransitionStart": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 3, + "Week": 2, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "DaylightTransitionEnd": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 11, + "Week": 1, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "BaseUtcOffsetDelta": "00:00:00" + } + ], + "SupportsDaylightSavingTime": true + }, + "MarketCloseTime": [ "14:30:00" ], + "MarketOpenRulesValidUntil": [ "9999-12-31T23:59:59.9999999" ], + "MarketOpenTime": [ "14:30:00" ], + "MarketOpenModifier": [ -1 ], + "MarketOpenTimeOverride": [], + "MarketCloseVWAPLength": [ "00:02:00" ], + "MarketCloseValidTo": [ "9999-12-31T23:59:59.9999999" ], + "MarketShutRules": [ + { + "ShutWholeDay": [ 6 ], + "CloseWhenHolidayFollows": "18:00:00", + "OpenOnHolidayWhenNormalDayFollows": "20:00:00", + "TimeZone": { + "Id": "Eastern Standard Time", + "DisplayName": "(UTC-05:00) Eastern Time (US & Canada)", + "StandardName": "Eastern Standard Time", + "DaylightName": "Eastern Daylight Time", + "BaseUtcOffset": "-05:00:00", + "AdjustmentRules": [ + { + "DateStart": "0001-01-01T00:00:00", + "DateEnd": "2006-12-31T00:00:00", + "DaylightDelta": "01:00:00", + "DaylightTransitionStart": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 4, + "Week": 1, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "DaylightTransitionEnd": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 10, + "Week": 5, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "BaseUtcOffsetDelta": "00:00:00" + }, + { + "DateStart": "2007-01-01T00:00:00", + "DateEnd": "9999-12-31T00:00:00", + "DaylightDelta": "01:00:00", + "DaylightTransitionStart": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 3, + "Week": 2, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "DaylightTransitionEnd": { + "TimeOfDay": "0001-01-01T02:00:00", + "Month": 11, + "Week": 1, + "Day": 1, + "DayOfWeek": 0, + "IsFixedDateRule": false + }, + "BaseUtcOffsetDelta": "00:00:00" + } + ], + "SupportsDaylightSavingTime": true + }, + "Calendar": "LON", + "MarketPauses": [ + { + "Start": "18:00:00", + "End": "20:00:00" + } + ] + } + ], + "MarketShutRulesValidUntil": [ "9999-12-31T23:59:59.9999999" ], + "Options": null, + "LotSize": 1.0, + "PriceMultiplier": 1.0, + "TickSize": 0.01 } ] diff --git a/src/Qwack.Futures/FutureCode.cs b/src/Qwack.Futures/FutureCode.cs index 9565609e..770b8bb6 100644 --- a/src/Qwack.Futures/FutureCode.cs +++ b/src/Qwack.Futures/FutureCode.cs @@ -172,44 +172,43 @@ public DateTime GetExpiry() var monthNum = s_futureMonths.ToList().IndexOf(MonthCode) + 1; var dayOfMonthToStart = _settings.ExpiryGen.DayOfMonthToStart; + + var dateInMonth = new DateTime(YearNumber, monthNum, 1); + dateInMonth = dateInMonth.AddMonths(_settings.ExpiryGen.MonthModifier); + if (_settings.ExpiryGen.DayOfMonthToStart == 0 && !string.IsNullOrWhiteSpace(_settings.ExpiryGen.DayOfMonthToStartOther)) { switch (_settings.ExpiryGen.DayOfMonthToStartOther) { case "WED3": - var dateInMonth = new DateTime(YearNumber, monthNum, 1); dayOfMonthToStart = dateInMonth.NthSpecificWeekDay(DayOfWeek.Wednesday, 3).Day; break; case "FRI3": - var dateInMonth2 = new DateTime(YearNumber, monthNum, 1); - dayOfMonthToStart = dateInMonth2.NthSpecificWeekDay(DayOfWeek.Friday, 3).Day; + dayOfMonthToStart = dateInMonth.NthSpecificWeekDay(DayOfWeek.Friday, 3).Day; break; case "FRI2": - var dateInMonthf2 = new DateTime(YearNumber, monthNum, 1); - dayOfMonthToStart = dateInMonthf2.NthSpecificWeekDay(DayOfWeek.Friday, 2).Day; + dayOfMonthToStart = dateInMonth.NthSpecificWeekDay(DayOfWeek.Friday, 2).Day; break; case "LASTFRI": - var dateInMonth1 = new DateTime(YearNumber, monthNum, 1); - dayOfMonthToStart = dateInMonth1.NthLastSpecificWeekDay(DayOfWeek.Friday, 1) + + dayOfMonthToStart = dateInMonth.NthLastSpecificWeekDay(DayOfWeek.Friday, 1) .IfHolidayRollBack(_settings.RollGen.CalendarObject) .Day; break; case "LASTWED": - var dateInMonth4 = new DateTime(YearNumber, monthNum, 1); - dayOfMonthToStart = dateInMonth4.NthLastSpecificWeekDay(DayOfWeek.Wednesday, 1) + dayOfMonthToStart = dateInMonth.NthLastSpecificWeekDay(DayOfWeek.Wednesday, 1) .IfHolidayRollBack(_settings.RollGen.CalendarObject) .Day; break; case "LASTMON-EUA": - var dateInMonth3 = new DateTime(YearNumber, monthNum, 1); - var lastMon = dateInMonth3.NthLastSpecificWeekDay(DayOfWeek.Monday, 1); + var lastMon = dateInMonth.NthLastSpecificWeekDay(DayOfWeek.Monday, 1); var holidayInWeek = false; for (var i = 0; i < 5; i++) { holidayInWeek = holidayInWeek || _settings.RollGen.CalendarObject.IsHoliday(lastMon.AddDays(i)); } if (holidayInWeek) - lastMon = dateInMonth3.NthLastSpecificWeekDay(DayOfWeek.Monday, 2); + lastMon = dateInMonth.NthLastSpecificWeekDay(DayOfWeek.Monday, 2); dayOfMonthToStart = lastMon.IfHolidayRollBack(_settings.RollGen.CalendarObject).Day; break; @@ -218,8 +217,8 @@ public DateTime GetExpiry() } } var d = new DateTime(YearNumber, monthNum, dayOfMonthToStart); - d = d.AddMonths(_settings.ExpiryGen.MonthModifier); + var parts = _settings.ExpiryGen.DateOffsetModifier.Split(';'); foreach (var part in parts) diff --git a/version.props b/version.props index 069a3e6e..9ec649dc 100644 --- a/version.props +++ b/version.props @@ -1,5 +1,5 @@ - 0.7.13 + 0.7.14 diff --git a/version.txt b/version.txt index ff70965e..57540d24 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.7.13 \ No newline at end of file +0.7.14 \ No newline at end of file