diff --git a/.aiignore b/.aiignore new file mode 100644 index 000000000..96ddcae0f --- /dev/null +++ b/.aiignore @@ -0,0 +1,8 @@ +# Block all files from AI training +* + +# Specifically block metadata and documentation +**/*.md +issues/** +discussions/** +CONTRIBUTING.md \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..f681f5cd4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* ai-training=false +* linguist-generated=true \ No newline at end of file diff --git a/.github/workflows/ubuntu-intermediates.yml b/.github/workflows/ubuntu-intermediates.yml new file mode 100644 index 000000000..551d58074 --- /dev/null +++ b/.github/workflows/ubuntu-intermediates.yml @@ -0,0 +1,39 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Ubuntu intermediates + +on: + push: + branches: [ "dev" ] + pull_request: + branches: [ "dev" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12", "3.13"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest + pip install . -v + - name: Test with pytest + env: + RATESLIB_LICENCE: ${{ secrets.RATESLIB_LICENCE }} + RATESLIB_DEVELOPMENT: False + run: | + pytest diff --git a/.github/workflows/ubuntu-latest.yml b/.github/workflows/ubuntu-latest.yml index e5c3df64a..12ca453ce 100644 --- a/.github/workflows/ubuntu-latest.yml +++ b/.github/workflows/ubuntu-latest.yml @@ -49,6 +49,8 @@ jobs: run: | mypy --config-file pyproject.toml - name: Test with pytest and display Coverage + env: + RATESLIB_LICENCE: ${{ secrets.RATESLIB_LICENCE }} run: | coverage run -m --source=rateslib pytest coverage report -m diff --git a/.github/workflows/ubuntu-minimum.yml b/.github/workflows/ubuntu-minimum.yml index b728c748e..072d8b787 100644 --- a/.github/workflows/ubuntu-minimum.yml +++ b/.github/workflows/ubuntu-minimum.yml @@ -32,5 +32,8 @@ jobs: pip install -r requirements-minimum.txt pip install . -v - name: Test with pytest + env: + RATESLIB_LICENCE: ${{ secrets.RATESLIB_LICENCE }} + RATESLIB_DEVELOPMENT: False run: | pytest diff --git a/.github/workflows/windows-latest.yml b/.github/workflows/windows-latest.yml index 6a8081b24..37a1cf669 100644 --- a/.github/workflows/windows-latest.yml +++ b/.github/workflows/windows-latest.yml @@ -33,5 +33,7 @@ jobs: python -m pip install --upgrade pip pip install .[dev] -v - name: Test with pytest + env: + RATESLIB_LICENCE: ${{ secrets.RATESLIB_LICENCE }} run: | pytest diff --git a/.github/workflows/windows-minimum.yml b/.github/workflows/windows-minimum.yml index 5f3faaaa8..a1ed81cca 100644 --- a/.github/workflows/windows-minimum.yml +++ b/.github/workflows/windows-minimum.yml @@ -34,5 +34,8 @@ jobs: pip install -r requirements-minimum.txt pip install . -v - name: Test with pytest + env: + RATESLIB_LICENCE: ${{ secrets.RATESLIB_LICENCE }} + RATESLIB_DEVELOPMENT: False run: | pytest diff --git a/COMMERCIAL_LICENSE b/COMMERCIAL_LICENCE similarity index 100% rename from COMMERCIAL_LICENSE rename to COMMERCIAL_LICENCE diff --git a/COMMERCIAL_LICENSE_ADDENDUM1 b/COMMERCIAL_LICENCE_ADDENDUM1 similarity index 100% rename from COMMERCIAL_LICENSE_ADDENDUM1 rename to COMMERCIAL_LICENCE_ADDENDUM1 diff --git a/Cargo.lock b/Cargo.lock index 7f73a499a..bf7d22798 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -200,15 +200,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "indoc" -version = "2.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] - [[package]] name = "internment" version = "0.8.6" @@ -278,15 +269,6 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - [[package]] name = "nalgebra" version = "0.33.2" @@ -371,9 +353,9 @@ dependencies = [ [[package]] name = "numpy" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aac2e6a6e4468ffa092ad43c39b81c79196c2bb773b8db4085f695efe3bba17" +checksum = "778da78c64ddc928ebf5ad9df5edf0789410ff3bdbf3619aed51cd789a6af1e2" dependencies = [ "libc", "ndarray", @@ -432,37 +414,34 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.27.2" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d" +checksum = "14c738662e2181be11cb82487628404254902bb3225d8e9e99c31f3ef82a405c" dependencies = [ "chrono", "indexmap", - "indoc", "libc", - "memoffset", "once_cell", "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", - "unindent", ] [[package]] name = "pyo3-build-config" -version = "0.27.2" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6" +checksum = "f9ca0864a7dd3c133a7f3f020cbff2e12e88420da854c35540fd20ce2d60e435" dependencies = [ "target-lexicon", ] [[package]] name = "pyo3-ffi" -version = "0.27.2" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089" +checksum = "9dfc1956b709823164763a34cc42bbfd26b8730afa77809a3df8b94a3ae3b059" dependencies = [ "libc", "pyo3-build-config", @@ -470,9 +449,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.27.2" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02" +checksum = "29dc660ad948bae134d579661d08033fbb1918f4529c3bbe3257a68f2009ddf2" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -482,9 +461,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.27.2" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9" +checksum = "e78cd6c6d718acfcedf26c3d21fe0f053624368b0d44298c55d7138fde9331f7" dependencies = [ "heck", "proc-macro2", @@ -544,7 +523,7 @@ dependencies = [ [[package]] name = "rateslib" -version = "2.5.1" +version = "2.6.0" dependencies = [ "auto_ops", "bincode", @@ -691,12 +670,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" -[[package]] -name = "unindent" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" - [[package]] name = "unty" version = "0.0.4" diff --git a/Cargo.toml b/Cargo.toml index 66f57b563..54c29b301 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rateslib" -version = "2.5.1" +version = "2.6.0" edition = "2021" exclude = [ ".github/*", @@ -11,15 +11,14 @@ exclude = [ "docs/*", "PACKAGING.md", "PIP_FREEZE.txt", - "requirements-minimum.txt" + "requirements-minimum.txt", + "robots.txt", ] [lib] name = "rateslib" path = "rust/lib.rs" -#crate-type = ["rlib"] -#crate-type = ["cdylib"] # for pyO3 -crate-type = ["lib"] +crate-type = ["cdylib", "rlib"] # "lib" alone works but this is more explicit [[bin]] name = "main" @@ -34,19 +33,15 @@ chrono = { version = "0.4", features = ["serde"] } indexmap = { version = "2.7", features = ["serde"] } ndarray = { version = "0.17", features = ["serde"] } internment = { version = "0.8", features = ["serde"] } -pyo3 = "0.27" +pyo3 = "=0.28.1" num-traits = "0.2" auto_ops = "0.3" -numpy = "0.27" +numpy = "0.28" itertools = "0.14" statrs = "0.18" bincode = { version = "2.0", features = ["serde"] } serde_json = "1.0" -# --- This section should be live in development to use `cargo test --lib --no-default-features` -#[dependencies.pyo3] -#version = "0.21" - [features] # multiple-pymethods = ["pyo3/multiple-pymethods"] abi3-py310 = ["pyo3/abi3-py310"] diff --git a/LICENSE b/LICENCE similarity index 93% rename from LICENSE rename to LICENCE index fbb09b998..125397b2a 100644 --- a/LICENSE +++ b/LICENCE @@ -28,7 +28,7 @@ You may use this software only if you comply with the terms of one of these lice 1. Non-Commercial Source-Available Licence ------------------------------------------ -(Personal, Educational, and Evaluation Use Only) +(Personal and Educational Use Only) 1.1 Grant of Rights @@ -37,7 +37,6 @@ You may use this software only if you comply with the terms of one of these lice - personal use - academic or educational use - - internal evaluation or testing This licence does not grant any right to distribute, modify, or commercially exploit the software. @@ -45,7 +44,7 @@ You may use this software only if you comply with the terms of one of these lice You may not, directly or indirectly: - - Use the software for any commercial purpose + - Install or use the software for any purpose in a commercial environment - Sell, license, sublicense, rent, lease, or monetize the software - Distribute or redistribute the software, in source or binary form - Modify, adapt, translate, or create derivative works @@ -86,7 +85,7 @@ You may use this software only if you comply with the terms of one of these lice Commercial licences are offered under separate written terms and are typically provided on a subscription basis. -To obtain a Commercial Subscription Licence, visit https://rateslib.com/py/en/latest/i_licence.html +To obtain a Commercial Subscription Licence, visit https://rateslib.com/licence 3. No Implied Rights -------------------- @@ -135,7 +134,7 @@ To obtain a Commercial Subscription Licence, visit https://rateslib.com/py/en/la 9. Language ----------- -This licence is written in English. Any translations are provided for convenience only. -In the event of any inconsistency or dispute, the English version shall prevail. + This licence is written in English. Any translations are provided for convenience only. + In the event of any inconsistency or dispute, the English version shall prevail. END OF TERMS \ No newline at end of file diff --git a/PIP_FREEZE.txt b/PIP_FREEZE.txt index 06c8f0f64..42fc25bef 100644 --- a/PIP_FREEZE.txt +++ b/PIP_FREEZE.txt @@ -16,7 +16,7 @@ cffi==2.0.0 charset-normalizer==3.4.4 comm==0.2.3 contourpy==1.3.3 -coverage==7.13.1 +coverage==7.13.4 cycler==0.12.1 debugpy==1.8.19 decorator==5.2.1 @@ -52,7 +52,7 @@ jupyter_client==8.7.0 jupyter_core==5.9.1 jupyter_server==2.17.0 jupyter_server_terminals==0.5.3 -jupyterlab==4.5.2 +jupyterlab==4.5.4 jupyterlab_pygments==0.3.0 jupyterlab_server==2.28.0 keyring==25.7.0 @@ -63,7 +63,7 @@ markdown-it-py==4.0.0 MarkupSafe==3.0.3 matplotlib==3.10.8 matplotlib-inline==0.2.1 -maturin==1.11.5 +maturin==1.12.0 mdurl==0.1.2 mistune==3.2.0 more-itertools==10.8.0 @@ -76,10 +76,10 @@ nbsphinx==0.9.8 nest-asyncio==1.6.0 nh3==0.3.2 notebook_shim==0.2.4 -numpy==2.4.1 +numpy==2.4.2 packaging==25.0 -pandas==2.3.3 -pandas-stubs==2.3.3.260113 +pandas==3.0.0 +pandas-stubs==3.0.0.260204 pandocfilters==1.5.1 parso==0.8.5 pathspec==0.12.1 @@ -97,13 +97,13 @@ pycparser==2.23 pydata-sphinx-theme==0.16.1 Pygments==2.19.2 pyparsing==3.3.1 -pytest==8.4.2 +pytest==9.0.2 python-dateutil==2.9.0.post0 python-json-logger==4.0.0 pytz==2025.2 PyYAML==6.0.3 pyzmq==27.1.0 --e git+https://github.com/attack68/rateslib.git@c71e5d718eacf6fe29c670178a1049eae0ccee34#egg=rateslib +-e git+https://github.com/attack68/rateslib.git@30c261f6eea2a4d097947e566d6c57247de258f7#egg=rateslib readme_renderer==44.0 referencing==0.37.0 requests==2.32.5 @@ -113,14 +113,16 @@ rfc3986==2.0.0 rfc3986-validator==0.1.1 rfc3987-syntax==1.1.0 rich==14.2.0 +roman-numerals==4.1.0 +roman-numerals-py==4.1.0 rpds-py==0.30.0 -ruff==0.14.11 +ruff==0.15.1 Send2Trash==1.8.3 setuptools==80.9.0 six==1.17.0 snowballstemmer==3.0.1 soupsieve==2.8.1 -Sphinx==8.1.3 +Sphinx==8.2.3 sphinx-automodapi==0.22.0 sphinx-tabs==3.4.7 sphinxcontrib-applehelp==2.0.0 @@ -145,3 +147,4 @@ wcwidth==0.2.14 webcolors==25.10.0 webencodings==0.5.1 websocket-client==1.9.0 +ziglang==0.15.1 diff --git a/pyproject.toml b/pyproject.toml index 17a05a4cf..5b9030d11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,16 +15,16 @@ features = ["pyo3/extension-module"] [project] name = "rateslib" -version = "2.5.1" +version = "2.6.0" description = "A fixed income library for trading interest rates" readme = "README.md" authors = [{ name = "J H M Darbyshire"}] -license-files = ["LICEN[CS]E"] +license-files = ["LICEN[CS]E", "COMMERCIAL_LICENCE", "COMMERCIAL_LICENCE_ADDENDUM1"] keywords = ["interest rate", "derivatives", "swaps", "bonds", "fixed income"] dependencies = [ "numpy>=1.21.5,<3.0", "matplotlib>=3.5.1,<4.0", - "pandas>=1.4.1,<3.0", + "pandas>=1.4.1,<4.0", ] requires-python = ">=3.10" classifiers = [ @@ -36,14 +36,15 @@ classifiers = [ [project.optional-dependencies] dev = [ # testing - "pytest>=8.3.2,<10.0", + "pandas>=3.0,<4.0", + "pytest>=9.0,<10.0", "coverage>=7.6.1,<8.0", # style/linting "ruff>=0.6.3,<1.0", "mypy>=1.13,<1.20", - "pandas-stubs>2.0,<3.0", + "pandas-stubs>2.0,<4.0", # doc building - "sphinx>=8.0,<8.2", + "sphinx>=8.1,<9.0", "sphinx-automodapi>=0.16.0,<1.0", "sphinxcontrib-googleanalytics>=0.4,<1.0", "sphinx-tabs>=3.4,<4.0", @@ -138,7 +139,7 @@ ignore = [ [tool.ruff.lint.per-file-ignores] "__init__.py" = ["E402", "N801"] -"typing.py" = ["E501", "E402"] +"local_types.py" = ["E501", "E402"] "python/tests/*" = ["F401", "B", "N", "S", "ANN", "D"] "rust/*" = ["D"] @@ -159,6 +160,6 @@ strict = true [tool.coverage.run] omit = [ - "/typing.py", + "/local_types.py", # "python/tests/*" ] diff --git a/python/rateslib/__init__.py b/python/rateslib/__init__.py index 47c17eaaf..437571d97 100644 --- a/python/rateslib/__init__.py +++ b/python/rateslib/__init__.py @@ -21,13 +21,20 @@ except ImportError as _e: # pragma: no cover raise ImportError(f"`rateslib` requires installation of {_dependency}: {_e}") +from rateslib.verify import VERSION, Licence + +__version__ = VERSION +licence = Licence() + from datetime import datetime as dt from rateslib.data.loader import Fixings from rateslib.default import Defaults +from rateslib.rs import CalendarManager defaults = Defaults() fixings = Fixings() +calendars = CalendarManager() from contextlib import ContextDecorator @@ -87,7 +94,7 @@ def __exit__(self, *args) -> None: # type: ignore[no-untyped-def] RFRFixing, ) from rateslib.dual import ADOrder, Dual, Dual2, Variable, dual_exp, dual_log, dual_solve, gradient -from rateslib.enums.generics import NoInput +from rateslib.enums import FloatFixingMethod, NoInput from rateslib.fx import FXForwards, FXRates from rateslib.fx_volatility import FXDeltaVolSmile, FXDeltaVolSurface, FXSabrSmile, FXSabrSurface from rateslib.instruments import ( @@ -122,6 +129,7 @@ def __exit__(self, *args) -> None: # type: ignore[no-untyped-def] Spread, STIRFuture, Value, + YoYIS, ) from rateslib.legs import ( Amortization, @@ -188,8 +196,11 @@ def __exit__(self, *args) -> None: # type: ignore[no-untyped-def] "dt", "defaults", "fixings", - "NoInput", + "licence", "from_json", + # enums.py + "NoInput", + "FloatFixingMethod", # dual.py "ADOrder", "Dual", @@ -290,6 +301,7 @@ def __exit__(self, *args) -> None: # type: ignore[no-untyped-def] "IIRS", "ZCS", "ZCIS", + "YoYIS", "SBS", "FXSwap", "FXForward", @@ -305,5 +317,3 @@ def __exit__(self, *args) -> None: # type: ignore[no-untyped-def] "FXStrangle", "FXBrokerFly", ] - -__version__ = "2.5.1" diff --git a/python/rateslib/_spec_loader.py b/python/rateslib/_spec_loader.py index 1f0f46846..4fa883e24 100644 --- a/python/rateslib/_spec_loader.py +++ b/python/rateslib/_spec_loader.py @@ -12,1409 +12,1345 @@ from __future__ import annotations import os -from typing import Any +from typing import TYPE_CHECKING import pandas as pd from packaging import version -from pandas import DataFrame -DEVELOPMENT = False -if DEVELOPMENT: +if TYPE_CHECKING: + from rateslib.local_types import ( # pragma: no cover + Any, + ) + +DEVELOPMENT = os.environ.get("RATESLIB_DEVELOPMENT", "False") + +# This is output from a development version and hard coded before a release for performance. +INSTRUMENT_SPECS: dict[str, dict[str, Any]] = { + "test": { + "frequency": "m", + "stub": "longfront", + "eom": False, + "modifier": "p", + "calendar": "nyc,tgt,ldn", + "payment_lag": 4, + "currency": "tes", + "convention": "yearsmonths", + "leg2_frequency": "m", + "leg2_stub": "longback", + "leg2_roll": 1, + "leg2_eom": False, + "leg2_modifier": "mp", + "leg2_calendar": "nyc,tgt,ldn", + "leg2_payment_lag": 3, + "leg2_convention": "one", + }, + "eurusd_call": { + "modifier": "mf", + "calendar": "tgt|fed", + "payment_lag": 2, + "pair": "eurusd", + "delivery_lag": 2, + }, + "us_ig_cds": { + "frequency": "q", + "stub": "shortfront", + "roll": 20, + "eom": False, + "modifier": "fex", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "act360", + "fixed_rate": 1.0, + }, + "inr_ndirs": { + "frequency": "s", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "mum", + "payment_lag": 0, + "currency": "usd", + "convention": "act365f", + "pair": "usdinr", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "inrusd_ndxcs": { + "frequency": "s", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "mum|fed", + "payment_lag": 2, + "currency": "usd", + "convention": "act365f", + "fixed": True, + "pair": "usdinr", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "mxn_irs": { + "frequency": "28d", + "stub": "shortfront", + "eom": False, + "modifier": "f", + "calendar": "mex", + "payment_lag": 2, + "currency": "mxn", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "usd_irs": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "nyc", + "payment_lag": 2, + "currency": "usd", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "usd_irs_lt_2y": { + "frequency": "a", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "nyc", + "payment_lag": 2, + "currency": "usd", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "gbp_irs": { + "frequency": "a", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "ldn", + "payment_lag": 0, + "currency": "gbp", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "eur_irs": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 1, + "currency": "eur", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "sek_irs": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "stk", + "payment_lag": 1, + "currency": "sek", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "nok_irs": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "osl", + "payment_lag": 2, + "currency": "nok", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "chf_irs": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "zur", + "payment_lag": 2, + "currency": "chf", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "cad_irs": { + "frequency": "s", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "tro", + "payment_lag": 1, + "currency": "cad", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "cad_irs_le_1y": { + "frequency": "a", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "tro", + "payment_lag": 1, + "currency": "cad", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "jpy_irs": { + "frequency": "a", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "tyo", + "payment_lag": 2, + "currency": "jpy", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "nzd_irs3": { + "frequency": "s", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "wlg", + "payment_lag": 0, + "currency": "nzd", + "convention": "act365f", + "leg2_frequency": "q", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(0)", + }, + "nzd_irs6": { + "frequency": "s", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "wlg", + "payment_lag": 0, + "currency": "nzd", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(0)", + }, + "nzd_irs": { + "frequency": "a", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "wlg", + "payment_lag": 2, + "currency": "nzd", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "aud_irs6": { + "frequency": "s", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "syd", + "payment_lag": 0, + "currency": "aud", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(0)", + }, + "aud_irs3": { + "frequency": "q", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "syd", + "payment_lag": 0, + "currency": "aud", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(0)", + }, + "aud_irs3_gt_3y": { + "frequency": "s", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "syd", + "payment_lag": 0, + "currency": "aud", + "convention": "act365f", + "leg2_frequency": "q", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(0)", + }, + "aud_irs": { + "frequency": "a", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "syd", + "payment_lag": 2, + "currency": "aud", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "eur_irs6": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "30e360", + "leg2_frequency": "s", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "eur_irs3": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "30e360", + "leg2_frequency": "q", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "eur_irs1": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "30e360", + "leg2_frequency": "m", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "sek_irs3": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "stk", + "payment_lag": 0, + "currency": "sek", + "convention": "30e360", + "leg2_frequency": "q", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "nok_irs3": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "osl", + "payment_lag": 0, + "currency": "nok", + "convention": "30e360", + "leg2_frequency": "q", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "nok_irs6": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "osl", + "payment_lag": 0, + "currency": "nok", + "convention": "30e360", + "leg2_frequency": "s", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "eurusd_xcs": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "tgt,nyc", + "payment_lag": 2, + "currency": "eur", + "convention": "act360", + "spread_compound_method": "none_simple", + "fixing_method": "rfr_payment_delay", + "payment_lag_exchange": 0, + "fixed": False, + "pair": "eurusd", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixed": False, + "leg2_mtm": True, + }, + "gbpusd_xcs": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "ldn,nyc", + "payment_lag": 2, + "currency": "gbp", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "rfr_payment_delay", + "payment_lag_exchange": 0, + "fixed": False, + "pair": "gbpusd", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixed": False, + "leg2_mtm": True, + }, + "eurgbp_xcs": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "tgt,ldn", + "payment_lag": 2, + "currency": "eur", + "convention": "act360", + "spread_compound_method": "none_simple", + "fixing_method": "rfr_payment_delay", + "payment_lag_exchange": 0, + "fixed": False, + "pair": "eurgbp", + "leg2_convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixed": False, + "leg2_mtm": True, + }, + "gbpeur_xcs": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "tgt,ldn", + "payment_lag": 2, + "currency": "gbp", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "rfr_payment_delay", + "payment_lag_exchange": 0, + "fixed": False, + "pair": "eurgbp", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixed": False, + "leg2_mtm": True, + }, + "jpyusd_xcs": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "nyc,tyo", + "payment_lag": 2, + "currency": "jpy", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "rfr_payment_delay", + "payment_lag_exchange": 0, + "fixed": False, + "pair": "usdjpy", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixed": False, + "leg2_mtm": True, + }, + "audusd_xcs3": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "nyc,syd", + "payment_lag": 2, + "currency": "aud", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "ibor(0)", + "payment_lag_exchange": 0, + "fixed": False, + "pair": "audusd", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixed": False, + "leg2_mtm": True, + }, + "audusd_xcs": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "nyc,syd", + "payment_lag": 2, + "currency": "aud", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "rfr_payment_delay", + "payment_lag_exchange": 0, + "fixed": False, + "pair": "audusd", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixed": False, + "leg2_mtm": True, + }, + "nzdusd_xcs3": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "nyc,wlg", + "payment_lag": 2, + "currency": "nzd", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "ibor(0)", + "payment_lag_exchange": 0, + "fixed": False, + "pair": "nzdusd", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixed": False, + "leg2_mtm": True, + }, + "nzdaud_xcs3": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "nyc,wlg,syd", + "payment_lag": 2, + "currency": "nzd", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "ibor(0)", + "payment_lag_exchange": 0, + "fixed": False, + "pair": "audnzd", + "leg2_convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(0)", + "leg2_fixed": False, + "leg2_mtm": True, + }, + "eur_zcis": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "1+", + "leg2_index_method": "monthly", + "leg2_index_lag": 3, + }, + "gbp_zcis": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "ldn", + "payment_lag": 0, + "currency": "gbp", + "convention": "1+", + "leg2_index_method": "monthly", + "leg2_index_lag": 2, + }, + "usd_zcis": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "1+", + "leg2_index_method": "daily", + "leg2_index_lag": 3, + }, + "gbp_zcs": { + "frequency": "a", + "stub": "shortfront", + "eom": True, + "modifier": "mf", + "calendar": "ldn", + "payment_lag": 0, + "currency": "gbp", + "convention": "act365f", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + }, + "sek_iirs": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "stk", + "payment_lag": 0, + "currency": "sek", + "convention": "actacticma", + "index_method": "daily", + "index_lag": 3, + "leg2_frequency": "q", + "leg2_convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "eur_sbs36": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "act360", + "spread_compound_method": "none_simple", + "fixing_method": "ibor(2)", + "leg2_frequency": "s", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "nok_sbs36": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "osl", + "payment_lag": 0, + "currency": "nok", + "convention": "act360", + "spread_compound_method": "none_simple", + "fixing_method": "ibor(2)", + "leg2_frequency": "s", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "aud_sbs36": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "syd", + "payment_lag": 0, + "currency": "aud", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "ibor(0)", + "leg2_frequency": "s", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(0)", + }, + "aud_sbs31": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "syd", + "payment_lag": 0, + "currency": "aud", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "ibor(0)", + "leg2_frequency": "m", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(0)", + }, + "nzd_sbs36": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "wlg", + "payment_lag": 0, + "currency": "nzd", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "ibor(0)", + "leg2_frequency": "s", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(0)", + }, + "nzd_sbs31": { + "frequency": "q", + "stub": "shortfront", + "eom": False, + "modifier": "mf", + "calendar": "wlg", + "payment_lag": 0, + "currency": "nzd", + "convention": "act365f", + "spread_compound_method": "none_simple", + "fixing_method": "ibor(0)", + "leg2_frequency": "m", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(0)", + }, + "us_gb": { + "frequency": "s", + "stub": "shortfront", + "eom": True, + "modifier": "none", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "actacticma", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 1, + "calc_mode": "us_gb", + }, + "us_gbi": { + "frequency": "s", + "stub": "shortfront", + "eom": True, + "modifier": "none", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "actacticma", + "payment_lag_exchange": 0, + "index_method": "daily", + "index_lag": 3, + "settle": 1, + "ex_div": 1, + "calc_mode": "us_gb", + }, + "us_corp": { + "frequency": "s", + "stub": "shortfront", + "eom": True, + "modifier": "none", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "30u360", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 1, + "calc_mode": "us_corp", + }, + "us_muni": { + "frequency": "s", + "stub": "shortfront", + "eom": True, + "modifier": "none", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "30u360", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 1, + "calc_mode": "us_muni", + }, + "us_gb_tsy": { + "frequency": "s", + "stub": "shortfront", + "eom": True, + "modifier": "none", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "actacticma", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 1, + "calc_mode": "us_gb_tsy", + }, + "uk_gb": { + "frequency": "s", + "stub": "longfront", + "eom": False, + "modifier": "none", + "calendar": "ldn", + "payment_lag": 0, + "currency": "gbp", + "convention": "actacticma", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 7, + "calc_mode": "uk_gb", + }, + "nz_gb": { + "frequency": "s", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "wlg", + "payment_lag": 0, + "currency": "nzd", + "convention": "actacticma", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 8, + "calc_mode": "nz_gb", + }, + "de_gb": { + "frequency": "a", + "stub": "longfront", + "eom": False, + "modifier": "none", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "actacticma", + "payment_lag_exchange": 0, + "settle": 2, + "ex_div": 1, + "calc_mode": "de_gb", + }, + "fr_gb": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "actacticma", + "payment_lag_exchange": 0, + "settle": 2, + "ex_div": 1, + "calc_mode": "fr_gb", + }, + "nl_gb": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "actacticma", + "payment_lag_exchange": 0, + "settle": 2, + "ex_div": 1, + "calc_mode": "nl_gb", + }, + "it_gb": { + "frequency": "s", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "actacticma", + "payment_lag_exchange": 0, + "settle": 2, + "ex_div": 1, + "calc_mode": "it_gb", + }, + "ch_gb": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "zur", + "payment_lag": 0, + "currency": "chf", + "convention": "30e360", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 1, + "calc_mode": "ch_gb", + }, + "se_gb": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "stk", + "payment_lag": 0, + "currency": "sek", + "convention": "actacticma", + "payment_lag_exchange": 0, + "settle": 2, + "ex_div": 5, + "calc_mode": "se_gb", + }, + "no_gb": { + "frequency": "a", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "osl", + "payment_lag": 0, + "currency": "nok", + "convention": "actacticma_stub365f", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 1, + "calc_mode": "no_gb", + }, + "ca_gb": { + "frequency": "s", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "tro", + "payment_lag": 0, + "currency": "cad", + "convention": "actacticma_stub365f", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 1, + "calc_mode": "ca_gb", + }, + "ca_gbi": { + "frequency": "s", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "tro", + "payment_lag": 0, + "currency": "cad", + "convention": "actacticma_stub365f", + "payment_lag_exchange": 0, + "index_method": "daily", + "index_lag": 3, + "settle": 1, + "ex_div": 1, + "calc_mode": "ca_gb", + }, + "us_gbb": { + "eom": True, + "modifier": "none", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "act360", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 0, + "calc_mode": "us_gbb", + }, + "se_gbb": { + "eom": False, + "modifier": "none", + "calendar": "stk", + "payment_lag": 0, + "currency": "sek", + "convention": "act360", + "payment_lag_exchange": 0, + "settle": 2, + "ex_div": 0, + "calc_mode": "se_gbb", + }, + "no_gbb": { + "eom": False, + "modifier": "none", + "calendar": "osl", + "payment_lag": 0, + "currency": "nok", + "convention": "act365f", + "payment_lag_exchange": 0, + "settle": 2, + "ex_div": 0, + "calc_mode": "no_gbb", + }, + "uk_gbb": { + "eom": True, + "modifier": "none", + "calendar": "ldn", + "payment_lag": 0, + "currency": "gbp", + "convention": "act365f", + "payment_lag_exchange": 0, + "settle": 1, + "ex_div": 0, + "calc_mode": "uk_gbb", + }, + "uk_gbi": { + "frequency": "s", + "stub": "shortfront", + "eom": False, + "modifier": "none", + "calendar": "ldn", + "payment_lag": 0, + "currency": "gbp", + "convention": "actacticma", + "payment_lag_exchange": 0, + "index_method": "daily", + "index_lag": 3, + "settle": 1, + "ex_div": 7, + "calc_mode": "uk_gb", + }, + "sek_fra3": { + "termination": "3m", + "frequency": "q", + "eom": False, + "modifier": "mf", + "calendar": "stk", + "payment_lag": 0, + "currency": "sek", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "eur_fra3": { + "termination": "3m", + "frequency": "q", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "eur_fra6": { + "termination": "6m", + "frequency": "s", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "eur_fra1": { + "termination": "1m", + "frequency": "m", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "nok_fra3": { + "termination": "3m", + "frequency": "q", + "eom": False, + "modifier": "mf", + "calendar": "osl", + "payment_lag": 0, + "currency": "nok", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "nok_fra6": { + "termination": "6m", + "frequency": "s", + "eom": False, + "modifier": "mf", + "calendar": "osl", + "payment_lag": 0, + "currency": "nok", + "convention": "act360", + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + }, + "usd_frn5": { + "frequency": "q", + "eom": False, + "modifier": "mf", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "act360", + "spread_compound_method": "none_simple", + "fixing_method": "rfr_observation_shift(5)", + "settle": 1, + "ex_div": 1, + }, + "usd_stir": { + "frequency": "q", + "roll": "imm", + "eom": False, + "modifier": "mf", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "actacticma", + "nominal": 1000000.0, + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixing_series": "usd_rfr", + }, + "usd_stir1": { + "frequency": "m", + "roll": "som", + "eom": False, + "modifier": "mf", + "calendar": "nyc", + "payment_lag": 0, + "currency": "usd", + "convention": "actacticma", + "nominal": 5000400.0, + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay_avg", + "leg2_fixing_series": "usd_rfr", + }, + "eur_stir": { + "frequency": "q", + "roll": "imm", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "actacticma", + "nominal": 1000000.0, + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixing_series": "eur_rfr", + }, + "eur_stir1": { + "frequency": "m", + "roll": "som", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "actacticma", + "nominal": 3000000.0, + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay_avg", + "leg2_fixing_series": "eur_rfr", + }, + "eur_stir3": { + "frequency": "q", + "roll": "imm", + "eom": False, + "modifier": "mf", + "calendar": "tgt", + "payment_lag": 0, + "currency": "eur", + "convention": "actacticma", + "nominal": 1000000.0, + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "ibor(2)", + "leg2_fixing_series": "eur_ibor", + }, + "gbp_stir": { + "frequency": "q", + "roll": "imm", + "eom": False, + "modifier": "mf", + "calendar": "ldn", + "payment_lag": 0, + "currency": "gbp", + "convention": "actacticma", + "nominal": 1000000.0, + "leg2_spread_compound_method": "none_simple", + "leg2_fixing_method": "rfr_payment_delay", + "leg2_fixing_series": "gbp_rfr", + }, + "uk_gb_2y": { + "calendar": "ldn", + "currency": "gbp", + "calc_mode": "ice_gbp", + "nominal": 100000.0, + "coupon": 3.0, + }, + "uk_gb_5y": { + "calendar": "ldn", + "currency": "gbp", + "calc_mode": "ice_gbp", + "nominal": 100000.0, + "coupon": 4.0, + }, + "uk_gb_10y": { + "calendar": "ldn", + "currency": "gbp", + "calc_mode": "ice_gbp", + "nominal": 100000.0, + "coupon": 4.0, + }, + "uk_gb_30y": { + "calendar": "ldn", + "currency": "gbp", + "calc_mode": "ice_gbp", + "nominal": 100000.0, + "coupon": 4.0, + }, + "us_gb_2y": { + "calendar": "fed", + "currency": "usd", + "calc_mode": "ust_short", + "nominal": 200000.0, + "coupon": 6.0, + }, + "us_gb_3y": { + "calendar": "fed", + "currency": "usd", + "calc_mode": "ust_short", + "nominal": 200000.0, + "coupon": 6.0, + }, + "us_gb_5y": { + "calendar": "fed", + "currency": "usd", + "calc_mode": "ust_short", + "nominal": 100000.0, + "coupon": 6.0, + }, + "us_gb_10y": { + "calendar": "fed", + "currency": "usd", + "calc_mode": "ust_long", + "nominal": 100000.0, + "coupon": 6.0, + }, + "us_gb_30y": { + "calendar": "fed", + "currency": "usd", + "calc_mode": "ust_long", + "nominal": 100000.0, + "coupon": 6.0, + }, + "de_gb_2y": { + "calendar": "tgt", + "currency": "eur", + "calc_mode": "eurex_eur", + "nominal": 100000.0, + "coupon": 6.0, + }, + "de_gb_5y": { + "calendar": "tgt", + "currency": "eur", + "calc_mode": "eurex_eur", + "nominal": 100000.0, + "coupon": 6.0, + }, + "de_gb_10y": { + "calendar": "tgt", + "currency": "eur", + "calc_mode": "eurex_eur", + "nominal": 100000.0, + "coupon": 6.0, + }, + "de_gb_30y": { + "calendar": "tgt", + "currency": "eur", + "calc_mode": "eurex_eur", + "nominal": 100000.0, + "coupon": 4.0, + }, + "fr_gb_5y": { + "calendar": "tgt", + "currency": "eur", + "calc_mode": "eurex_eur", + "nominal": 100000.0, + "coupon": 6.0, + }, + "fr_gb_10y": { + "calendar": "tgt", + "currency": "eur", + "calc_mode": "eurex_eur", + "nominal": 100000.0, + "coupon": 6.0, + }, + "sp_gb_10y": { + "calendar": "tgt", + "currency": "eur", + "calc_mode": "eurex_eur", + "nominal": 100000.0, + "coupon": 6.0, + }, + "ch_gb_10y": { + "calendar": "zur", + "currency": "chf", + "calc_mode": "eurex_chf", + "nominal": 100000.0, + "coupon": 6.0, + }, +} + +if DEVELOPMENT == "True": # DEVELOPMENT mode is used to load and create instrument specs from a CSV file. # This is loaded by default and slower to parse than directly creating a dict # So when packaging output the INSTRUMENT_SPEC dict and paste into the non-development # section. - def _append_kwargs_name(df: DataFrame) -> DataFrame: - """combine the columns leg and kwargs to produce library consistent kwargs for dicts""" - prefix = df["leg"] - prefix = prefix.where(prefix == "leg2", "") - prefix = prefix.replace("leg2", "leg2_") - df["kwargs_name"] = prefix + df["kwarg"] - return df.set_index("kwargs_name") - - def _parse_bool(df: DataFrame) -> DataFrame: - """parse data input as bools to return True and False dtypes.""" - - def _map_true_false(v: str) -> bool | None: - try: - if v.upper() == "TRUE": - return True - elif v.upper() == "FALSE": - return False - except AttributeError: - return None - else: - return None - - if version.parse(pd.__version__) >= version.parse("2.1.0"): - # applymap issues a deprecation warning with version <2.1.0 - # TODO (low): clean this up when setting a minimum pandas version at 2.1.0 - df[df["dtype"] == "bool"] = df[df["dtype"] == "bool"].map(_map_true_false) - else: - df[df["dtype"] == "bool"] = df[df["dtype"] == "bool"].applymap(_map_true_false) # type: ignore[operator, index] - return df + if version.parse(pd.__version__) < version.parse("3.0.0"): + raise RuntimeError( + "Development of instrument `spec` loading from CSV should be handled by pandas >= 3.0." + "To avoid development mode set DEVELOPMENT=False." + ) path = "data/__instrument_spec.csv" abspath = os.path.dirname(os.path.abspath(__file__)) target = os.path.join(abspath, path) - df = pd.read_csv(target) - df = _append_kwargs_name(df) - df = _parse_bool(df) - df_legs = df[~(df["leg"] == "meta")] + df2 = pd.read_csv(target, header=[0, 1, 2, 3], index_col=[0]) - DTYPE_MAP = { - "str": str, - "float": float, - "bool": bool, - "int": int, - } + for column in df2.columns: + df2[column] = df2[column].astype(column[3]) # type: ignore[call-overload] + df2_legs = df2.loc[:, (slice(None), ["leg1", "leg2"])] - def _map_dtype(v: str) -> Any: + INSTRUMENT_SPECS = {} + for spec in df2_legs.index: + leg1 = df2_legs.loc[spec].dropna().droplevel([0, 3]).loc["leg1"].to_dict() try: - return DTYPE_MAP[v] + leg2 = df2_legs.loc[spec].dropna().droplevel([0, 3]).loc["leg2"].to_dict() except KeyError: - return v + leg2 = {} + INSTRUMENT_SPECS.update({spec: {**leg1, **{f"leg2_{k}": v for k, v in leg2.items()}}}) - def _map_str_int(v: Any) -> Any: + # extra dtype conversion mappings for keys + def _map_str_float_int(v: Any) -> Any: try: - return int(v) - except ValueError: + return int(float(v)) + except (ValueError, TypeError): return v - def _get_kwargs(spec: str) -> dict[str, Any]: - """From the legs DataFrame extract the relevant column and ensure dtypes are suitable.""" - # get values that are not null - s = df_legs[spec] - s = s[pd.notna(s)] - # assign the correct dtypes for the values - dfs = s.to_frame().transpose() - dtypes = df.loc[s.index, "dtype"] - dtypes = dtypes.map(_map_dtype) - dfs = dfs.astype(dtype=dtypes.to_dict(), errors="raise") - # rotate and return values in a dict - s = dfs.transpose()[spec] - d = s.to_dict() - - # roll dtype is str or int causes object issues - if "roll" in d: - d["roll"] = _map_str_int(d["roll"]) - if "leg2_roll" in d: - d["leg2_roll"] = _map_str_int(d["leg2_roll"]) - return d # type: ignore[return-value] - - INSTRUMENT_SPECS = {k: _get_kwargs(k) for k in df.columns[4:]} - -else: - # This is output from a development version and hard coded before a release for performance. - INSTRUMENT_SPECS = { - "test": { - "frequency": "m", - "stub": "longfront", - "eom": False, - "modifier": "p", - "calendar": "nyc,tgt,ldn", - "payment_lag": 4, - "currency": "tes", - "convention": "yearsmonths", - "leg2_frequency": "m", - "leg2_stub": "longback", - "leg2_roll": 1, - "leg2_eom": False, - "leg2_modifier": "mp", - "leg2_calendar": "nyc,tgt,ldn", - "leg2_payment_lag": 3, - "leg2_convention": "one", - }, - "eurusd_call": { - "modifier": "mf", - "calendar": "tgt|fed", - "payment_lag": 2, - "pair": "eurusd", - "delivery_lag": 2, - }, - "us_ig_cds": { - "frequency": "q", - "stub": "shortfront", - "roll": 20, - "eom": False, - "modifier": "fex", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "act360", - "fixed_rate": 1.0, - }, - "inr_ndirs": { - "frequency": "s", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "mum", - "payment_lag": 0, - "currency": "usd", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "pair": "usdinr", - }, - "inrusd_ndxcs": { - "frequency": "s", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "mum|fed", - "payment_lag": 2, - "currency": "usd", - "convention": "act365f", - "leg2_convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "fixed": True, - "pair": "usdinr", - }, - "usd_irs": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "nyc", - "payment_lag": 2, - "currency": "usd", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "usd_irs_lt_2y": { - "frequency": "a", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "nyc", - "payment_lag": 2, - "currency": "usd", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "gbp_irs": { - "frequency": "a", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "ldn", - "payment_lag": 0, - "currency": "gbp", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "eur_irs": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 1, - "currency": "eur", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "sek_irs": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "stk", - "payment_lag": 1, - "currency": "sek", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "nok_irs": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "osl", - "payment_lag": 2, - "currency": "nok", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "chf_irs": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "zur", - "payment_lag": 2, - "currency": "chf", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "cad_irs": { - "frequency": "s", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "tro", - "payment_lag": 1, - "currency": "cad", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "cad_irs_le_1y": { - "frequency": "a", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "tro", - "payment_lag": 1, - "currency": "cad", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "jpy_irs": { - "frequency": "a", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "tyo", - "payment_lag": 2, - "currency": "jpy", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "nzd_irs3": { - "frequency": "s", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "wlg", - "payment_lag": 0, - "currency": "nzd", - "convention": "act365f", - "leg2_frequency": "q", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 0, - }, - "nzd_irs6": { - "frequency": "s", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "wlg", - "payment_lag": 0, - "currency": "nzd", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 0, - }, - "nzd_irs": { - "frequency": "a", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "wlg", - "payment_lag": 2, - "currency": "nzd", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - }, - "aud_irs6": { - "frequency": "s", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "syd", - "payment_lag": 0, - "currency": "aud", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 0, - }, - "aud_irs3": { - "frequency": "q", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "syd", - "payment_lag": 0, - "currency": "aud", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 0, - }, - "aud_irs3_gt_3y": { - "frequency": "s", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "syd", - "payment_lag": 0, - "currency": "aud", - "convention": "act365f", - "leg2_frequency": "q", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 0, - }, - "aud_irs": { - "frequency": "a", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "syd", - "payment_lag": 2, - "currency": "aud", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "eur_irs6": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "30e360", - "leg2_frequency": "s", - "leg2_convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "eur_irs3": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "30e360", - "leg2_frequency": "q", - "leg2_convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "eur_irs1": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "30e360", - "leg2_frequency": "m", - "leg2_convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "sek_irs3": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "stk", - "payment_lag": 0, - "currency": "sek", - "convention": "30e360", - "leg2_frequency": "q", - "leg2_convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "nok_irs3": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "osl", - "payment_lag": 0, - "currency": "nok", - "convention": "30e360", - "leg2_frequency": "q", - "leg2_convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "nok_irs6": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "osl", - "payment_lag": 0, - "currency": "nok", - "convention": "30e360", - "leg2_frequency": "s", - "leg2_convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "eurusd_xcs": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "tgt,nyc", - "payment_lag": 2, - "currency": "eur", - "convention": "act360", - "spread_compound_method": "none_simple", - "fixing_method": "rfr_payment_delay", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "payment_lag_exchange": 0, - "fixed": False, - "leg2_fixed": False, - "leg2_mtm": True, - "pair": "eurusd", - }, - "gbpusd_xcs": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "ldn,nyc", - "payment_lag": 2, - "currency": "gbp", - "convention": "act365f", - "leg2_convention": "act360", - "spread_compound_method": "none_simple", - "fixing_method": "rfr_payment_delay", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "payment_lag_exchange": 0, - "fixed": False, - "leg2_fixed": False, - "leg2_mtm": True, - "pair": "gbpusd", - }, - "eurgbp_xcs": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "tgt,ldn", - "payment_lag": 2, - "currency": "eur", - "convention": "act360", - "leg2_convention": "act365f", - "spread_compound_method": "none_simple", - "fixing_method": "rfr_payment_delay", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "payment_lag_exchange": 0, - "fixed": False, - "leg2_fixed": False, - "leg2_mtm": True, - "pair": "eurgbp", - }, - "gbpeur_xcs": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "tgt,ldn", - "payment_lag": 2, - "currency": "gbp", - "convention": "act365f", - "leg2_convention": "act360", - "spread_compound_method": "none_simple", - "fixing_method": "rfr_payment_delay", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "payment_lag_exchange": 0, - "fixed": False, - "leg2_fixed": False, - "leg2_mtm": True, - "pair": "eurgbp", - }, - "jpyusd_xcs": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "nyc,tyo", - "payment_lag": 2, - "currency": "jpy", - "convention": "act365f", - "leg2_convention": "act360", - "spread_compound_method": "none_simple", - "fixing_method": "rfr_payment_delay", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "payment_lag_exchange": 0, - "fixed": False, - "leg2_fixed": False, - "leg2_mtm": True, - "pair": "usdjpy", - }, - "audusd_xcs3": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "nyc,syd", - "payment_lag": 2, - "currency": "aud", - "convention": "act365f", - "leg2_convention": "act360", - "spread_compound_method": "none_simple", - "fixing_method": "ibor", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "payment_lag_exchange": 0, - "fixed": False, - "leg2_fixed": False, - "leg2_mtm": True, - "pair": "audusd", - }, - "audusd_xcs": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "nyc,syd", - "payment_lag": 2, - "currency": "aud", - "convention": "act365f", - "leg2_convention": "act360", - "spread_compound_method": "none_simple", - "fixing_method": "rfr_payment_delay", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "payment_lag_exchange": 0, - "fixed": False, - "leg2_fixed": False, - "leg2_mtm": True, - "pair": "audusd", - }, - "nzdusd_xcs3": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "nyc,wlg", - "payment_lag": 2, - "currency": "nzd", - "convention": "act365f", - "leg2_convention": "act360", - "spread_compound_method": "none_simple", - "fixing_method": "ibor", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "payment_lag_exchange": 0, - "fixed": False, - "leg2_fixed": False, - "leg2_mtm": True, - "pair": "nzdusd", - }, - "nzdaud_xcs3": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "nyc,wlg,syd", - "payment_lag": 2, - "currency": "nzd", - "convention": "act365f", - "leg2_convention": "act365f", - "spread_compound_method": "none_simple", - "fixing_method": "ibor", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 0, - "payment_lag_exchange": 0, - "fixed": False, - "leg2_fixed": False, - "leg2_mtm": True, - "pair": "audnzd", - }, - "eur_zcis": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "1+", - "leg2_index_method": "monthly", - "leg2_index_lag": 3, - }, - "gbp_zcis": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "ldn", - "payment_lag": 0, - "currency": "gbp", - "convention": "1+", - "leg2_index_method": "monthly", - "leg2_index_lag": 2, - }, - "usd_zcis": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "1+", - "leg2_index_method": "daily", - "leg2_index_lag": 3, - }, - "gbp_zcs": { - "frequency": "a", - "stub": "shortfront", - "eom": True, - "modifier": "mf", - "calendar": "ldn", - "payment_lag": 0, - "currency": "gbp", - "convention": "act365f", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - }, - "sek_iirs": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "none", - "calendar": "stk", - "payment_lag": 0, - "currency": "sek", - "convention": "actacticma", - "leg2_frequency": "q", - "leg2_convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - "index_method": "daily", - "index_lag": 3, - }, - "eur_sbs36": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "act360", - "leg2_frequency": "s", - "spread_compound_method": "none_simple", - "fixing_method": "ibor", - "method_param": 2, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "nok_sbs36": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "osl", - "payment_lag": 0, - "currency": "nok", - "convention": "act360", - "leg2_frequency": "s", - "spread_compound_method": "none_simple", - "fixing_method": "ibor", - "method_param": 2, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "aud_sbs36": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "syd", - "payment_lag": 0, - "currency": "aud", - "convention": "act365f", - "leg2_frequency": "s", - "spread_compound_method": "none_simple", - "fixing_method": "ibor", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 0, - }, - "aud_sbs31": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "syd", - "payment_lag": 0, - "currency": "aud", - "convention": "act365f", - "leg2_frequency": "m", - "spread_compound_method": "none_simple", - "fixing_method": "ibor", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 0, - }, - "nzd_sbs36": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "wlg", - "payment_lag": 0, - "currency": "nzd", - "convention": "act365f", - "leg2_frequency": "s", - "spread_compound_method": "none_simple", - "fixing_method": "ibor", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 0, - }, - "nzd_sbs31": { - "frequency": "q", - "stub": "shortfront", - "eom": False, - "modifier": "mf", - "calendar": "wlg", - "payment_lag": 0, - "currency": "nzd", - "convention": "act365f", - "leg2_frequency": "m", - "spread_compound_method": "none_simple", - "fixing_method": "ibor", - "method_param": 0, - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 0, - }, - "us_gb": { - "frequency": "s", - "stub": "shortfront", - "eom": True, - "modifier": "none", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "actacticma", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 1, - "calc_mode": "us_gb", - }, - "us_gbi": { - "frequency": "s", - "stub": "shortfront", - "eom": True, - "modifier": "none", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "actacticma", - "payment_lag_exchange": 0, - "index_method": "daily", - "index_lag": 3, - "settle": 1, - "ex_div": 1, - "calc_mode": "us_gb", - }, - "us_corp": { - "frequency": "s", - "stub": "shortfront", - "eom": True, - "modifier": "none", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "30u360", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 1, - "calc_mode": "us_corp", - }, - "us_muni": { - "frequency": "s", - "stub": "shortfront", - "eom": True, - "modifier": "none", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "30u360", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 1, - "calc_mode": "us_muni", - }, - "us_gb_tsy": { - "frequency": "s", - "stub": "shortfront", - "eom": True, - "modifier": "none", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "actacticma", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 1, - "calc_mode": "us_gb_tsy", - }, - "uk_gb": { - "frequency": "s", - "stub": "longfront", - "eom": False, - "modifier": "none", - "calendar": "ldn", - "payment_lag": 0, - "currency": "gbp", - "convention": "actacticma", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 7, - "calc_mode": "uk_gb", - }, - "nz_gb": { - "frequency": "s", - "stub": "shortfront", - "eom": False, - "modifier": "none", - "calendar": "wlg", - "payment_lag": 0, - "currency": "nzd", - "convention": "actacticma", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 8, - "calc_mode": "nz_gb", - }, - "de_gb": { - "frequency": "a", - "stub": "longfront", - "eom": False, - "modifier": "none", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "actacticma", - "payment_lag_exchange": 0, - "settle": 2, - "ex_div": 1, - "calc_mode": "de_gb", - }, - "fr_gb": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "none", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "actacticma", - "payment_lag_exchange": 0, - "settle": 2, - "ex_div": 1, - "calc_mode": "fr_gb", - }, - "nl_gb": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "none", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "actacticma", - "payment_lag_exchange": 0, - "settle": 2, - "ex_div": 1, - "calc_mode": "nl_gb", - }, - "it_gb": { - "frequency": "s", - "stub": "shortfront", - "eom": False, - "modifier": "none", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "actacticma", - "payment_lag_exchange": 0, - "settle": 2, - "ex_div": 1, - "calc_mode": "it_gb", - }, - "ch_gb": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "none", - "calendar": "zur", - "payment_lag": 0, - "currency": "chf", - "convention": "30e360", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 1, - "calc_mode": "ch_gb", - }, - "se_gb": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "none", - "calendar": "stk", - "payment_lag": 0, - "currency": "sek", - "convention": "actacticma", - "payment_lag_exchange": 0, - "settle": 2, - "ex_div": 5, - "calc_mode": "se_gb", - }, - "no_gb": { - "frequency": "a", - "stub": "shortfront", - "eom": False, - "modifier": "none", - "calendar": "osl", - "payment_lag": 0, - "currency": "nok", - "convention": "actacticma_stub365f", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 1, - "calc_mode": "no_gb", - }, - "ca_gb": { - "frequency": "s", - "stub": "shortfront", - "eom": False, - "modifier": "none", - "calendar": "tro", - "payment_lag": 0, - "currency": "cad", - "convention": "actacticma_stub365f", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 1, - "calc_mode": "ca_gb", - }, - "us_gbb": { - "eom": True, - "modifier": "none", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "act360", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 0, - "calc_mode": "us_gbb", - }, - "se_gbb": { - "eom": False, - "modifier": "none", - "calendar": "stk", - "payment_lag": 0, - "currency": "sek", - "convention": "act360", - "payment_lag_exchange": 0, - "settle": 2, - "ex_div": 0, - "calc_mode": "se_gbb", - }, - "uk_gbb": { - "eom": True, - "modifier": "none", - "calendar": "ldn", - "payment_lag": 0, - "currency": "gbp", - "convention": "act365f", - "payment_lag_exchange": 0, - "settle": 1, - "ex_div": 0, - "calc_mode": "uk_gbb", - }, - "uk_gbi": { - "frequency": "s", - "stub": "shortfront", - "eom": False, - "modifier": "none", - "calendar": "ldn", - "payment_lag": 0, - "currency": "gbp", - "convention": "actacticma", - "payment_lag_exchange": 0, - "index_method": "daily", - "index_lag": 3, - "settle": 1, - "ex_div": 7, - "calc_mode": "uk_gb", - }, - "sek_fra3": { - "termination": "3m", - "frequency": "q", - "eom": False, - "modifier": "mf", - "calendar": "stk", - "payment_lag": 0, - "currency": "sek", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "eur_fra3": { - "termination": "3m", - "frequency": "q", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "eur_fra6": { - "termination": "6m", - "frequency": "s", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "eur_fra1": { - "termination": "1m", - "frequency": "m", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "nok_fra3": { - "termination": "3m", - "frequency": "q", - "eom": False, - "modifier": "mf", - "calendar": "osl", - "payment_lag": 0, - "currency": "nok", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "nok_fra6": { - "termination": "6m", - "frequency": "s", - "eom": False, - "modifier": "mf", - "calendar": "osl", - "payment_lag": 0, - "currency": "nok", - "convention": "act360", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - }, - "usd_frn5": { - "frequency": "q", - "eom": False, - "modifier": "mf", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "act360", - "spread_compound_method": "none_simple", - "fixing_method": "rfr_observation_shift", - "method_param": 5, - "settle": 1, - "ex_div": 1, - }, - "usd_stir": { - "frequency": "q", - "roll": "imm", - "eom": False, - "modifier": "mf", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "actacticma", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "leg2_fixing_series": "usd_rfr", - "nominal": 1000000.0, - }, - "usd_stir1": { - "frequency": "m", - "roll": "som", - "eom": False, - "modifier": "mf", - "calendar": "nyc", - "payment_lag": 0, - "currency": "usd", - "convention": "actacticma", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay_avg", - "leg2_method_param": 0, - "leg2_fixing_series": "usd_rfr", - "nominal": 5000400.0, - }, - "eur_stir": { - "frequency": "q", - "roll": "imm", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "actacticma", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "leg2_fixing_series": "eur_rfr", - "nominal": 1000000.0, - }, - "eur_stir1": { - "frequency": "m", - "roll": "som", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "actacticma", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay_avg", - "leg2_method_param": 0, - "leg2_fixing_series": "eur_rfr", - "nominal": 3000000.0, - }, - "eur_stir3": { - "frequency": "q", - "roll": "imm", - "eom": False, - "modifier": "mf", - "calendar": "tgt", - "payment_lag": 0, - "currency": "eur", - "convention": "actacticma", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "ibor", - "leg2_method_param": 2, - "leg2_fixing_series": "eur_ibor", - "nominal": 1000000.0, - }, - "gbp_stir": { - "frequency": "q", - "roll": "imm", - "eom": False, - "modifier": "mf", - "calendar": "ldn", - "payment_lag": 0, - "currency": "gbp", - "convention": "actacticma", - "leg2_spread_compound_method": "none_simple", - "leg2_fixing_method": "rfr_payment_delay", - "leg2_method_param": 0, - "leg2_fixing_series": "gbp_rfr", - "nominal": 1000000.0, - }, - "uk_gb_2y": { - "calendar": "ldn", - "currency": "gbp", - "calc_mode": "ice_gbp", - "nominal": 100000.0, - "coupon": 3.0, - }, - "uk_gb_5y": { - "calendar": "ldn", - "currency": "gbp", - "calc_mode": "ice_gbp", - "nominal": 100000.0, - "coupon": 4.0, - }, - "uk_gb_10y": { - "calendar": "ldn", - "currency": "gbp", - "calc_mode": "ice_gbp", - "nominal": 100000.0, - "coupon": 4.0, - }, - "uk_gb_30y": { - "calendar": "ldn", - "currency": "gbp", - "calc_mode": "ice_gbp", - "nominal": 100000.0, - "coupon": 4.0, - }, - "us_gb_2y": { - "calendar": "fed", - "currency": "usd", - "calc_mode": "ust_short", - "nominal": 200000.0, - "coupon": 6.0, - }, - "us_gb_3y": { - "calendar": "fed", - "currency": "usd", - "calc_mode": "ust_short", - "nominal": 200000.0, - "coupon": 6.0, - }, - "us_gb_5y": { - "calendar": "fed", - "currency": "usd", - "calc_mode": "ust_short", - "nominal": 100000.0, - "coupon": 6.0, - }, - "us_gb_10y": { - "calendar": "fed", - "currency": "usd", - "calc_mode": "ust_long", - "nominal": 100000.0, - "coupon": 6.0, - }, - "us_gb_30y": { - "calendar": "fed", - "currency": "usd", - "calc_mode": "ust_long", - "nominal": 100000.0, - "coupon": 6.0, - }, - "de_gb_2y": { - "calendar": "tgt", - "currency": "eur", - "calc_mode": "eurex_eur", - "nominal": 100000.0, - "coupon": 6.0, - }, - "de_gb_5y": { - "calendar": "tgt", - "currency": "eur", - "calc_mode": "eurex_eur", - "nominal": 100000.0, - "coupon": 6.0, - }, - "de_gb_10y": { - "calendar": "tgt", - "currency": "eur", - "calc_mode": "eurex_eur", - "nominal": 100000.0, - "coupon": 6.0, - }, - "de_gb_30y": { - "calendar": "tgt", - "currency": "eur", - "calc_mode": "eurex_eur", - "nominal": 100000.0, - "coupon": 4.0, - }, - "fr_gb_5y": { - "calendar": "tgt", - "currency": "eur", - "calc_mode": "eurex_eur", - "nominal": 100000.0, - "coupon": 6.0, - }, - "fr_gb_10y": { - "calendar": "tgt", - "currency": "eur", - "calc_mode": "eurex_eur", - "nominal": 100000.0, - "coupon": 6.0, - }, - "sp_gb_10y": { - "calendar": "tgt", - "currency": "eur", - "calc_mode": "eurex_eur", - "nominal": 100000.0, - "coupon": 6.0, - }, - "ch_gb_10y": { - "calendar": "zur", - "currency": "chf", - "calc_mode": "eurex_chf", - "nominal": 100000.0, - "coupon": 6.0, - }, + _maps = { + "roll": _map_str_float_int, + "leg2_roll": _map_str_float_int, } + + for _, v in INSTRUMENT_SPECS.items(): + for k2, v2 in v.items(): + if k2 in _maps: + v[k2] = _maps[k2](v2) diff --git a/python/rateslib/curves/_parsers.py b/python/rateslib/curves/_parsers.py index 892274733..11b23a2f5 100644 --- a/python/rateslib/curves/_parsers.py +++ b/python/rateslib/curves/_parsers.py @@ -23,7 +23,7 @@ from rateslib.enums.generics import Err, NoInput, Ok if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurveInput, CurveInput_, CurveOption, diff --git a/python/rateslib/curves/academic/ns.py b/python/rateslib/curves/academic/ns.py index cd4670b40..c7ad226b5 100644 --- a/python/rateslib/curves/academic/ns.py +++ b/python/rateslib/curves/academic/ns.py @@ -26,7 +26,7 @@ from rateslib.scheduling.convention import _get_convention if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CalInput, DualTypes, diff --git a/python/rateslib/curves/academic/nss.py b/python/rateslib/curves/academic/nss.py index 4cd28e09e..7e251895f 100644 --- a/python/rateslib/curves/academic/nss.py +++ b/python/rateslib/curves/academic/nss.py @@ -26,7 +26,7 @@ from rateslib.scheduling.convention import _get_convention if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CalInput, DualTypes, diff --git a/python/rateslib/curves/academic/sw.py b/python/rateslib/curves/academic/sw.py index 59dd12bd4..542c9d68f 100644 --- a/python/rateslib/curves/academic/sw.py +++ b/python/rateslib/curves/academic/sw.py @@ -8,12 +8,12 @@ from __future__ import annotations +from datetime import timezone from functools import cached_property from typing import TYPE_CHECKING from uuid import uuid4 import numpy as np -from pytz import UTC from rateslib import defaults from rateslib.curves import ( @@ -34,7 +34,7 @@ from numpy import object_ as Nobject # noqa: N812 from numpy.typing import NDArray - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, DualTypes, Variable, @@ -45,6 +45,9 @@ ) +UTC = timezone.utc + + class _NullInterpolator: def _csolve(self, curve_type: _CurveType, nodes: _CurveNodes, ad: int) -> None: pass diff --git a/python/rateslib/curves/curves.py b/python/rateslib/curves/curves.py index 87178e0b8..3eece1a2c 100644 --- a/python/rateslib/curves/curves.py +++ b/python/rateslib/curves/curves.py @@ -18,14 +18,13 @@ from abc import ABC, abstractmethod from calendar import monthrange from dataclasses import replace -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from math import comb, prod from typing import TYPE_CHECKING, TypeAlias from uuid import uuid4 import numpy as np from pandas import Series -from pytz import UTC import rateslib.errors as err from rateslib import defaults, fixings @@ -57,7 +56,7 @@ from rateslib.scheduling.convention import _get_convention if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CalInput, CurveOption_, @@ -70,6 +69,8 @@ str_, ) +UTC = timezone.utc + DualTypes: TypeAlias = ( "Dual | Dual2 | Variable | float" # required for non-cyclic import on _WithCache ) @@ -275,7 +276,8 @@ def __getitem__(self, date: datetime) -> DualTypes: "Evaluating points on a curve beyond the endpoint of the basic " "spline interval is undefined.\n" f"date: {date.strftime('%Y-%m-%d')}, spline end: " - f"{self.interpolator.spline.t[-1].strftime('%Y-%m-%d')}\n" + f"{self.interpolator.spline.t[-1].strftime('%Y-%m-%d')}, curve id: " + f"'{self.id}'\n" "This often occurs when a curve is constructed with a final node date " "that aligns with the maturity of an instrument with a payment lag.\nIn the " "case that the instrument has a payment lag (e.g. a SOFR swap or ESTR swap or " @@ -1812,7 +1814,7 @@ class Curve(_WithMutability, _BaseCurve): modifier : str, optional The modification rule, in {"F", "MF", "P", "MP"}, for determining rates when input as a tenor, e.g. "3M". - calendar : calendar or str, optional + calendar : Cal, UnionCal, NamedCal, str, optional The holiday calendar object to use. If str, looks up named calendar from static data. Used for determining rates. ad : int in {0, 1, 2}, optional @@ -1971,7 +1973,7 @@ class LineCurve(_WithMutability, _BaseCurve): modifier : str, optional The modification rule, in {"F", "MF", "P", "MP"}, for determining rates when input as a tenor, e.g. "3M". - calendar : calendar or str, optional + calendar : Cal, UnionCal, NamedCal, str, optional The holiday calendar object to use. If str, looks up named calendar from static data. Used for determining rates. ad : int in {0, 1, 2}, optional diff --git a/python/rateslib/curves/interpolation.py b/python/rateslib/curves/interpolation.py index 7e4c9c8c3..8ad5fff4e 100644 --- a/python/rateslib/curves/interpolation.py +++ b/python/rateslib/curves/interpolation.py @@ -12,17 +12,19 @@ from __future__ import annotations +from datetime import timezone from math import floor from typing import TYPE_CHECKING, Protocol -from pytz import UTC - from rateslib.dual import dual_exp, dual_log from rateslib.rs import index_left_f64 from rateslib.scheduling import Convention, dcf if TYPE_CHECKING: - from rateslib.typing import Any, DualTypes, _BaseCurve, datetime # pragma: no cover + from rateslib.local_types import Any, DualTypes, _BaseCurve, datetime # pragma: no cover + + +UTC = timezone.utc class InterpolationFunction(Protocol): diff --git a/python/rateslib/curves/rs.py b/python/rateslib/curves/rs.py index 5db5b9f5c..53ffe45b8 100644 --- a/python/rateslib/curves/rs.py +++ b/python/rateslib/curves/rs.py @@ -37,7 +37,7 @@ from rateslib.scheduling.convention import _get_convention if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurveInterpolator, DualTypes, @@ -71,7 +71,7 @@ def __init__( id=_drb(uuid4().hex[:5] + "_", id), # 1 in a million clash convention=_get_convention(_drb(defaults.convention, convention)), modifier=Modifier.ModF, - calendar=get_calendar(calendar, named=True), + calendar=get_calendar(calendar), index_base=_drb(None, index_base), ) diff --git a/python/rateslib/curves/utils.py b/python/rateslib/curves/utils.py index 98d30a483..6cd5677b8 100644 --- a/python/rateslib/curves/utils.py +++ b/python/rateslib/curves/utils.py @@ -14,13 +14,11 @@ import json from dataclasses import dataclass -from datetime import datetime +from datetime import datetime, timezone from enum import Enum from functools import cached_property from typing import TYPE_CHECKING -from pytz import UTC - from rateslib import defaults from rateslib.curves.interpolation import INTERPOLATION, InterpolationFunction from rateslib.dual import dual_log, set_order_convert @@ -31,7 +29,7 @@ from rateslib.splines import PPSplineDual, PPSplineDual2, PPSplineF64 if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Any, CalTypes, DualTypes, @@ -43,6 +41,9 @@ ) # pragma: no cover +UTC = timezone.utc + + class _CurveType(Enum): """ Enumerable type to define the difference between a discount factor (DF) based and diff --git a/python/rateslib/data/__instrument_spec.csv b/python/rateslib/data/__instrument_spec.csv index 9a4301958..c864d375e 100644 --- a/python/rateslib/data/__instrument_spec.csv +++ b/python/rateslib/data/__instrument_spec.csv @@ -1,77 +1,104 @@ -kind,leg,kwarg,dtype,test,eurusd_call,us_ig_cds,inr_ndirs,inrusd_ndxcs,usd_irs,usd_irs_lt_2y,gbp_irs,eur_irs,sek_irs,nok_irs,chf_irs,cad_irs,cad_irs_le_1y,jpy_irs,nzd_irs3,nzd_irs6,nzd_irs,aud_irs6,aud_irs3,aud_irs3_gt_3y,aud_irs,eur_irs6,eur_irs3,eur_irs1,sek_irs3,nok_irs3,nok_irs6,eurusd_xcs,gbpusd_xcs,eurgbp_xcs,gbpeur_xcs,jpyusd_xcs,audusd_xcs3,audusd_xcs,nzdusd_xcs3,nzdaud_xcs3,eur_zcis,gbp_zcis,usd_zcis,gbp_zcs,sek_iirs,eur_sbs36,nok_sbs36,aud_sbs36,aud_sbs31,nzd_sbs36,nzd_sbs31,us_gb,us_gbi,us_corp,us_muni,us_gb_tsy,uk_gb,nz_gb,de_gb,fr_gb,nl_gb,it_gb,ch_gb,se_gb,no_gb,ca_gb,us_gbb,se_gbb,uk_gbb,uk_gbi,sek_fra3,eur_fra3,eur_fra6,eur_fra1,nok_fra3,nok_fra6,usd_frn5,usd_stir,usd_stir1,eur_stir,eur_stir1,eur_stir3,gbp_stir,uk_gb_2y,uk_gb_5y,uk_gb_10y,uk_gb_30y,us_gb_2y,us_gb_3y,us_gb_5y,us_gb_10y,us_gb_30y,de_gb_2y,de_gb_5y,de_gb_10y,de_gb_30y,fr_gb_5y,fr_gb_10y,sp_gb_10y,ch_gb_10y -meta,meta,currency,str,TES,eurusd,usd,inr,inrusd_ndxcs,usd,usd,gbp,eur,sek,nok,chf,cad,cad,jpy,nzd,nzd,nzd,aud,aud,aud,aud,eur,eur,eur,sek,nok,nok,eur/usd,gbp/usd,eur/gbp,gbp/eur,jpy/usd,aud/usd,aud/usd,nzd/usd,nzd/aud,eur,gbp,usd,gbp,sek_iirs,eur,nok,aud,aud,nzd,nzd,usd,usd,usd,usd,usd,gbp,nzd,eur,eur,eur,eur,chf,sek,nok,cad,usd,sek,gbp,gbp,sek,eur,eur,eur,nok,nok,usd,usd,usd,eur,eur,eur,gbp,gbp,gbp,gbp,gbp,usd,usd,usd,usd,usd,eur,eur,eur,eur,eur,eur,eur,chf -meta,meta,instrument,str,none,fx_call,cds,irs,ndxcs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,irs,xcs,xcs,xcs,xcs,xcs,xcs,xcs,xcs,xcs,zcis,zcis,zcis,zcs,iirs,sbs,sbs,sbs,sbs,sbs,sbs,frb,ifrb,frb,frb,frb,frb,frb,frb,frb,frb,frb,frb,frb,frb,frb,bill,bill,bill,ifrb,fra,fra,fra,fra,fra,fra,frn,stir,stir,stir,stir,stir,stir,bf,bf,bf,bf,bf,bf,bf,bf,bf,bf,bf,bf,bf,bf,bf,bf,bf -meta,meta,sub_type,str,none,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -meta,meta,bloomberg_ticker,str,none,,,irswni,IRUSON,usosfr,usosfr,bpsws,eeswe,sksws,nks,sfsnt,cdso,cdso,jyso,ndswap,,,adsw,adsw_q,,adso,eusa,eusw_v3,,sksw,nksw_v3,nksw,euxoqq,bpxoqq,ebxoqq,ebxoqq,jybss,,,,,euswi,bpswit,usswit,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,SFR,SF1,KTR,,ER,SFI,G,G,G,G,US,US,US,US,US,DE,DE,DE,DE,FR,FR,SP,CH -meta,meta,eval,str,none,2b,,1b,2b,2b,2b,0b,2b,2b,2b,2b,1b,1b,2b,2b,2b,2b,1b,1b,2b,1b,2b,2b,2b,2b,2b,2b,2b,2b,2b,2b,2b,,,,,2bx15,0bx15,2b,0b,2b,2b,2b,2b,2b,2b,2b,,,,,,,,,,,,,,,,,,,,,,,,,,,3m SOFR Futures convention,1m Avergaed SOFR Futures,3m ESTR Futures,1m Averaged ESTR futures,Euribor 3m Futures,SONIA 3m Futures,Gilt future,Gilt future,Gilt future,Gilt future,US treasury futures,US treasury futures,US treasury futures,US treasury futures,US treasury futures,Eurex Germany Futures,Eurex Germany Futures,Eurex Germany Futures,Eurex Germany Futures,Eurex France Futures,Eurex France Futures,Eurex Spain Futures,Eurex CHF Futures -meta,meta,description,str,A test column,Currency call option,,NDIRS vs IN000/N Index,NDXCS Fixed/Float vs SOFR,SOFR IRS conventions,SOFR IRS conventions,SONIA IRS conventions,ESTR IRS conventions,SWESTR IRS conventions,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg1,effective,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg1,termination,str,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3m,3m,6m,1m,3m,6m,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg1,frequency,str,m,,q,s,s,a,a,a,a,a,a,a,s,a,a,s,s,a,s,q,s,a,a,a,a,a,a,a,q,q,q,q,q,q,q,q,q,a,a,a,a,a,q,q,q,q,q,q,s,s,s,s,s,s,s,a,a,a,s,a,a,a,s,,,,s,q,q,s,m,q,s,q,q,m,q,m,q,q,,,,,,,,,,,,,,,,, -base_derivative,leg1,stub,str,longfront,,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,longfront,shortfront,longfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,shortfront,,,,shortfront,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg1,front_stub,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg1,back_stub,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg1,roll,,,,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,imm,som,imm,som,imm,imm,,,,,,,,,,,,,,,,, -base_derivative,leg1,eom,bool,FALSE,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,,,,,,,,,,,,,,,,, -base_derivative,leg1,modifier,str,p,mf,fex,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,none,mf,mf,mf,mf,mf,mf,none,none,none,none,none,none,none,none,none,none,none,none,none,none,none,none,none,none,none,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,mf,,,,,,,,,,,,,,,,, -base_derivative,leg1,calendar,str,"nyc,tgt,ldn",tgt|fed,nyc,mum,mum|fed,nyc,nyc,ldn,tgt,stk,osl,zur,tro,tro,tyo,wlg,wlg,wlg,syd,syd,syd,syd,tgt,tgt,tgt,stk,osl,osl,"tgt,nyc","ldn,nyc","tgt,ldn","tgt,ldn","nyc,tyo","nyc,syd","nyc,syd","nyc,wlg","nyc,wlg,syd",tgt,ldn,nyc,ldn,stk,tgt,osl,syd,syd,wlg,wlg,nyc,nyc,nyc,nyc,nyc,ldn,wlg,tgt,tgt,tgt,tgt,zur,stk,osl,tro,nyc,stk,ldn,ldn,stk,tgt,tgt,tgt,osl,osl,nyc,nyc,nyc,tgt,tgt,tgt,ldn,ldn,ldn,ldn,ldn,fed,fed,fed,fed,fed,tgt,tgt,tgt,tgt,tgt,tgt,tgt,zur -base_derivative,leg1,payment_lag,int,4,2,0,0,2,2,2,0,1,1,2,2,1,1,2,0,0,2,0,0,0,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,,,,,,,,,,,,,,,,, -base_derivative,leg1,notional,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg1,currency,str,tes,,usd,usd,usd,usd,usd,gbp,eur,sek,nok,chf,cad,cad,jpy,nzd,nzd,nzd,aud,aud,aud,aud,eur,eur,eur,sek,nok,nok,eur,gbp,eur,gbp,jpy,aud,aud,nzd,nzd,eur,gbp,usd,gbp,sek,eur,nok,aud,aud,nzd,nzd,usd,usd,usd,usd,usd,gbp,nzd,eur,eur,eur,eur,chf,sek,nok,cad,usd,sek,gbp,gbp,sek,eur,eur,eur,nok,nok,usd,usd,usd,eur,eur,eur,gbp,gbp,gbp,gbp,gbp,usd,usd,usd,usd,usd,eur,eur,eur,eur,eur,eur,eur,chf -base_derivative,leg1,amortization,float,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg1,convention,str,yearsmonths,,act360,act365f,act365f,act360,act360,act365f,act360,act360,act365f,act360,act365f,act365f,act365f,act365f,act365f,act365f,act365f,act365f,act365f,act365f,30e360,30e360,30e360,30e360,30e360,30e360,act360,act365f,act360,act365f,act365f,act365f,act365f,act365f,act365f,1+,1+,1+,act365f,actacticma,act360,act360,act365f,act365f,act365f,act365f,actacticma,actacticma,30u360,30u360,actacticma,actacticma,actacticma,actacticma,actacticma,actacticma,actacticma,30e360,actacticma,actacticma_stub365f,actacticma_stub365f,act360,act360,act365f,actacticma,act360,act360,act360,act360,act360,act360,act360,actacticma,actacticma,actacticma,actacticma,actacticma,actacticma,,,,,,,,,,,,,,,,, -base_derivative,leg2,effective,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,termination,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,frequency,str,m,,,,,,,,,,,,,,,q,,,,,q,,s,q,m,q,q,s,,,,,,,,,,,,,,q,s,s,s,m,s,m,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,stub,str,longback,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,front_stub,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,back_stub,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,roll,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,eom,bool,FALSE,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,modifier,str,mp,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,calendar,str,"nyc,tgt,ldn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,payment_lag,int,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,notional,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,currency,str,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,amortization,float,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -base_derivative,leg2,convention,str,one,,,,act360,,,,,,,,,,,,,,,,,,act360,act360,act360,act360,act360,act360,,act360,act365f,act360,act360,act360,act360,act360,act365f,,,,,act360,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -fixed,leg1,fixed_rate,float,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -float,leg1,float_spread,float,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -float,leg1,spread_compound_method,str,,,,,,,,,,,,,,,,,,,,,,,,,,,,,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,,,,,,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,,,,,,,,,,,,,,,,,,,,,,,,,,none_simple,,,,,,,,,,,,,,,,,,,,,,, -float,leg1,fixings,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -float,leg1,fixing_method,str,,,,,,,,,,,,,,,,,,,,,,,,,,,,,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,ibor,rfr_payment_delay,ibor,ibor,,,,,,ibor,ibor,ibor,ibor,ibor,ibor,,,,,,,,,,,,,,,,,,,,,,,,,,rfr_observation_shift,,,,,,,,,,,,,,,,,,,,,,, -float,leg1,method_param,int,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,0,0,0,0,0,0,0,0,,,,,,2,2,0,0,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,,,,,,,,,,,,,,,,,,,, -fixed,leg2,fixed_rate,float,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -float,leg2,float_spread,float,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -float,leg2,spread_compound_method,str,,,,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,,,,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,,,,,,,,,,,,,,,,,,,,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,,none_simple,none_simple,none_simple,none_simple,none_simple,none_simple,,,,,,,,,,,,,,,,, -float,leg2,fixings,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -float,leg2,fixing_method,str,,,,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,ibor,ibor,rfr_payment_delay,ibor,ibor,ibor,rfr_payment_delay,ibor,ibor,ibor,ibor,ibor,ibor,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,rfr_payment_delay,ibor,,,,rfr_payment_delay,ibor,ibor,ibor,ibor,ibor,ibor,ibor,,,,,,,,,,,,,,,,,,,,ibor,ibor,ibor,ibor,ibor,ibor,,rfr_payment_delay,rfr_payment_delay_avg,rfr_payment_delay,rfr_payment_delay_avg,ibor,rfr_payment_delay,,,,,,,,,,,,,,,,, -float,leg2,method_param,int,,,,0,0,0,0,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,,,,0,2,2,2,0,0,0,0,,,,,,,,,,,,,,,,,,,,2,2,2,2,2,2,,0,0,0,0,2,0,,,,,,,,,,,,,,,,, -float,leg2,fixing_series,str,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,usd_rfr,usd_rfr,eur_rfr,eur_rfr,eur_ibor,gbp_rfr,,,,,,,,,,,,,,,,, -exchange,leg1,initial_exchange,bool,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -exchange,leg1,final_exchange,bool,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -exchange,leg2,initial_exchange,bool,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -exchange,leg2,final_exchange,bool,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -exchange,leg1,fx_fixings,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -exchange,leg2,fx_fixings,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -exchange,leg1,payment_lag_exchange,int,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,0,0,0,0,0,0,0,0,,,,,,,,,,,,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -exchange,leg2,payment_lag_exchange,int,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -xcs,leg1,fixed,bool,,,,,TRUE,,,,,,,,,,,,,,,,,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -xcs,leg2,fixed,bool,,,,,,,,,,,,,,,,,,,,,,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -xcs,leg2,mtm,bool,,,,,,,,,,,,,,,,,,,,,,,,,,,,,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -index,leg1,index_method,str,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,daily,,,,,,,,daily,,,,,,,,,,,,,,,,,daily,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -index,leg1,index_fixings,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -index,leg1,index_base,float,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -index,leg1,index_lag,int,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,,3,,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -index,leg2,index_method,str,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,monthly,monthly,daily,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -index,leg2,index_fixings,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -index,leg2,index_base,float,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -index,leg2,index_lag,int,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,2,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -bond,leg1,settle,int,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1,1,1,2,2,2,2,1,2,1,1,1,2,1,1,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, -bond,leg1,ex_div,int,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1,7,8,1,1,1,1,1,5,1,1,0,0,0,7,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, -bond,leg1,calc_mode,str,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,us_gb,us_gb,us_corp,us_muni,us_gb_tsy,uk_gb,nz_gb,de_gb,fr_gb,nl_gb,it_gb,ch_gb,se_gb,no_gb,ca_gb,us_gbb,se_gbb,uk_gbb,uk_gb,,,,,,,,,,,,,,ice_gbp,ice_gbp,ice_gbp,ice_gbp,ust_short,ust_short,ust_short,ust_long,ust_long,eurex_eur,eurex_eur,eurex_eur,eurex_eur,eurex_eur,eurex_eur,eurex_eur,eurex_chf -stir,leg1,nominal,float,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1000000,5000400,1000000,3000000,1000000,1000000,100000,100000,100000,100000,200000,200000,100000,100000,100000,100000,100000,100000,100000,100000,100000,100000,100000 -cds,leg1,premium_accrued,bool,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -bondfuture,leg1,coupon,float,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,4,4,4,6,6,6,6,6,6,6,6,4,6,6,6,6 -fx,leg1,pair,str,,eurusd,,usdinr,usdinr,,,,,,,,,,,,,,,,,,,,,,,,eurusd,gbpusd,eurgbp,eurgbp,usdjpy,audusd,audusd,nzdusd,audnzd,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -fx,leg1,delivery_lag,int,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, \ No newline at end of file +kind,meta,meta,meta,meta,meta,meta,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,base_derivative,fixed,float,float,float,float,fixed,float,float,float,float,float,exchange,exchange,exchange,exchange,exchange,exchange,exchange,exchange,xcs,xcs,xcs,index,index,index,index,index,index,index,index,bond,bond,bond,stir,cds,bondfuture,fx,fx +leg,meta,meta,meta,meta,meta,meta,leg1,leg1,leg1,leg1,leg1,leg1,leg1,leg1,leg1,leg1,leg1,leg1,leg1,leg1,leg1,leg2,leg2,leg2,leg2,leg2,leg2,leg2,leg2,leg2,leg2,leg2,leg2,leg2,leg2,leg2,leg1,leg1,leg1,leg1,leg1,leg2,leg2,leg2,leg2,leg2,leg2,leg1,leg1,leg2,leg2,leg1,leg2,leg1,leg2,leg1,leg2,leg2,leg1,leg1,leg1,leg1,leg2,leg2,leg2,leg2,leg1,leg1,leg1,leg1,leg1,leg1,leg1,leg1 +kwarg,currency,instrument,sub_type,bloomberg_ticker,eval,description,effective,termination,frequency,stub,front_stub,back_stub,roll,eom,modifier,calendar,payment_lag,notional,currency,amortization,convention,effective,termination,frequency,stub,front_stub,back_stub,roll,eom,modifier,calendar,payment_lag,notional,currency,amortization,convention,fixed_rate,float_spread,spread_compound_method,rate_fixings,fixing_method,fixed_rate,float_spread,spread_compound_method,rate_fixings,fixing_method,fixing_series,initial_exchange,final_exchange,initial_exchange,final_exchange,fx_fixings,fx_fixings,payment_lag_exchange,payment_lag_exchange,fixed,fixed,mtm,index_method,index_fixings,index_base,index_lag,index_method,index_fixings,index_base,index_lag,settle,ex_div,calc_mode,nominal,premium_accrued,coupon,pair,delivery_lag +dtype,str,str,str,str,str,str,str,str,str,str,str,str,str,boolean,str,str,Int64,float,str,float,str,str,str,str,str,str,str,str,boolean,str,str,Int64,float,str,float,str,float,float,str,str,str,float,float,str,str,str,str,boolean,boolean,boolean,boolean,str,str,Int64,Int64,boolean,boolean,boolean,str,str,float,Int64,str,str,float,Int64,Int64,Int64,str,float,boolean,float,str,Int64 +test,TES,none,none,none,none,A test column,,,m,longfront,,,,FALSE,p,"nyc,tgt,ldn",4,,tes,,yearsmonths,,,m,longback,,,1,FALSE,mp,"nyc,tgt,ldn",3,,,,one,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +eurusd_call,eurusd,fx_call,,,2b,Currency call option,,,,,,,,,mf,tgt|fed,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,eurusd,2 +us_ig_cds,usd,cds,,,,,,,q,shortfront,,,20,FALSE,fex,nyc,0,,usd,,act360,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +inr_ndirs,inr,irs,,irswni,1b,NDIRS vs IN000/N Index,,,s,shortfront,,,,FALSE,mf,mum,0,,usd,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,usdinr, +inrusd_ndxcs,inrusd_ndxcs,ndxcs,,IRUSON,2b,NDXCS Fixed/Float vs SOFR,,,s,shortfront,,,,FALSE,mf,mum|fed,2,,usd,,act365f,,,,,,,,,,,,,,,act360,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,TRUE,,,,,,,,,,,,,,,,,usdinr, +mxn_irs,mxn,irs,,MPSWF,2b,F-TIIE OIS,,,28d,shortfront,,,,FALSE,f,mex,2,,mxn,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +usd_irs,usd,irs,,usosfr,2b,SOFR IRS conventions,,,a,shortfront,,,,FALSE,mf,nyc,2,,usd,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +usd_irs_lt_2y,usd,irs,,usosfr,2b,SOFR IRS conventions,,,a,shortfront,,,,TRUE,mf,nyc,2,,usd,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +gbp_irs,gbp,irs,,bpsws,0b,SONIA IRS conventions,,,a,shortfront,,,,TRUE,mf,ldn,0,,gbp,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +eur_irs,eur,irs,,eeswe,2b,ESTR IRS conventions,,,a,shortfront,,,,FALSE,mf,tgt,1,,eur,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +sek_irs,sek,irs,,sksws,2b,SWESTR IRS conventions,,,a,shortfront,,,,FALSE,mf,stk,1,,sek,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +nok_irs,nok,irs,,nks,2b,,,,a,shortfront,,,,FALSE,mf,osl,2,,nok,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +chf_irs,chf,irs,,sfsnt,2b,,,,a,shortfront,,,,FALSE,mf,zur,2,,chf,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +cad_irs,cad,irs,,cdso,1b,,,,s,shortfront,,,,FALSE,mf,tro,1,,cad,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +cad_irs_le_1y,cad,irs,,cdso,1b,,,,a,shortfront,,,,TRUE,mf,tro,1,,cad,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +jpy_irs,jpy,irs,,jyso,2b,,,,a,shortfront,,,,TRUE,mf,tyo,2,,jpy,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +nzd_irs3,nzd,irs,,ndswap,2b,,,,s,shortfront,,,,TRUE,mf,wlg,0,,nzd,,act365f,,,q,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(0),,,,,,,,,,,,,,,,,,,,,,,,,,,, +nzd_irs6,nzd,irs,,,2b,,,,s,shortfront,,,,TRUE,mf,wlg,0,,nzd,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(0),,,,,,,,,,,,,,,,,,,,,,,,,,,, +nzd_irs,nzd,irs,,,2b,,,,a,shortfront,,,,TRUE,mf,wlg,2,,nzd,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +aud_irs6,aud,irs,,adsw,1b,,,,s,shortfront,,,,TRUE,mf,syd,0,,aud,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(0),,,,,,,,,,,,,,,,,,,,,,,,,,,, +aud_irs3,aud,irs,,adsw_q,1b,,,,q,shortfront,,,,TRUE,mf,syd,0,,aud,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(0),,,,,,,,,,,,,,,,,,,,,,,,,,,, +aud_irs3_gt_3y,aud,irs,,,2b,,,,s,shortfront,,,,TRUE,mf,syd,0,,aud,,act365f,,,q,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(0),,,,,,,,,,,,,,,,,,,,,,,,,,,, +aud_irs,aud,irs,,adso,1b,,,,a,shortfront,,,,TRUE,mf,syd,2,,aud,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +eur_irs6,eur,irs,,eusa,2b,,,,a,shortfront,,,,FALSE,mf,tgt,0,,eur,,30e360,,,s,,,,,,,,,,,,act360,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +eur_irs3,eur,irs,,eusw_v3,2b,,,,a,shortfront,,,,FALSE,mf,tgt,0,,eur,,30e360,,,q,,,,,,,,,,,,act360,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +eur_irs1,eur,irs,,,2b,,,,a,shortfront,,,,FALSE,mf,tgt,0,,eur,,30e360,,,m,,,,,,,,,,,,act360,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +sek_irs3,sek,irs,,sksw,2b,,,,a,shortfront,,,,FALSE,mf,stk,0,,sek,,30e360,,,q,,,,,,,,,,,,act360,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +nok_irs3,nok,irs,,nksw_v3,2b,,,,a,shortfront,,,,FALSE,mf,osl,0,,nok,,30e360,,,q,,,,,,,,,,,,act360,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +nok_irs6,nok,irs,,nksw,2b,,,,a,shortfront,,,,FALSE,mf,osl,0,,nok,,30e360,,,s,,,,,,,,,,,,act360,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +eurusd_xcs,eur/usd,xcs,,euxoqq,2b,,,,q,shortfront,,,,FALSE,mf,"tgt,nyc",2,,eur,,act360,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,none_simple,,rfr_payment_delay,,,,,,,,0,,FALSE,FALSE,TRUE,,,,,,,,,,,,,,,eurusd, +gbpusd_xcs,gbp/usd,xcs,,bpxoqq,2b,,,,q,shortfront,,,,FALSE,mf,"ldn,nyc",2,,gbp,,act365f,,,,,,,,,,,,,,,act360,,,none_simple,,rfr_payment_delay,,,none_simple,,rfr_payment_delay,,,,,,,,0,,FALSE,FALSE,TRUE,,,,,,,,,,,,,,,gbpusd, +eurgbp_xcs,eur/gbp,xcs,,ebxoqq,2b,,,,q,shortfront,,,,FALSE,mf,"tgt,ldn",2,,eur,,act360,,,,,,,,,,,,,,,act365f,,,none_simple,,rfr_payment_delay,,,none_simple,,rfr_payment_delay,,,,,,,,0,,FALSE,FALSE,TRUE,,,,,,,,,,,,,,,eurgbp, +gbpeur_xcs,gbp/eur,xcs,,ebxoqq,2b,,,,q,shortfront,,,,FALSE,mf,"tgt,ldn",2,,gbp,,act365f,,,,,,,,,,,,,,,act360,,,none_simple,,rfr_payment_delay,,,none_simple,,rfr_payment_delay,,,,,,,,0,,FALSE,FALSE,TRUE,,,,,,,,,,,,,,,eurgbp, +jpyusd_xcs,jpy/usd,xcs,,jybss,2b,,,,q,shortfront,,,,FALSE,mf,"nyc,tyo",2,,jpy,,act365f,,,,,,,,,,,,,,,act360,,,none_simple,,rfr_payment_delay,,,none_simple,,rfr_payment_delay,,,,,,,,0,,FALSE,FALSE,TRUE,,,,,,,,,,,,,,,usdjpy, +audusd_xcs3,aud/usd,xcs,,,,,,,q,shortfront,,,,FALSE,mf,"nyc,syd",2,,aud,,act365f,,,,,,,,,,,,,,,act360,,,none_simple,,ibor(0),,,none_simple,,rfr_payment_delay,,,,,,,,0,,FALSE,FALSE,TRUE,,,,,,,,,,,,,,,audusd, +audusd_xcs,aud/usd,xcs,,,,,,,q,shortfront,,,,FALSE,mf,"nyc,syd",2,,aud,,act365f,,,,,,,,,,,,,,,act360,,,none_simple,,rfr_payment_delay,,,none_simple,,rfr_payment_delay,,,,,,,,0,,FALSE,FALSE,TRUE,,,,,,,,,,,,,,,audusd, +nzdusd_xcs3,nzd/usd,xcs,,,,,,,q,shortfront,,,,FALSE,mf,"nyc,wlg",2,,nzd,,act365f,,,,,,,,,,,,,,,act360,,,none_simple,,ibor(0),,,none_simple,,rfr_payment_delay,,,,,,,,0,,FALSE,FALSE,TRUE,,,,,,,,,,,,,,,nzdusd, +nzdaud_xcs3,nzd/aud,xcs,,,,,,,q,shortfront,,,,FALSE,mf,"nyc,wlg,syd",2,,nzd,,act365f,,,,,,,,,,,,,,,act365f,,,none_simple,,ibor(0),,,none_simple,,ibor(0),,,,,,,,0,,FALSE,FALSE,TRUE,,,,,,,,,,,,,,,audnzd, +eur_zcis,eur,zcis,,euswi,2b,,,,a,shortfront,,,,FALSE,mf,tgt,0,,eur,,1+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,monthly,,,3,,,,,,,, +gbp_zcis,gbp,zcis,,bpswit,0b,,,,a,shortfront,,,,FALSE,mf,ldn,0,,gbp,,1+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,monthly,,,2,,,,,,,, +usd_zcis,usd,zcis,,usswit,2b,,,,a,shortfront,,,,FALSE,mf,nyc,0,,usd,,1+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,daily,,,3,,,,,,,, +gbp_zcs,gbp,zcs,,,0b,,,,a,shortfront,,,,TRUE,mf,ldn,0,,gbp,,act365f,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,,,,,,,,,,,,,,,,,,,,,,,,,,,, +sek_iirs,sek_iirs,iirs,,,2b,,,,a,shortfront,,,,FALSE,none,stk,0,,sek,,actacticma,,,q,,,,,,,,,,,,act360,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,daily,,,3,,,,,,,,,,,, +eur_sbs36,eur,sbs,,,2b,,,,q,shortfront,,,,FALSE,mf,tgt,0,,eur,,act360,,,s,,,,,,,,,,,,,,,none_simple,,ibor(2),,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +nok_sbs36,nok,sbs,,,2b,,,,q,shortfront,,,,FALSE,mf,osl,0,,nok,,act360,,,s,,,,,,,,,,,,,,,none_simple,,ibor(2),,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +aud_sbs36,aud,sbs,,,2b,,,,q,shortfront,,,,FALSE,mf,syd,0,,aud,,act365f,,,s,,,,,,,,,,,,,,,none_simple,,ibor(0),,,none_simple,,ibor(0),,,,,,,,,,,,,,,,,,,,,,,,,,,, +aud_sbs31,aud,sbs,,,2b,,,,q,shortfront,,,,FALSE,mf,syd,0,,aud,,act365f,,,m,,,,,,,,,,,,,,,none_simple,,ibor(0),,,none_simple,,ibor(0),,,,,,,,,,,,,,,,,,,,,,,,,,,, +nzd_sbs36,nzd,sbs,,,2b,,,,q,shortfront,,,,FALSE,mf,wlg,0,,nzd,,act365f,,,s,,,,,,,,,,,,,,,none_simple,,ibor(0),,,none_simple,,ibor(0),,,,,,,,,,,,,,,,,,,,,,,,,,,, +nzd_sbs31,nzd,sbs,,,2b,,,,q,shortfront,,,,FALSE,mf,wlg,0,,nzd,,act365f,,,m,,,,,,,,,,,,,,,none_simple,,ibor(0),,,none_simple,,ibor(0),,,,,,,,,,,,,,,,,,,,,,,,,,,, +us_gb,usd,frb,,,,,,,s,shortfront,,,,TRUE,none,nyc,0,,usd,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,1,us_gb,,,,, +us_gbi,usd,ifrb,,,,,,,s,shortfront,,,,TRUE,none,nyc,0,,usd,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,daily,,,3,,,,,1,1,us_gb,,,,, +us_corp,usd,frb,,,,,,,s,shortfront,,,,TRUE,none,nyc,0,,usd,,30u360,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,1,us_corp,,,,, +us_muni,usd,frb,,,,,,,s,shortfront,,,,TRUE,none,nyc,0,,usd,,30u360,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,1,us_muni,,,,, +us_gb_tsy,usd,frb,,,,,,,s,shortfront,,,,TRUE,none,nyc,0,,usd,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,1,us_gb_tsy,,,,, +uk_gb,gbp,frb,,,,,,,s,longfront,,,,FALSE,none,ldn,0,,gbp,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,7,uk_gb,,,,, +nz_gb,nzd,frb,,,,,,,s,shortfront,,,,FALSE,none,wlg,0,,nzd,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,8,nz_gb,,,,, +de_gb,eur,frb,,,,,,,a,longfront,,,,FALSE,none,tgt,0,,eur,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,2,1,de_gb,,,,, +fr_gb,eur,frb,,,,,,,a,shortfront,,,,FALSE,none,tgt,0,,eur,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,2,1,fr_gb,,,,, +nl_gb,eur,frb,,,,,,,a,shortfront,,,,FALSE,none,tgt,0,,eur,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,2,1,nl_gb,,,,, +it_gb,eur,frb,,,,,,,s,shortfront,,,,FALSE,none,tgt,0,,eur,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,2,1,it_gb,,,,, +ch_gb,chf,frb,,,,,,,a,shortfront,,,,FALSE,none,zur,0,,chf,,30e360,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,1,ch_gb,,,,, +se_gb,sek,frb,,,,,,,a,shortfront,,,,FALSE,none,stk,0,,sek,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,2,5,se_gb,,,,, +no_gb,nok,frb,,,,,,,a,shortfront,,,,FALSE,none,osl,0,,nok,,actacticma_stub365f,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,1,no_gb,,,,, +ca_gb,cad,frb,,,,,,,s,shortfront,,,,FALSE,none,tro,0,,cad,,actacticma_stub365f,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,1,ca_gb,,,,, +ca_gbi,cad,ifrb,,,,,,,s,shortfront,,,,FALSE,none,tro,0,,cad,,actacticma_stub365f,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,daily,,,3,,,,,1,1,ca_gb,,,,, +us_gbb,usd,bill,,,,,,,,,,,,TRUE,none,nyc,0,,usd,,act360,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,0,us_gbb,,,,, +se_gbb,sek,bill,,,,,,,,,,,,FALSE,none,stk,0,,sek,,act360,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,2,0,se_gbb,,,,, +no_gbb,nok,bill,,,,,,,,,,,,FALSE,none,osl,0,,nok,,act365f,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,2,0,no_gbb,,,,, +uk_gbb,gbp,bill,,,,,,,,,,,,TRUE,none,ldn,0,,gbp,,act365f,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,1,0,uk_gbb,,,,, +uk_gbi,gbp,ifrb,,,,,,,s,shortfront,,,,FALSE,none,ldn,0,,gbp,,actacticma,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,daily,,,3,,,,,1,7,uk_gb,,,,, +sek_fra3,sek,fra,,,,,,3m,q,,,,,FALSE,mf,stk,0,,sek,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +eur_fra3,eur,fra,,,,,,3m,q,,,,,FALSE,mf,tgt,0,,eur,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +eur_fra6,eur,fra,,,,,,6m,s,,,,,FALSE,mf,tgt,0,,eur,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +eur_fra1,eur,fra,,,,,,1m,m,,,,,FALSE,mf,tgt,0,,eur,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +nok_fra3,nok,fra,,,,,,3m,q,,,,,FALSE,mf,osl,0,,nok,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +nok_fra6,nok,fra,,,,,,6m,s,,,,,FALSE,mf,osl,0,,nok,,act360,,,,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(2),,,,,,,,,,,,,,,,,,,,,,,,,,,, +usd_frn5,usd,frn,,,,,,,q,,,,,FALSE,mf,nyc,0,,usd,,act360,,,,,,,,,,,,,,,,,,none_simple,,rfr_observation_shift(5),,,,,,,,,,,,,,,,,,,,,,,,,,1,1,,,,,, +usd_stir,usd,stir,,SFR,3m SOFR Futures convention,,,,q,,,,imm,FALSE,mf,nyc,0,,usd,,actacticma,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,usd_rfr,,,,,,,,,,,,,,,,,,,,,,,1000000,,,, +usd_stir1,usd,stir,,SF1,1m Avergaed SOFR Futures,,,,m,,,,som,FALSE,mf,nyc,0,,usd,,actacticma,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay_avg,usd_rfr,,,,,,,,,,,,,,,,,,,,,,,5000400,,,, +eur_stir,eur,stir,,KTR,3m ESTR Futures,,,,q,,,,imm,FALSE,mf,tgt,0,,eur,,actacticma,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,eur_rfr,,,,,,,,,,,,,,,,,,,,,,,1000000,,,, +eur_stir1,eur,stir,,,1m Averaged ESTR futures,,,,m,,,,som,FALSE,mf,tgt,0,,eur,,actacticma,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay_avg,eur_rfr,,,,,,,,,,,,,,,,,,,,,,,3000000,,,, +eur_stir3,eur,stir,,ER,Euribor 3m Futures,,,,q,,,,imm,FALSE,mf,tgt,0,,eur,,actacticma,,,,,,,,,,,,,,,,,,,,,,,none_simple,,ibor(2),eur_ibor,,,,,,,,,,,,,,,,,,,,,,,1000000,,,, +gbp_stir,gbp,stir,,SFI,SONIA 3m Futures,,,,q,,,,imm,FALSE,mf,ldn,0,,gbp,,actacticma,,,,,,,,,,,,,,,,,,,,,,,none_simple,,rfr_payment_delay,gbp_rfr,,,,,,,,,,,,,,,,,,,,,,,1000000,,,, +uk_gb_2y,gbp,bf,,G,Gilt future,,,,,,,,,,,ldn,,,gbp,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ice_gbp,100000,,3,, +uk_gb_5y,gbp,bf,,G,Gilt future,,,,,,,,,,,ldn,,,gbp,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ice_gbp,100000,,4,, +uk_gb_10y,gbp,bf,,G,Gilt future,,,,,,,,,,,ldn,,,gbp,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ice_gbp,100000,,4,, +uk_gb_30y,gbp,bf,,G,Gilt future,,,,,,,,,,,ldn,,,gbp,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ice_gbp,100000,,4,, +us_gb_2y,usd,bf,,US,US treasury futures,,,,,,,,,,,fed,,,usd,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ust_short,200000,,6,, +us_gb_3y,usd,bf,,US,US treasury futures,,,,,,,,,,,fed,,,usd,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ust_short,200000,,6,, +us_gb_5y,usd,bf,,US,US treasury futures,,,,,,,,,,,fed,,,usd,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ust_short,100000,,6,, +us_gb_10y,usd,bf,,US,US treasury futures,,,,,,,,,,,fed,,,usd,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ust_long,100000,,6,, +us_gb_30y,usd,bf,,US,US treasury futures,,,,,,,,,,,fed,,,usd,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ust_long,100000,,6,, +de_gb_2y,eur,bf,,DE,Eurex Germany Futures,,,,,,,,,,,tgt,,,eur,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,eurex_eur,100000,,6,, +de_gb_5y,eur,bf,,DE,Eurex Germany Futures,,,,,,,,,,,tgt,,,eur,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,eurex_eur,100000,,6,, +de_gb_10y,eur,bf,,DE,Eurex Germany Futures,,,,,,,,,,,tgt,,,eur,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,eurex_eur,100000,,6,, +de_gb_30y,eur,bf,,DE,Eurex Germany Futures,,,,,,,,,,,tgt,,,eur,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,eurex_eur,100000,,4,, +fr_gb_5y,eur,bf,,FR,Eurex France Futures,,,,,,,,,,,tgt,,,eur,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,eurex_eur,100000,,6,, +fr_gb_10y,eur,bf,,FR,Eurex France Futures,,,,,,,,,,,tgt,,,eur,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,eurex_eur,100000,,6,, +sp_gb_10y,eur,bf,,SP,Eurex Spain Futures,,,,,,,,,,,tgt,,,eur,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,eurex_eur,100000,,6,, +ch_gb_10y,chf,bf,,CH,Eurex CHF Futures,,,,,,,,,,,zur,,,chf,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,eurex_chf,100000,,6,, diff --git a/python/rateslib/data/fixings.py b/python/rateslib/data/fixings.py index 35fb12846..fed157afb 100644 --- a/python/rateslib/data/fixings.py +++ b/python/rateslib/data/fixings.py @@ -43,10 +43,11 @@ from rateslib.scheduling.convention import Convention, _get_convention from rateslib.scheduling.dcfs import dcf from rateslib.scheduling.frequency import _get_frequency, _get_tenor_from_frequency, add_tenor +from rateslib.scheduling.schedule import _get_stub_inference from rateslib.utils.calendars import _get_first_bus_day if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, Arr1dF64, Arr1dObj, @@ -63,6 +64,7 @@ LegFixings, PeriodFixings, Result, + StubInference, _BaseCurve_, bool_, datetime_, @@ -350,7 +352,7 @@ class FXIndex: the given ``calendar``. If int is assumed to be settleable business days. isda_mtm_calendar: Calendar, str, :green:`optional` The calendar associated with the MTM fixing date determination. - isda_mtm_settle: Adjuster, str, int_, :green:`optional`, + isda_mtm_settle: Adjuster, str, int, :green:`optional`, The adjustment applied to determine the MTM fixing date. allow_cross: bool, :green:`optional (set as True)` This allows sub-division of the fixing into its *majors* as defined by WMR @@ -1712,10 +1714,12 @@ class IBORStubFixing(_BaseFixing): Notes ----- - An interpolated tenor-IBOR type calculation depends upon two tenors being available from - the *Fixings* object. Appropriate tenors will be automatically selected based on the - ``accrual_end`` date. If only one tenor is available, this will be used as the single - ``fixing1`` value. + An interpolated tenor-IBOR type calculation depends upon two tenors being determinable from + which a rate can be linearly interpolated. + + The ``rate_series`` has a ``tenors`` attribute which will be used in a first instance. If this + is empty, i.e. unspecified, then the default tenors of ['1W', '1M', '3M', '6M', '12M'] + are used in place. Examples -------- @@ -1747,21 +1751,15 @@ class IBORStubFixing(_BaseFixing): calendar="tgt", convention="act360", eom=False, + tenors=["1M", "2M", "3M", "6M", "12M"], ) ) ibor_fix.date ibor_fix.value - .. ipython:: python - :suppress: - - fixings.pop("Euribor_1m") - fixings.pop("Euribor_2m") - fixings.pop("Euribor_3m") - fixings.pop("Euribor_6m") This fixing can only be determined from a single tenor, which is quite distinct from the - stub tenor in this case. + 12 day period length in this case. In practice this should be avoided. .. ipython:: python @@ -1776,34 +1774,21 @@ class IBORStubFixing(_BaseFixing): calendar="osl", convention="act360", eom=True, + tenors=["6M"], ) ) ibor_fix.date ibor_fix.value ibor_fix.fixing2 - The following fixing cannot identify any tenor indices in the *Fixings* object, and will - log a *UserWarning* before proceeding to yield *NoInput* for all values. - .. ipython:: python - :okwarning: + :suppress: - ibor_fix = IBORStubFixing( - accrual_start=dt(2000, 1, 5), - accrual_end=dt(2000, 1, 17), - identifier="Unavailable_Identifier", - rate_series=FloatRateSeries( - lag=2, - modifier="MF", - calendar="nyc", - convention="act360", - eom=True, - ) - ) - ibor_fix.date - ibor_fix.value - ibor_fix.fixing1 - ibor_fix.fixing2 + fixings.pop("Euribor_1m") + fixings.pop("Euribor_2m") + fixings.pop("Euribor_3m") + fixings.pop("Euribor_6m") + fixings.pop("NIBOR_6M") """ # noqa: E501 @@ -1832,43 +1817,38 @@ def __init__( date, ) - if isinstance(value, NoInput): - if isinstance(identifier, NoInput): - self._fixing2 = NoInput(0) - self._fixing1 = NoInput(0) - else: - # then populate additional required information - tenors = self._stub_tenors() - if len(tenors[0]) in [1, 2]: - self._fixing1 = IBORFixing( - rate_index=FloatRateIndex( - series=self.series, - frequency=_get_frequency(tenors[0][0], NoInput(0), NoInput(0)), - ), - accrual_start=self.accrual_start, - date=date, - value=NoInput(0), - identifier=identifier + "_" + tenors[0][0], - ) - if len(tenors[0]) == 2: - self._fixing2 = IBORFixing( - rate_index=FloatRateIndex( - series=self._series, - frequency=_get_frequency(tenors[0][1], NoInput(0), NoInput(0)), - ), - date=date, - accrual_start=self.accrual_start, - value=NoInput(0), - identifier=identifier + "_" + tenors[0][1], - ) - else: - self._fixing2 = NoInput(0) - else: - warnings.warn(err.UW_NO_TENORS.format(identifier)) - self._fixing2 = NoInput(0) - self._fixing1 = NoInput(0) + tenors = self._stub_tenors_from_list( + tenors=_drb(["1W", "1M", "3M", "6M", "12M"], self.series.tenors) + ) + self._fixing1 = IBORFixing( + rate_index=FloatRateIndex( + series=self.series, + frequency=_get_frequency(tenors[0][0], NoInput(0), NoInput(0)), + ), + accrual_start=self.accrual_start, + date=date, + value=value, + identifier=NoInput(0) + if isinstance(identifier, NoInput) + else identifier + "_" + tenors[0][0], + ) + if len(tenors[0]) == 2: + self._fixing2 = IBORFixing( + rate_index=FloatRateIndex( + series=self._series, + frequency=_get_frequency(tenors[0][1], NoInput(0), NoInput(0)), + ), + date=date, + accrual_start=self.accrual_start, + value=value, + identifier=NoInput(0) + if isinstance(identifier, NoInput) + else identifier + "_" + tenors[0][1], + ) else: - self._value = value + self._fixing2 = NoInput(0) + + self._value = value @property def date(self) -> datetime: @@ -1947,58 +1927,22 @@ def _lookup_and_calculate( ) -> DualTypes_: raise RuntimeError("This method should be unused due to overloaded properties") - def _stub_tenors(self) -> tuple[list[str], list[datetime]]: - """ - Return the tenors available in the :class:`~rateslib.defaults.Fixings` object for - determining an IBOR type stub period. - - Returns - ------- - tuple of list[string tenors] and list[evaluated end dates] - """ - from rateslib.scheduling import add_tenor - + def _stub_tenors_from_list(self, tenors: list[str]) -> tuple[list[str], list[datetime]]: left: tuple[str | None, datetime] = (None, datetime(1, 1, 1)) right: tuple[str | None, datetime] = (None, datetime(9999, 1, 1)) - for tenor in [ - "1D", - "1B", - "2B", - "1W", - "2W", - "3W", - "4W", - "1M", - "2M", - "3M", - "4M", - "5M", - "6M", - "7M", - "8M", - "9M", - "10M", - "11M", - "12M", - "1Y", - ]: - try: - _ = fixings.__getitem__(f"{self.identifier}_{tenor}") - except Exception: # noqa: S112 - continue - else: - sample_end = add_tenor( - start=self.accrual_start, - tenor=tenor, - modifier=self.series.modifier, - calendar=self.series.calendar, - ) - if sample_end <= self.accrual_end and sample_end > left[1]: - left = (tenor, sample_end) - if sample_end > self.accrual_end and sample_end < right[1]: - right = (tenor, sample_end) - break + for tenor in tenors: + sample_end = add_tenor( + start=self.accrual_start, + tenor=tenor, + modifier=self.series.modifier, + calendar=self.series.calendar, + ) + if sample_end <= self.accrual_end and sample_end > left[1]: + left = (tenor, sample_end) + if sample_end > self.accrual_end and sample_end < right[1]: + right = (tenor, sample_end) + break ret: tuple[list[str], list[datetime]] = ([], []) if left[0] is not None: @@ -2009,6 +1953,68 @@ def _stub_tenors(self) -> tuple[list[str], list[datetime]]: ret[1].append(right[1]) return ret + # def _stub_tenors_from_fixings(self) -> tuple[list[str], list[datetime]]: + # """ + # Return the tenors available in the :class:`~rateslib.defaults.Fixings` object for + # determining an IBOR type stub period. + # + # Returns + # ------- + # tuple of list[string tenors] and list[evaluated end dates] + # """ + # from rateslib.scheduling import add_tenor + # + # left: tuple[str | None, datetime] = (None, datetime(1, 1, 1)) + # right: tuple[str | None, datetime] = (None, datetime(9999, 1, 1)) + # + # for tenor in [ + # "1D", + # "1B", + # "2B", + # "1W", + # "2W", + # "3W", + # "4W", + # "1M", + # "2M", + # "3M", + # "4M", + # "5M", + # "6M", + # "7M", + # "8M", + # "9M", + # "10M", + # "11M", + # "12M", + # "1Y", + # ]: + # try: + # _ = fixings.__getitem__(f"{self.identifier}_{tenor}") + # except Exception: # noqa: S112 + # continue + # else: + # sample_end = add_tenor( + # start=self.accrual_start, + # tenor=tenor, + # modifier=self.series.modifier, + # calendar=self.series.calendar, + # ) + # if sample_end <= self.accrual_end and sample_end > left[1]: + # left = (tenor, sample_end) + # if sample_end > self.accrual_end and sample_end < right[1]: + # right = (tenor, sample_end) + # break + # + # ret: tuple[list[str], list[datetime]] = ([], []) + # if left[0] is not None: + # ret[0].append(left[0]) + # ret[1].append(left[1]) + # if right[0] is not None: + # ret[0].append(right[0]) + # ret[1].append(right[1]) + # return ret + class RFRFixing(_BaseFixing): """ @@ -2030,8 +2036,6 @@ class RFRFixing(_BaseFixing): internal structuring these should have the suffix "_1B", e.g. "ESTR_1B". fixing_method: FloatFixingMethod or str The :class:`FloatFixingMethod` object used to combine multiple RFR fixings. - method_param: int - A parameter required by the ``fixing_method``. spread_compound_method: SpreadCompoundMethod or str A :class:`SpreadCompoundMethod` object used define the calculation of the addition of the ``float_spread``. @@ -2062,8 +2066,7 @@ class RFRFixing(_BaseFixing): accrual_end=dt(2025, 1, 15), identifier="SOFR_1B", spread_compound_method=SpreadCompoundMethod.NoneSimple, - fixing_method=FloatFixingMethod.RFRPaymentDelay, - method_param=0, + fixing_method=FloatFixingMethod.RFRPaymentDelay(), float_spread=0.0, rate_index=FloatRateIndex(frequency="1B", series="usd_rfr") ) @@ -2081,7 +2084,6 @@ class RFRFixing(_BaseFixing): identifier="SOFR_1B", spread_compound_method="NoneSimple", fixing_method="RFRPaymentDelay", - method_param=0, float_spread=0.0, rate_index=FloatRateIndex(frequency="1B", series="usd_rfr") ) @@ -2104,7 +2106,6 @@ class RFRFixing(_BaseFixing): _accrual_end: datetime _fixing_method: FloatFixingMethod _spread_compound_method: SpreadCompoundMethod - _method_param: int def __init__( self, @@ -2113,7 +2114,6 @@ def __init__( accrual_start: datetime, accrual_end: datetime, fixing_method: FloatFixingMethod | str, - method_param: int, spread_compound_method: SpreadCompoundMethod | str, float_spread: DualTypes, value: DualTypes_ = NoInput(0), @@ -2130,7 +2130,6 @@ def __init__( self._accrual_start = accrual_start self._accrual_end = accrual_end self._fixing_method = _get_float_fixing_method(fixing_method) - self._method_param = method_param self._populated = Series(index=[], data=[], dtype=float) # type: ignore[assignment] def reset(self, state: int_ = NoInput(0)) -> None: @@ -2144,11 +2143,6 @@ def fixing_method(self) -> FloatFixingMethod: """The :class:`FloatFixingMethod` object used to combine multiple RFR fixings.""" return self._fixing_method - @property - def method_param(self) -> int: - """A parameter required by the ``fixing_method``.""" - return self._method_param - @property def float_spread(self) -> DualTypes: """The spread value incorporated into the fixing calculation using the compound method.""" @@ -2207,7 +2201,6 @@ def _lookup_and_calculate( value, populated = self._lookup( timeseries=timeseries, fixing_method=self.fixing_method, - method_param=self.method_param, dates_obs=self.dates_obs, dcfs_dcf=self.dcfs_dcf, float_spread=self.float_spread, @@ -2224,7 +2217,6 @@ def _lookup( # accrual_start: datetime, # accrual_end: datetime, fixing_method: FloatFixingMethod, - method_param: int, dates_obs: Arr1dObj, # dates_dcf: list[datetime] | None, # dcfs_obs: Arr1dF64, @@ -2239,7 +2231,6 @@ def _lookup( fixing_rates=fixing_rates, rate_fixings=timeseries, fixing_method=fixing_method, - method_param=method_param, ) ) if len(unpopulated) > 0: @@ -2249,7 +2240,6 @@ def _lookup( fixing_rates=fixing_rates, fixing_dcfs=dcfs_dcf, fixing_method=fixing_method, - method_param=method_param, spread_compound_method=spread_compound_method, float_spread=float_spread, ) @@ -2302,7 +2292,6 @@ def bounds(self) -> tuple[tuple[datetime, datetime], tuple[datetime, datetime]]: accrual_start=self.accrual_start, accrual_end=self.accrual_end, fixing_method=self.fixing_method, - method_param=self.method_param, fixing_calendar=self.rate_index.calendar, ) @@ -2311,7 +2300,6 @@ def _get_date_bounds( accrual_start: datetime, accrual_end: datetime, fixing_method: FloatFixingMethod, - method_param: int, fixing_calendar: CalTypes, ) -> tuple[tuple[datetime, datetime], tuple[datetime, datetime]]: """ @@ -2324,7 +2312,7 @@ def _get_date_bounds( align. """ # Depending upon method get the observation dates and dcf dates - if fixing_method in [ + if type(fixing_method) in [ FloatFixingMethod.RFRPaymentDelay, FloatFixingMethod.RFRPaymentDelayAverage, FloatFixingMethod.RFRLockout, @@ -2332,20 +2320,28 @@ def _get_date_bounds( ]: start_obs, end_obs = accrual_start, accrual_end start_dcf, end_dcf = accrual_start, accrual_end - elif fixing_method in [ + elif type(fixing_method) in [ FloatFixingMethod.RFRObservationShift, FloatFixingMethod.RFRObservationShiftAverage, ]: - start_obs = fixing_calendar.lag_bus_days(accrual_start, -method_param, settlement=False) - end_obs = fixing_calendar.lag_bus_days(accrual_end, -method_param, settlement=False) + start_obs = fixing_calendar.lag_bus_days( + accrual_start, -fixing_method.method_param(), settlement=False + ) + end_obs = fixing_calendar.lag_bus_days( + accrual_end, -fixing_method.method_param(), settlement=False + ) start_dcf, end_dcf = start_obs, end_obs else: # fixing_method in [ # FloatFixingMethod.RFRLookback, # FloatFixingMethod.RFRLookbackAverage, # ]: - start_obs = fixing_calendar.lag_bus_days(accrual_start, -method_param, settlement=False) - end_obs = fixing_calendar.lag_bus_days(accrual_end, -method_param, settlement=False) + start_obs = fixing_calendar.lag_bus_days( + accrual_start, -fixing_method.method_param(), settlement=False + ) + end_obs = fixing_calendar.lag_bus_days( + accrual_end, -fixing_method.method_param(), settlement=False + ) start_dcf, end_dcf = accrual_start, accrual_end return (start_obs, end_obs), (start_dcf, end_dcf) @@ -2426,14 +2422,21 @@ class FloatRateSeries: ---------- lag: int, :red:`required` The number of business days by which the fixing date is lagged to the accrual start date. - calendar: Calendar, str :green:`required` + calendar: Calendar, str :red:`required` The calendar associated with the floating rate's date determination. modifier: Adjuster, str, :red:`required` - The :class:`Adjuster` associated with the end accrual day of the floating rate's date. - convention: Convention, str, :green:`required` + The :class:`~rateslib.scheduling.Adjuster` associated with the end accrual day of the + floating rate's date. + convention: Convention, str, :red:`required` The day count :class:`~rateslib.scheduling.Convention` associated with the floating rate. eom: bool, :red:`required` Whether the interest rate index natively adopts EoM roll preference or not. + tenors: list[str], :green:`optional` + The official list of tenor indexes published by this series. + zero_float_period_stub: StubInference, str, :green:`optional (set as 'ShortBack')` + The stub inference parameter that is used to steer schedule construction when this + series is used as part of a :class:`~rateslib.legs.FloatLeg` composed of + :class:`~rateslib.periods.ZeroFloatPeriod`. """ @@ -2442,6 +2445,8 @@ class FloatRateSeries: _modifier: Adjuster _convention: Convention _eom: bool + _zero_period_stub: StubInference + _tenors: list[str] | NoInput def __init__( self, @@ -2450,33 +2455,61 @@ def __init__( modifier: Adjuster | str, convention: Convention | str, eom: bool, + zero_period_stub: StubInference | str_ = NoInput(0), + tenors: list[str] | NoInput = NoInput(0), ) -> None: self._lag = lag self._calendar = get_calendar(calendar) self._modifier = _get_adjuster(modifier) self._convention = _get_convention(convention) self._eom = eom + self._tenors: list[str] = tenors + if not isinstance(self.tenors, NoInput) and len(self.tenors) == 0: + raise ValueError("`tenors` cannot be given as an empty list.") + self._zero_period_stub = _get_stub_inference( + _drb("ShortBack", zero_period_stub), NoInput(0), NoInput(0) + ) @property def lag(self) -> int: + """The number of business days before accrual start that the fixing is published according + to ``calendar``.""" return self._lag @property def calendar(self) -> CalTypes: + """The fixing calendar for the rate series.""" return self._calendar @property def convention(self) -> Convention: + """The day count :class:`~rateslib.scheduling.Convention` associated with the fixing.""" return self._convention @property def modifier(self) -> Adjuster: + """The date :class:`~rateslib.scheduling.Adjuster` used for date adjustment of the tenor.""" return self._modifier @property def eom(self) -> bool: + """Whether end of month date rolling is applied to date calculations for the fixing + series.""" return self._eom + @property + def zero_period_stub(self) -> StubInference: + """:class:`~rateslib.scheduling.StubInference` used when a fixing tenor does not divide + into the frequency of a compounded :class:`~rateslib.periods.ZeroFloatPeriod`.""" + return self._zero_period_stub + + @property + def tenors(self) -> list[str] | NoInput: + """ + A list of tenors that are published by this interest rate series. + """ + return self._tenors + class _IBORRate: @staticmethod @@ -2486,14 +2519,16 @@ def _rate( rate_fixings: DualTypes | Series[DualTypes] | str_, # type: ignore[type-var] start: datetime, end: datetime, - method_param: int, + lag: int, stub: bool, float_spread: DualTypes, rate_series: FloatRateSeries | NoInput, frequency: Frequency, ) -> Result[DualTypes]: rate_series_ = _maybe_get_rate_series_from_curve( - rate_curve=rate_curve, rate_series=rate_series, method_param=method_param + rate_curve=rate_curve, + rate_series=rate_series, + lag=lag, ) fixing_date = rate_series_.calendar.lag_bus_days(start, -rate_series_.lag, settlement=False) if stub: @@ -2848,7 +2883,6 @@ def _rate( rate_curve: _BaseCurve_, rate_fixings: DualTypes | Series[DualTypes] | str_, # type: ignore[type-var] fixing_method: FloatFixingMethod, - method_param: int, spread_compound_method: SpreadCompoundMethod, float_spread: DualTypes, rate_series: FloatRateSeries | NoInput, @@ -2893,14 +2927,13 @@ def _rate( rate_series_ = _maybe_get_rate_series_from_curve( rate_curve=rate_curve, rate_series=rate_series, - method_param=method_param, + lag=0, ) bounds_obs, bounds_dcf, is_matching = _RFRRate._adjust_dates( start=start, end=end, fixing_method=fixing_method, - method_param=method_param, fixing_calendar=rate_series_.calendar, ) @@ -2931,7 +2964,6 @@ def _rate( is_matching=is_matching, rate_fixings=rate_fixings, fixing_method=fixing_method, - method_param=method_param, ) ) @@ -2979,7 +3011,6 @@ def _rate( fixing_rates=fixing_rates, fixing_dcfs=dcfs_dcf, fixing_method=fixing_method, - method_param=method_param, spread_compound_method=spread_compound_method, float_spread=float_spread, ) @@ -3060,7 +3091,6 @@ def _inefficient_calculation( fixing_rates: Series, fixing_dcfs: Arr1dF64, fixing_method: FloatFixingMethod, - method_param: int, spread_compound_method: SpreadCompoundMethod, float_spread: DualTypes, ) -> Result[DualTypes]: @@ -3069,8 +3099,12 @@ def _inefficient_calculation( or averaging each of them up in turn, combining a float spread if necessary. """ # overwrite with lockout rates: this is needed if rates have been forecast from curve. - if fixing_method in [FloatFixingMethod.RFRLockout, FloatFixingMethod.RFRLockoutAverage]: + if type(fixing_method) in [ + FloatFixingMethod.RFRLockout, + FloatFixingMethod.RFRLockoutAverage, + ]: # overwrite fixings + method_param = fixing_method.method_param() if method_param >= len(fixing_rates): return Err( ValueError(err.VE_LOCKOUT_METHOD_PARAM.format(method_param, fixing_rates)) @@ -3078,7 +3112,7 @@ def _inefficient_calculation( for i in range(1, method_param + 1): fixing_rates.iloc[-i] = fixing_rates.iloc[-(method_param + 1)] - if fixing_method in [ + if type(fixing_method) in [ FloatFixingMethod.RFRLockoutAverage, FloatFixingMethod.RFRLookbackAverage, FloatFixingMethod.RFRObservationShiftAverage, @@ -3106,7 +3140,6 @@ def _get_dates_and_fixing_rates_from_fixings( is_matching: bool, rate_fixings: Series[DualTypes] | str_, # type: ignore[type-var] fixing_method: FloatFixingMethod, - method_param: int, ) -> tuple[ # type: ignore[type-var] Arr1dObj, Arr1dObj, @@ -3153,7 +3186,6 @@ def _get_dates_and_fixing_rates_from_fixings( fixing_rates=fixing_rates, rate_fixings=rate_fixings, fixing_method=fixing_method, - method_param=method_param, ) ) else: @@ -3203,7 +3235,6 @@ def _push_rate_fixings_as_series_to_fixing_rates( fixing_rates: Series[DualTypes], # type: ignore[type-var] rate_fixings: str | Series[DualTypes], # type: ignore[type-var] fixing_method: FloatFixingMethod, - method_param: int, ) -> tuple[Series[DualTypes], Series[DualTypes], Series[DualTypes]]: # type: ignore[type-var] """ Populates an empty fixings_rates Series with values from a looked up fixings collection. @@ -3219,7 +3250,11 @@ def _push_rate_fixings_as_series_to_fixing_rates( fixing_rates.update(fixing_series) # push lockout rates if they are available - if fixing_method in [FloatFixingMethod.RFRLockout, FloatFixingMethod.RFRLockoutAverage]: + if type(fixing_method) in [ + FloatFixingMethod.RFRLockout, + FloatFixingMethod.RFRLockoutAverage, + ]: + method_param = fixing_method.method_param() if method_param >= len(fixing_rates): raise ValueError(err.VE_LOCKOUT_METHOD_PARAM.format(method_param, fixing_rates)) if not isna(fixing_rates.iloc[-(1 + method_param)]): # type: ignore[arg-type] @@ -3261,7 +3296,6 @@ def _adjust_dates( start: datetime, end: datetime, fixing_method: FloatFixingMethod, - method_param: int, fixing_calendar: CalTypes, ) -> tuple[tuple[datetime, datetime], tuple[datetime, datetime], bool]: """ @@ -3274,7 +3308,7 @@ def _adjust_dates( align. """ # Depending upon method get the observation dates and dcf dates - if fixing_method in [ + if type(fixing_method) in [ FloatFixingMethod.RFRPaymentDelay, FloatFixingMethod.RFRPaymentDelayAverage, FloatFixingMethod.RFRLockout, @@ -3283,12 +3317,16 @@ def _adjust_dates( start_obs, end_obs = start, end start_dcf, end_dcf = start, end is_matching = True - elif fixing_method in [ + elif type(fixing_method) in [ FloatFixingMethod.RFRObservationShift, FloatFixingMethod.RFRObservationShiftAverage, ]: - start_obs = fixing_calendar.lag_bus_days(start, -method_param, settlement=False) - end_obs = fixing_calendar.lag_bus_days(end, -method_param, settlement=False) + start_obs = fixing_calendar.lag_bus_days( + start, -fixing_method.method_param(), settlement=False + ) + end_obs = fixing_calendar.lag_bus_days( + end, -fixing_method.method_param(), settlement=False + ) start_dcf, end_dcf = start_obs, end_obs is_matching = True else: @@ -3296,8 +3334,12 @@ def _adjust_dates( # FloatFixingMethod.RFRLookback, # FloatFixingMethod.RFRLookbackAverage, # ]: - start_obs = fixing_calendar.lag_bus_days(start, -method_param, settlement=False) - end_obs = fixing_calendar.lag_bus_days(end, -method_param, settlement=False) + start_obs = fixing_calendar.lag_bus_days( + start, -fixing_method.method_param(), settlement=False + ) + end_obs = fixing_calendar.lag_bus_days( + end, -fixing_method.method_param(), settlement=False + ) start_dcf, end_dcf = start, end is_matching = False @@ -3369,7 +3411,7 @@ def _is_rfr_efficient( isinstance(rate_curve, _BaseCurve) and rate_curve._base_type == _CurveType.dfs and isinstance(rate_fixings, NoInput) - and fixing_method + and type(fixing_method) in [FloatFixingMethod.RFRPaymentDelay, FloatFixingMethod.RFRObservationShift] and (float_spread == 0.0 or spread_compound_method == SpreadCompoundMethod.NoneSimple) ) @@ -3474,7 +3516,7 @@ def _get_float_rate_series_or_blank(val: FloatRateSeries | str_) -> FloatRateSer def _maybe_get_rate_series_from_curve( rate_curve: CurveOption_, rate_series: FloatRateSeries | NoInput, - method_param: int, + lag: int, ) -> FloatRateSeries: """Get a rate fixing calendar and convention from a Curve or the alternatives if not given.""" @@ -3497,7 +3539,7 @@ def _maybe_get_rate_series_from_curve( if isinstance(rate_series, NoInput): # get params from rate_curve return FloatRateSeries( - lag=method_param, + lag=lag, calendar=cal_, convention=conv_, modifier=mod_, diff --git a/python/rateslib/data/loader.py b/python/rateslib/data/loader.py index 254b5ed56..1f879c412 100644 --- a/python/rateslib/data/loader.py +++ b/python/rateslib/data/loader.py @@ -24,7 +24,7 @@ from rateslib.enums.generics import Err, NoInput, Ok if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Adjuster, CalTypes, DualTypes, diff --git a/python/rateslib/default.py b/python/rateslib/default.py index d5bda140d..d4686f156 100644 --- a/python/rateslib/default.py +++ b/python/rateslib/default.py @@ -21,7 +21,6 @@ from rateslib._spec_loader import INSTRUMENT_SPECS from rateslib.enums.generics import NoInput, _drb -from rateslib.enums.parameters import FloatFixingMethod from rateslib.rs import Adjuster, Convention, NamedCal PlotOutput = tuple[plt.Figure, plt.Axes, list[plt.Line2D]] # type: ignore[name-defined] @@ -30,7 +29,7 @@ # Commercial use of this code, and/or copying and redistribution is prohibited. # Contact rateslib at gmail.com if this code is observed outside its intended sphere. if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CalTypes, ) @@ -41,24 +40,6 @@ stub_length="SHORT", eval_mode="swaps_align", modifier="MF", - calendars={ - "all": NamedCal("all"), - "bus": NamedCal("bus"), - "tgt": NamedCal("tgt"), - "ldn": NamedCal("ldn"), - "nyc": NamedCal("nyc"), - "fed": NamedCal("fed"), - "stk": NamedCal("stk"), - "osl": NamedCal("osl"), - "zur": NamedCal("zur"), - "tro": NamedCal("tro"), - "tyo": NamedCal("tyo"), - "syd": NamedCal("syd"), - "nsw": NamedCal("nsw"), - "wlg": NamedCal("wlg"), - "mum": NamedCal("mum"), - "mex": NamedCal("mex"), - }, eom=False, eom_fx=True, # Instrument parameterisation @@ -76,6 +57,7 @@ "IRS": 2, "STIRFuture": 0, "IIRS": 2, + "YoYIS": 2, "ZCS": 2, "ZCIS": 0, "FXSwap": 0, @@ -92,26 +74,6 @@ "NDF": 2, }, fixing_method="rfr_payment_delay", - fixing_method_param={ - "rfr_payment_delay": 0, # no observation shift - use payment_delay param - "rfr_observation_shift": 2, - "rfr_lockout": 2, - "rfr_lookback": 2, - "rfr_payment_delay_avg": 0, # no observation shift - use payment_delay param - "rfr_observation_shift_avg": 2, - "rfr_lockout_avg": 2, - "rfr_lookback_avg": 2, - "ibor": 2, - FloatFixingMethod.RFRPaymentDelayAverage: 0, - FloatFixingMethod.RFRPaymentDelay: 0, - FloatFixingMethod.IBOR: 2, - FloatFixingMethod.RFRLockout: 2, - FloatFixingMethod.RFRLockoutAverage: 2, - FloatFixingMethod.RFRObservationShiftAverage: 2, - FloatFixingMethod.RFRObservationShift: 2, - FloatFixingMethod.RFRLookback: 2, - FloatFixingMethod.RFRLookbackAverage: 2, - }, spread_compound_method="none_simple", base_currency="usd", fx_delivery_lag=2, @@ -372,6 +334,7 @@ modifier=Adjuster.ModifiedFollowing(), convention=Convention.Act360, eom=False, + tenors=["1B", "1W", "1M", "2M", "3M", "6M", "12M"], ), "usd_rfr": dict( lag=0, @@ -379,6 +342,7 @@ modifier=Adjuster.Following(), convention=Convention.Act360, eom=False, + tenors=["1b"], ), "gbp_ibor": dict( lag=0, @@ -386,6 +350,7 @@ modifier=Adjuster.ModifiedFollowing(), convention=Convention.Act365F, eom=True, + tenors=["1B", "1W", "1M", "2M", "3M", "6M", "12M"], ), "gbp_rfr": dict( lag=0, @@ -393,6 +358,7 @@ modifier=Adjuster.Following(), convention=Convention.Act365F, eom=False, + tenors=["1b"], ), "sek_ibor": dict( lag=2, @@ -400,6 +366,7 @@ modifier=Adjuster.ModifiedFollowing(), convention=Convention.Act360, eom=True, + tenors=["2B", "1W", "1M", "2M", "3M", "6M"], ), "sek_rfr": dict( lag=0, @@ -407,6 +374,7 @@ modifier=Adjuster.Following(), convention=Convention.Act360, eom=False, + tenors=["1b"], ), "eur_ibor": dict( lag=2, @@ -414,6 +382,7 @@ modifier=Adjuster.ModifiedFollowing(), convention=Convention.Act360, eom=False, + tenors=["1W", "1M", "3M", "6M", "12M"], ), "eur_rfr": dict( lag=0, @@ -421,6 +390,7 @@ modifier=Adjuster.Following(), convention=Convention.Act360, eom=False, + tenors=["1b"], ), "nok_ibor": dict( lag=2, @@ -428,6 +398,7 @@ modifier=Adjuster.ModifiedFollowing(), convention=Convention.Act360, eom=False, + tenors=["1W", "1M", "2M", "3M", "6M"], ), "nok_rfr": dict( lag=0, @@ -435,6 +406,7 @@ modifier=Adjuster.Following(), convention=Convention.Act365F, eom=False, + tenors=["1b"], ), "chf_ibor": dict( lag=2, @@ -442,6 +414,7 @@ modifier=Adjuster.ModifiedFollowing(), convention=Convention.Act360, eom=False, + tenors=["1B", "1W", "1M", "2M", "3M", "6M", "12M"], ), "chf_rfr": dict( lag=0, @@ -449,6 +422,7 @@ modifier=Adjuster.Following(), convention=Convention.Act360, eom=False, + tenors=["1b"], ), "cad_ibor": dict( lag=2, @@ -456,6 +430,7 @@ modifier=Adjuster.ModifiedFollowing(), convention=Convention.Act365F, eom=False, + tenors=["1M", "2M", "3M", "6M", "12M"], ), "cad_rfr": dict( lag=0, @@ -463,6 +438,7 @@ modifier=Adjuster.Following(), convention=Convention.Act365F, eom=False, + tenors=["1b"], ), "jpy_ibor": dict( lag=2, @@ -470,6 +446,7 @@ modifier=Adjuster.ModifiedFollowing(), convention=Convention.Act365F, eom=False, + tenors=["1M", "3M", "6M"], ), "jpy_rfr": dict( lag=0, @@ -477,6 +454,7 @@ modifier=Adjuster.Following(), convention=Convention.Act365F, eom=False, + tenors=["1b"], ), "aud_ibor": dict( lag=0, @@ -484,6 +462,7 @@ modifier=Adjuster.ModifiedFollowing(), convention=Convention.Act365F, eom=True, + tenors=["1M", "2M", "3M", "4M", "5M", "6M"], ), "aud_rfr": dict( lag=0, @@ -491,6 +470,7 @@ modifier=Adjuster.Following(), convention=Convention.Act365F, eom=False, + tenors=["1b"], ), "nzd_ibor": dict( lag=0, @@ -498,6 +478,7 @@ modifier=Adjuster.ModifiedFollowing(), convention=Convention.Act365F, eom=True, + tenors=["1M", "3M", "6M"], ), "nzd_rfr": dict( lag=0, @@ -505,6 +486,7 @@ modifier=Adjuster.Following(), convention=Convention.Act365F, eom=False, + tenors=["1b"], ), }, ) @@ -541,7 +523,6 @@ class Defaults: payment_lag_exchange: int payment_lag_specific: dict[str, int] fixing_method: str - fixing_method_param: dict[str | FloatFixingMethod, int] spread_compound_method: str base_currency: str fx_delivery_lag: int @@ -651,7 +632,6 @@ def _t_n(v: str) -> str: # teb-newline "payment_lag_specific", "notional", "fixing_method", - "fixing_method_param", "spread_compound_method", "base_currency", "fx_delivery_lag", diff --git a/python/rateslib/dual/ift.py b/python/rateslib/dual/ift.py index 45c7e1b03..2c07f4d70 100644 --- a/python/rateslib/dual/ift.py +++ b/python/rateslib/dual/ift.py @@ -23,7 +23,7 @@ from rateslib.rs import Dual, Dual2 if TYPE_CHECKING: - from rateslib.typing import DualTypes, Number + from rateslib.local_types import DualTypes, Number P = ParamSpec("P") diff --git a/python/rateslib/dual/newton.py b/python/rateslib/dual/newton.py index 7ec0c938e..5f6c2349d 100644 --- a/python/rateslib/dual/newton.py +++ b/python/rateslib/dual/newton.py @@ -23,7 +23,7 @@ from rateslib.rs import Dual, Dual2 if TYPE_CHECKING: - from rateslib.typing import DualTypes + from rateslib.local_types import DualTypes P = ParamSpec("P") # Licence: Creative Commons - Attribution-NonCommercial-NoDerivatives 4.0 International diff --git a/python/rateslib/dual/quadratic.py b/python/rateslib/dual/quadratic.py index 648a80a64..4beead211 100644 --- a/python/rateslib/dual/quadratic.py +++ b/python/rateslib/dual/quadratic.py @@ -17,7 +17,7 @@ from rateslib.dual.newton import _solver_result if TYPE_CHECKING: - from rateslib.typing import DualTypes + from rateslib.local_types import DualTypes # Licence: Creative Commons - Attribution-NonCommercial-NoDerivatives 4.0 International # Commercial use of this code, and/or copying and redistribution is prohibited. diff --git a/python/rateslib/dual/utils.py b/python/rateslib/dual/utils.py index 22a8fd086..ccd3e9304 100644 --- a/python/rateslib/dual/utils.py +++ b/python/rateslib/dual/utils.py @@ -25,7 +25,7 @@ from rateslib.rs import ADOrder, Dual, Dual2, _dsolve1, _dsolve2, _fdsolve1, _fdsolve2 if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Any, Arr1dF64, Arr1dObj, diff --git a/python/rateslib/dual/variable.py b/python/rateslib/dual/variable.py index f1fc50f16..8b972235a 100644 --- a/python/rateslib/dual/variable.py +++ b/python/rateslib/dual/variable.py @@ -24,7 +24,7 @@ from rateslib.rs import Dual, Dual2 if TYPE_CHECKING: - from rateslib.typing import Arr1dF64 + from rateslib.local_types import Arr1dF64 PRECISION = 1e-14 FLOATS = float | np.float16 | np.float32 | np.float64 | np.longdouble diff --git a/python/rateslib/enums/__init__.py b/python/rateslib/enums/__init__.py index 8aeb3aefe..b703bb8bb 100644 --- a/python/rateslib/enums/__init__.py +++ b/python/rateslib/enums/__init__.py @@ -16,6 +16,7 @@ FXDeltaMethod, FXOptionMetric, IndexMethod, + LegIndexBase, LegMtm, SpreadCompoundMethod, ) @@ -27,6 +28,7 @@ "FXDeltaMethod", "FXOptionMetric", "LegMtm", + "LegIndexBase", "NoInput", "Result", "Ok", diff --git a/python/rateslib/enums/parameters.py b/python/rateslib/enums/parameters.py index 40c25d2f6..0172494fd 100644 --- a/python/rateslib/enums/parameters.py +++ b/python/rateslib/enums/parameters.py @@ -13,6 +13,38 @@ from __future__ import annotations from enum import Enum +from typing import TYPE_CHECKING + +import rateslib.rs +from rateslib.rs import FloatFixingMethod, LegIndexBase + +if TYPE_CHECKING: + pass + + +class PicklingContainer: + pass + + +rateslib.rs.PyFloatFixingMethod = PicklingContainer() # type: ignore[attr-defined] + +rateslib.rs.PyFloatFixingMethod.RFRPaymentDelay = rateslib.rs.FloatFixingMethod.RFRPaymentDelay # type: ignore[attr-defined] +rateslib.rs.PyFloatFixingMethod.RFRObservationShift = ( # type: ignore[attr-defined] + rateslib.rs.FloatFixingMethod.RFRObservationShift +) +rateslib.rs.PyFloatFixingMethod.RFRLockout = rateslib.rs.FloatFixingMethod.RFRLockout # type: ignore[attr-defined] +rateslib.rs.PyFloatFixingMethod.RFRLookback = rateslib.rs.FloatFixingMethod.RFRLookback # type: ignore[attr-defined] +rateslib.rs.PyFloatFixingMethod.RFRPaymentDelayAverage = ( # type: ignore[attr-defined] + rateslib.rs.FloatFixingMethod.RFRPaymentDelayAverage +) +rateslib.rs.PyFloatFixingMethod.RFRObservationShiftAverage = ( # type: ignore[attr-defined] + rateslib.rs.FloatFixingMethod.RFRObservationShiftAverage +) +rateslib.rs.PyFloatFixingMethod.RFRLockoutAverage = rateslib.rs.FloatFixingMethod.RFRLockoutAverage # type: ignore[attr-defined] +rateslib.rs.PyFloatFixingMethod.RFRLookbackAverage = ( # type: ignore[attr-defined] + rateslib.rs.FloatFixingMethod.RFRLookbackAverage +) +rateslib.rs.PyFloatFixingMethod.IBOR = rateslib.rs.FloatFixingMethod.IBOR # type: ignore[attr-defined] class OptionType(float, Enum): @@ -53,7 +85,7 @@ class LegMtm(Enum): } -def _get_let_mtm(leg_mtm: str | LegMtm) -> LegMtm: +def _get_leg_mtm(leg_mtm: str | LegMtm) -> LegMtm: if isinstance(leg_mtm, LegMtm): return leg_mtm else: @@ -83,47 +115,6 @@ def __str__(self) -> str: return self.name -class FloatFixingMethod(Enum): - """ - Enumerable type to define floating period rate fixing methods. - """ - - RFRPaymentDelay = 0 - RFRObservationShift = 1 - RFRLockout = 2 - RFRLookback = 3 - RFRPaymentDelayAverage = 4 - RFRObservationShiftAverage = 5 - RFRLockoutAverage = 6 - RFRLookbackAverage = 7 - IBOR = 8 - - def __str__(self) -> str: - # _MAP = { - # FloatFixingMethod.RFRPaymentDelay: "RFRPaymentDelay", - # FloatFixingMethod.RFRObservationShift: "RFRObservationShift", - # FloatFixingMethod.RFRLockout: "RFRLockout", - # FloatFixingMethod.RFRLookback: "RFRLookback", - # FloatFixingMethod.RFRPaymentDelayAverage: "RFRPaymentDelayAverage", - # FloatFixingMethod.RFRObservationShiftAverage: "RFRObservationShiftAverage", - # FloatFixingMethod.RFRLockoutAverage: "RFRLockoutAverage", - # FloatFixingMethod.RFRLookbackAverage: "RFRLookbackAverage", - # FloatFixingMethod.IBOR: "IBOR", - # } - _MAP = { - FloatFixingMethod.RFRPaymentDelay: "rfr_payment_delay", - FloatFixingMethod.RFRObservationShift: "rfr_observation_shift", - FloatFixingMethod.RFRLockout: "rfr_lockout", - FloatFixingMethod.RFRLookback: "rfr_lookback", - FloatFixingMethod.RFRPaymentDelayAverage: "rfr_payment_delay_avg", - FloatFixingMethod.RFRObservationShiftAverage: "rfr_observation_shift_avg", - FloatFixingMethod.RFRLockoutAverage: "rfr_lockout_avg", - FloatFixingMethod.RFRLookbackAverage: "rfr_lookback_avg", - FloatFixingMethod.IBOR: "ibor", - } - return _MAP[self] - - class SpreadCompoundMethod(Enum): """ Enumerable type to define spread compounding methods for floating rates. @@ -171,7 +162,7 @@ def _get_index_method(index_method: str | IndexMethod) -> IndexMethod: ) -_FIXING_METHOD_MAP = { +_FIXING_METHOD_MAP: dict[str, type[FloatFixingMethod]] = { "ibor": FloatFixingMethod.IBOR, "rfrpaymentdelay": FloatFixingMethod.RFRPaymentDelay, "rfrobservationshift": FloatFixingMethod.RFRObservationShift, @@ -197,12 +188,26 @@ def _get_float_fixing_method(method: str | FloatFixingMethod) -> FloatFixingMeth if isinstance(method, FloatFixingMethod): return method else: + if method.lower() in ["rfrpaymentdelay", "rfr_payment_delay"]: + return FloatFixingMethod.RFRPaymentDelay() + elif method.lower() in ["rfrpaymentdelayaverage", "rfr_payment_delay_avg"]: + return FloatFixingMethod.RFRPaymentDelayAverage() + + if not ("(" in method and method[-1] == ")"): + raise ValueError( + f"`fixing_method` as string: '{method}' must have an associated parameter " + f"contained in parentheses, for example 'ibor(2)' or 'rfr_observation_shift(5)'. " + ) + + method_, number_part = method[:-1].split("(") + number = int(number_part) try: - return _FIXING_METHOD_MAP[method.lower()] + enum_ = _FIXING_METHOD_MAP[method_.lower()] except KeyError: raise ValueError( - f"`fixing_method` as string: '{method}' is not a valid option. Please consult docs." + f"`fixing_method` as string: '{method_}' is not a valid FloatFixingMethod." ) + return enum_(number) # type: ignore[call-arg] _SPREAD_COMPOUNDING_METHOD_MAP = { @@ -268,3 +273,15 @@ def _get_fx_option_metric(method: str | FXOptionMetric) -> FXOptionMetric: f"FXOption `metric` as string: '{method}' is not a valid option. Please consult " f"docs." ) + + +__all__ = [ + "SpreadCompoundMethod", + "FloatFixingMethod", + "FXDeltaMethod", + "FXOptionMetric", + "LegMtm", + "LegIndexBase", + "OptionType", + "IndexMethod", +] diff --git a/python/rateslib/errors.py b/python/rateslib/errors.py index 1ce71452a..5957741cb 100644 --- a/python/rateslib/errors.py +++ b/python/rateslib/errors.py @@ -68,10 +68,11 @@ # Fixings -UW_NO_TENORS = ( - "The IBORStubFixing has not detected any tenors under the identifier: '{0}' and " - "will therefore never obtain any fixing value." -) +# Tenors are now derived from a `fixing_series` and not a fixings timeseries +# UW_NO_TENORS = ( +# "The IBORStubFixing has not detected any tenors under the identifier: '{0}' and " +# "will therefore never obtain any fixing value." +# ) TE_NO_FIXING_EXPOSURE_ON_OBJ = ( "The object type '{0}' does not contain or have available methods to calculate fixings " diff --git a/python/rateslib/fx/fx_forwards.py b/python/rateslib/fx/fx_forwards.py index 6d0444123..2120093e6 100644 --- a/python/rateslib/fx/fx_forwards.py +++ b/python/rateslib/fx/fx_forwards.py @@ -40,7 +40,7 @@ from rateslib.scheduling import add_tenor if TYPE_CHECKING: - from rateslib.typing import Number, _BaseCurve, datetime_ + from rateslib.local_types import Number, _BaseCurve, datetime_ DualTypes: TypeAlias = ( "Dual | Dual2 | Variable | float" # required for non-cyclic import on _WithCache ) diff --git a/python/rateslib/fx/fx_rates.py b/python/rateslib/fx/fx_rates.py index 75bea3917..279da9640 100644 --- a/python/rateslib/fx/fx_rates.py +++ b/python/rateslib/fx/fx_rates.py @@ -37,7 +37,7 @@ from rateslib.rs import FXRates as FXRatesObj if TYPE_CHECKING: - from rateslib.typing import Arr1dF64, Arr1dObj, Arr2dObj, DualTypes, Number + from rateslib.local_types import Arr1dF64, Arr1dObj, Arr2dObj, DualTypes, Number """ .. ipython:: python diff --git a/python/rateslib/fx_volatility/base.py b/python/rateslib/fx_volatility/base.py index b20b5c4c7..19c0ac4d5 100644 --- a/python/rateslib/fx_volatility/base.py +++ b/python/rateslib/fx_volatility/base.py @@ -21,7 +21,7 @@ from rateslib.mutability import _WithCache, _WithState if TYPE_CHECKING: - from rateslib.typing import FXForwards + from rateslib.local_types import FXForwards DualTypes: TypeAlias = "float | Dual | Dual2 | Variable" # if not defined causes _WithCache failure diff --git a/python/rateslib/fx_volatility/delta_vol.py b/python/rateslib/fx_volatility/delta_vol.py index 0f985dd13..c394900be 100644 --- a/python/rateslib/fx_volatility/delta_vol.py +++ b/python/rateslib/fx_volatility/delta_vol.py @@ -13,13 +13,12 @@ from __future__ import annotations # type hinting import warnings -from datetime import datetime +from datetime import datetime, timezone from typing import TYPE_CHECKING from uuid import uuid4 import numpy as np from pandas import Series -from pytz import UTC from rateslib import defaults from rateslib.default import ( @@ -65,7 +64,10 @@ from rateslib.splines import evaluate if TYPE_CHECKING: - from rateslib.typing import DualTypes, DualTypes_, Sequence # pragma: no cover + from rateslib.local_types import DualTypes, DualTypes_, Sequence # pragma: no cover + + +UTC = timezone.utc class FXDeltaVolSmile(_BaseSmile): @@ -289,7 +291,12 @@ def get_from_strike( Returns ------- - tuple of float, Dual, Dual2 : (delta index, vol, k) + delta_index: float, Dual, Dual2, Variable + The delta index that can be used as lookup value on the *Smile* + vol: float, Dual, Dual2, Variable + The volatility value attained from lookup of the index on the *Smile*. + k: float, Dual, Dual2, Variable + The strike value associated with the option of the delta index. Notes ----- @@ -857,7 +864,12 @@ def get_from_strike( Returns ------- - tuple of float, Dual, Dual2 : (delta index, vol, k) + delta_index: float, Dual, Dual2, Variable + The delta index that can be used as lookup value on the *Smile* + vol: float, Dual, Dual2, Variable + The volatility value attained from lookup of the index on the *Smile*. + k: float, Dual, Dual2, Variable + The strike value associated with the option of the delta index. Notes ----- diff --git a/python/rateslib/fx_volatility/sabr.py b/python/rateslib/fx_volatility/sabr.py index 9f0db549e..0df4449b2 100644 --- a/python/rateslib/fx_volatility/sabr.py +++ b/python/rateslib/fx_volatility/sabr.py @@ -12,13 +12,12 @@ from __future__ import annotations # type hinting -from datetime import datetime +from datetime import datetime, timezone from typing import TYPE_CHECKING from uuid import uuid4 import numpy as np from pandas import Series -from pytz import UTC from rateslib import defaults from rateslib.dual import ( @@ -55,7 +54,7 @@ from rateslib.scheduling import get_calendar if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, DualTypes, DualTypes_, @@ -67,6 +66,9 @@ ) +UTC = timezone.utc + + class FXSabrSmile(_BaseSmile): r""" Create an *FX Volatility Smile* at a given expiry indexed by strike using SABR parameters. @@ -86,7 +88,7 @@ class FXSabrSmile(_BaseSmile): The number of business days after expiry that the physical settlement of the FX exchange occurs. Uses ``defaults.fx_delivery_lag``. Used in determination of ATM forward rates. - calendar : calendar or str, optional + calendar : Cal, UnionCal, NamedCal, str, optional The holiday calendar object to use for FX delivery day determination. If str, looks up named calendar from static data. pair : str, optional @@ -221,7 +223,12 @@ def get_from_strike( Returns ------- - tuple of DualTypes : (placeholder, vol, k) + null: float, Dual, Dual2, Variable + A *SabrSmile* has no requirement for a delta index. + vol: float, Dual, Dual2, Variable + The volatility value attained from lookup of the index on the *Smile*. + k: float, Dual, Dual2, Variable + The strike value associated with the option of the delta index. Notes ----- @@ -478,7 +485,7 @@ class FXSabrSurface(_WithState, _WithCache[datetime, FXSabrSmile]): The number of business days after expiry that the physical settlement of the FX exchange occurs. Uses ``defaults.fx_delivery_lag``. Used in determination of ATM forward rates for different expiries. - calendar : calendar or str, optional + calendar : Cal, UnionCal, NamedCal, str, optional The holiday calendar object to use for FX delivery day determination. If str, looks up named calendar from static data. pair : str, optional @@ -662,7 +669,12 @@ def get_from_strike( Returns ------- - tuple of DualTypes : (placeholder, vol, k) + null: float, Dual, Dual2, Variable + A *SabrSurface* has no requirement for a delta index. + vol: float, Dual, Dual2, Variable + The volatility value attained from lookup of the index on the *Smile*. + k: float, Dual, Dual2, Variable + The strike value associated with the option of the delta index. Notes ----- diff --git a/python/rateslib/fx_volatility/utils.py b/python/rateslib/fx_volatility/utils.py index d70641fbb..a7763a76b 100644 --- a/python/rateslib/fx_volatility/utils.py +++ b/python/rateslib/fx_volatility/utils.py @@ -14,12 +14,11 @@ import json from dataclasses import dataclass -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from functools import cached_property from typing import TYPE_CHECKING, TypeAlias from pandas import Series -from pytz import UTC from rateslib.dual import ( Dual, @@ -44,10 +43,12 @@ from rateslib.splines import PPSplineDual, PPSplineDual2, PPSplineF64 if TYPE_CHECKING: - from rateslib.typing import Any, CalTypes, Number + from rateslib.local_types import Any, CalTypes, Number DualTypes: TypeAlias = "float | Dual | Dual2 | Variable" # if not defined causes _WithCache failure +UTC = timezone.utc + TERMINAL_DATE = datetime(2100, 1, 1) diff --git a/python/rateslib/instruments/__init__.py b/python/rateslib/instruments/__init__.py index 501d13ead..a796e3ba9 100644 --- a/python/rateslib/instruments/__init__.py +++ b/python/rateslib/instruments/__init__.py @@ -46,6 +46,7 @@ from rateslib.instruments.stir_future import STIRFuture from rateslib.instruments.value import Value from rateslib.instruments.xcs import XCS +from rateslib.instruments.yoyis import YoYIS from rateslib.instruments.zcis import ZCIS from rateslib.instruments.zcs import ZCS @@ -65,6 +66,7 @@ # inflation "ZCIS", "IIRS", + "YoYIS", # credit "CDS", # securities diff --git a/python/rateslib/instruments/bonds/bill.py b/python/rateslib/instruments/bonds/bill.py index be90550fe..8f8ae979c 100644 --- a/python/rateslib/instruments/bonds/bill.py +++ b/python/rateslib/instruments/bonds/bill.py @@ -35,7 +35,7 @@ from rateslib.scheduling.frequency import _get_frequency if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DualTypes, diff --git a/python/rateslib/instruments/bonds/bond_future.py b/python/rateslib/instruments/bonds/bond_future.py index 05ea14678..fe80ddd20 100644 --- a/python/rateslib/instruments/bonds/bond_future.py +++ b/python/rateslib/instruments/bonds/bond_future.py @@ -32,7 +32,7 @@ from rateslib.solver import Solver if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Any, CurvesT_, DualTypes, diff --git a/python/rateslib/instruments/bonds/conventions/__init__.py b/python/rateslib/instruments/bonds/conventions/__init__.py index 338ee799e..658dca3e6 100644 --- a/python/rateslib/instruments/bonds/conventions/__init__.py +++ b/python/rateslib/instruments/bonds/conventions/__init__.py @@ -29,7 +29,7 @@ YtmDiscountFunction, YtmStubDiscountFunction, ) - from rateslib.typing import Any # pragma: no cover + from rateslib.local_types import Any # pragma: no cover class BondCalcMode: @@ -597,8 +597,8 @@ def kwargs(self) -> dict[str, str]: DE_GB = BondCalcMode( # German government bonds - settle_accrual="linear_days", - ytm_accrual="linear_days", + settle_accrual="linear_days_long_front_split", + ytm_accrual="linear_days_long_front_split", v1="compounding_final_simple", v2="regular", v3="compounding", @@ -688,6 +688,13 @@ def kwargs(self) -> dict[str, str]: ytm_clone_kwargs="se_gb", ) +NO_GBB = BillCalcMode( + # Norwegian T-bills + price_type="discount", + # price_accrual_type="linear_days", + ytm_clone_kwargs="no_gb", +) + BOND_MODE_MAP = { "uk_gb": UK_GB, "nz_gb": NZ_GB, @@ -715,6 +722,7 @@ def kwargs(self) -> dict[str, str]: "uk_gbb": UK_GBB, "us_gbb": US_GBB, "se_gbb": SE_GBB, + "no_gbb": NO_GBB, # aliases "ustb": US_GBB, "uktb": UK_GBB, diff --git a/python/rateslib/instruments/bonds/conventions/accrued.py b/python/rateslib/instruments/bonds/conventions/accrued.py index 2442bebf9..6891d7ab4 100644 --- a/python/rateslib/instruments/bonds/conventions/accrued.py +++ b/python/rateslib/instruments/bonds/conventions/accrued.py @@ -17,7 +17,7 @@ from rateslib.scheduling import dcf if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, _SupportsFixedFloatLeg1, ) diff --git a/python/rateslib/instruments/bonds/conventions/discounting.py b/python/rateslib/instruments/bonds/conventions/discounting.py index 7a2d427c2..0d88face3 100644 --- a/python/rateslib/instruments/bonds/conventions/discounting.py +++ b/python/rateslib/instruments/bonds/conventions/discounting.py @@ -18,7 +18,7 @@ if TYPE_CHECKING: from rateslib.instruments.bonds.conventions.accrued import AccrualFunction - from rateslib.typing import ( + from rateslib.local_types import ( CurveOption_, DualTypes, _SupportsFixedFloatLeg1, diff --git a/python/rateslib/instruments/bonds/fixed_rate_bond.py b/python/rateslib/instruments/bonds/fixed_rate_bond.py index 33e66a6dc..390a6a6b8 100644 --- a/python/rateslib/instruments/bonds/fixed_rate_bond.py +++ b/python/rateslib/instruments/bonds/fixed_rate_bond.py @@ -30,7 +30,7 @@ from rateslib.legs import FixedLeg if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DualTypes, diff --git a/python/rateslib/instruments/bonds/float_rate_note.py b/python/rateslib/instruments/bonds/float_rate_note.py index c367bda9d..26e0635cc 100644 --- a/python/rateslib/instruments/bonds/float_rate_note.py +++ b/python/rateslib/instruments/bonds/float_rate_note.py @@ -34,7 +34,7 @@ from rateslib.scheduling import Frequency if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurveOption_, CurvesT_, @@ -73,8 +73,7 @@ class FloatRateNote(_BaseBondInstrument): termination="2y", frequency="A", currency="usd", - fixing_method="rfr_observation_shift", - method_param=5, + fixing_method="rfr_observation_shift(5)", convention="Act360", calendar="nyc|fed", float_spread=25.0, @@ -176,8 +175,6 @@ class FloatRateNote(_BaseBondInstrument): fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for each period. - method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -185,7 +182,7 @@ class FloatRateNote(_BaseBondInstrument): fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in each period rate determination. spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` @@ -265,7 +262,6 @@ def __init__( spread_compound_method: str_ = NoInput(0), rate_fixings: LegFixings = NoInput(0), fixing_method: str_ = NoInput(0), - method_param: int_ = NoInput(0), fixing_frequency: Frequency | str_ = NoInput(0), fixing_series: FloatRateSeries | str_ = NoInput(0), # meta parameters @@ -300,7 +296,6 @@ def __init__( spread_compound_method=spread_compound_method, rate_fixings=rate_fixings, fixing_method=fixing_method, - method_param=method_param, fixing_frequency=fixing_frequency, fixing_series=fixing_series, # meta @@ -446,11 +441,11 @@ def accrued( rate_curve: CurveOption_ = NoInput(0), ) -> DualTypes: acc_idx = self.leg1._period_index(settlement) - if self.leg1.rate_params.fixing_method == FloatFixingMethod.IBOR: + if isinstance(self.leg1.rate_params.fixing_method, FloatFixingMethod.IBOR): frac = self.kwargs.meta["calc_mode"]._settle_accrual(self, settlement, acc_idx) if self.ex_div(settlement): frac = frac - 1 # accrued is negative in ex-div period - rate = self.leg1._regular_periods[acc_idx].rate(rate_curve) + rate = self.leg1._regular_periods[acc_idx].rate(rate_curve=rate_curve) cashflow = ( -self.leg1._regular_periods[acc_idx].settlement_params.notional * self.leg1._regular_periods[acc_idx].period_params.dcf @@ -473,7 +468,6 @@ def accrued( float_spread=self.float_spread, fixing_method=self.leg1.rate_params.fixing_method, rate_fixings=self.leg1.rate_params.fixing_identifier, - method_param=self.leg1.rate_params.method_param, spread_compound_method=self.leg1.rate_params.spread_compound_method, fixing_series=self.leg1.rate_params.fixing_series, fixing_frequency=self.leg1.rate_params.fixing_frequency, diff --git a/python/rateslib/instruments/bonds/index_fixed_rate_bond.py b/python/rateslib/instruments/bonds/index_fixed_rate_bond.py index 886b31935..847777f90 100644 --- a/python/rateslib/instruments/bonds/index_fixed_rate_bond.py +++ b/python/rateslib/instruments/bonds/index_fixed_rate_bond.py @@ -33,7 +33,7 @@ from rateslib.periods.parameters import _IndexParams if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurveOption_, CurvesT_, @@ -934,7 +934,7 @@ def ytm( settlement: datetime, :red:`required` The settlement date on which to determine the price. dirty: bool, :green:`optional (set as False)` - If `True` will assume the + If `True` will assume the (settlement) :meth:`~rateslib.instruments.FixedRateBond.accrued` is included in the price. rate_curve: _BaseCurve or dict of such, :green:`optional` Used to forecast floating rates if required. diff --git a/python/rateslib/instruments/bonds/protocols/__init__.py b/python/rateslib/instruments/bonds/protocols/__init__.py index 319821950..9df26854a 100644 --- a/python/rateslib/instruments/bonds/protocols/__init__.py +++ b/python/rateslib/instruments/bonds/protocols/__init__.py @@ -27,7 +27,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CurvesT_, DataFrame, DualTypes, diff --git a/python/rateslib/instruments/bonds/protocols/accrued.py b/python/rateslib/instruments/bonds/protocols/accrued.py index 3512947cc..1afe74178 100644 --- a/python/rateslib/instruments/bonds/protocols/accrued.py +++ b/python/rateslib/instruments/bonds/protocols/accrued.py @@ -17,13 +17,14 @@ if TYPE_CHECKING: from rateslib.instruments.bonds.conventions.accrued import AccrualFunction # pragma: no cover - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Cashflow, DualTypes, FixedLeg, FixedPeriod, FloatLeg, FloatPeriod, + ZeroFloatPeriod, _BaseCurveOrDict_, _KWArgs, datetime, @@ -36,7 +37,9 @@ class _WithAccrued(Protocol): """ def _period_cashflow( - self, period: Cashflow | FixedPeriod | FloatPeriod, rate_curve: _BaseCurveOrDict_ + self, + period: Cashflow | FixedPeriod | FloatPeriod | ZeroFloatPeriod, + rate_curve: _BaseCurveOrDict_, ) -> DualTypes: ... @property diff --git a/python/rateslib/instruments/bonds/protocols/cashflows.py b/python/rateslib/instruments/bonds/protocols/cashflows.py index e070d9a58..3628d5348 100644 --- a/python/rateslib/instruments/bonds/protocols/cashflows.py +++ b/python/rateslib/instruments/bonds/protocols/cashflows.py @@ -14,7 +14,7 @@ from typing import TYPE_CHECKING, Protocol if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover FixedLeg, FloatLeg, datetime, diff --git a/python/rateslib/instruments/bonds/protocols/duration.py b/python/rateslib/instruments/bonds/protocols/duration.py index 561642bc8..cf6b9ed40 100644 --- a/python/rateslib/instruments/bonds/protocols/duration.py +++ b/python/rateslib/instruments/bonds/protocols/duration.py @@ -17,7 +17,7 @@ from rateslib.dual.utils import _dual_float if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, DualTypes, FixedLeg, diff --git a/python/rateslib/instruments/bonds/protocols/oaspread.py b/python/rateslib/instruments/bonds/protocols/oaspread.py index abe0c62c1..632775042 100644 --- a/python/rateslib/instruments/bonds/protocols/oaspread.py +++ b/python/rateslib/instruments/bonds/protocols/oaspread.py @@ -28,7 +28,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CurvesT_, DualTypes, DualTypes_, diff --git a/python/rateslib/instruments/bonds/protocols/repo.py b/python/rateslib/instruments/bonds/protocols/repo.py index 8d9b29d19..e11206075 100644 --- a/python/rateslib/instruments/bonds/protocols/repo.py +++ b/python/rateslib/instruments/bonds/protocols/repo.py @@ -22,7 +22,7 @@ from rateslib.scheduling import dcf if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover DualTypes, datetime, str_, diff --git a/python/rateslib/instruments/bonds/protocols/ytm.py b/python/rateslib/instruments/bonds/protocols/ytm.py index 9afb9c357..a38f5a313 100644 --- a/python/rateslib/instruments/bonds/protocols/ytm.py +++ b/python/rateslib/instruments/bonds/protocols/ytm.py @@ -29,7 +29,7 @@ CashflowFunction, YtmDiscountFunction, ) - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Cashflow, CurveOption_, DualTypes, @@ -38,6 +38,7 @@ FloatLeg, FloatPeriod, Number, + ZeroFloatPeriod, _BaseCurve_, _KWArgs, datetime, @@ -75,10 +76,9 @@ def _price_from_ytm( calc_mode_ = BOND_MODE_MAP[calc_mode_] try: if indexed: - return self._generic_price_from_ytm_indexed( + q = self._generic_price_from_ytm_indexed( ytm=ytm, settlement=settlement, - dirty=dirty, f1=calc_mode_._v1, f2=calc_mode_._v2, f3=calc_mode_._v3, @@ -89,11 +89,14 @@ def _price_from_ytm( rate_curve=rate_curve, index_curve=index_curve, ) + if dirty: + return q + self.accrued(settlement, indexed=True, index_curve=index_curve) # type: ignore[call-arg] + else: + return q else: - return self._generic_price_from_ytm( + q = self._generic_price_from_ytm( ytm=ytm, settlement=settlement, - dirty=dirty, f1=calc_mode_._v1, f2=calc_mode_._v2, f3=calc_mode_._v3, @@ -103,6 +106,10 @@ def _price_from_ytm( accrual=calc_mode_._ytm_accrual, rate_curve=rate_curve, ) + if dirty: + return q + self._accrued(settlement, calc_mode_._settle_accrual) + else: + return q except KeyError: raise ValueError(f"Cannot calculate with `calc_mode`: {calc_mode}") @@ -110,7 +117,6 @@ def _generic_price_from_ytm( self, ytm: DualTypes, settlement: datetime, - dirty: bool, f1: YtmDiscountFunction, f2: YtmDiscountFunction, f3: YtmDiscountFunction, @@ -182,13 +188,13 @@ def _generic_price_from_ytm( # discount all by the first period factor and scaled to price p = d / -self.leg1.settlement_params.notional * 100 - return p if dirty else p - self._accrued(settlement, accrual) + return p - self._accrued(settlement, accrual) # always return the clean price due to + # the possibility of different accrual functions for physical settlement vs YTM calc. def _generic_price_from_ytm_indexed( self, ytm: DualTypes, settlement: datetime, - dirty: bool, f1: YtmDiscountFunction, f2: YtmDiscountFunction, f3: YtmDiscountFunction, @@ -263,8 +269,8 @@ def _generic_price_from_ytm_indexed( # discount all by the first period factor and scaled to price p = d / -self.leg1.settlement_params.notional * 100 - settle_ir = self.index_ratio(settlement=settlement, index_curve=index_curve) - return p if dirty else p - self._accrued(settlement, accrual) * settle_ir + settle_ir: DualTypes = self.index_ratio(settlement=settlement, index_curve=index_curve) + return p - self._accrued(settlement, accrual) * settle_ir # return the clean indexed price def _ytm( self, @@ -365,7 +371,7 @@ def ytm( settlement: datetime, :red:`required` The settlement date on which to determine the price. dirty: bool, :green:`optional (set as False)` - If `True` will assume the + If `True` will assume the (settlement) :meth:`~rateslib.instruments.FixedRateBond.accrued` is included in the price. rate_curve: _BaseCurve or dict of such, :green:`optional` Used to forecast floating rates if required. @@ -401,7 +407,9 @@ def ytm( ) def _period_cashflow( - self, period: Cashflow | FixedPeriod | FloatPeriod, rate_curve: CurveOption_ + self, + period: Cashflow | FixedPeriod | FloatPeriod | ZeroFloatPeriod, + rate_curve: CurveOption_, ) -> DualTypes: """Nominal fixed rate bonds use the known "cashflow" attribute on the *Period*.""" return period.unindexed_cashflow(rate_curve=rate_curve) diff --git a/python/rateslib/instruments/cds.py b/python/rateslib/instruments/cds.py index bd1c5c32a..95163ba01 100644 --- a/python/rateslib/instruments/cds.py +++ b/python/rateslib/instruments/cds.py @@ -28,7 +28,7 @@ from rateslib.scheduling import Frequency if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DataFrame, @@ -165,7 +165,6 @@ class CDS(_BaseInstrument): leg2_payment_lag: Adjuster, int, :green:`optional (inherited from leg1)` leg2_payment_lag_exchange: Adjuster, int, :green:`optional (inherited from leg1)` leg2_ex_div: Adjuster, int, :green:`optional (inherited from leg1)` - leg2_convention: str, :green:`optional (inherited from leg1)` .. note:: @@ -265,7 +264,7 @@ def __init__( leg2_calendar: CalInput = NoInput(1), leg2_payment_lag: int_ = NoInput(1), leg2_payment_lag_exchange: int_ = NoInput(1), - leg2_convention: str_ = NoInput(1), + # leg2_convention: str_ = NoInput(1), leg2_ex_div: int_ = NoInput(1), # settlement notional: float_ = NoInput(0), @@ -313,7 +312,7 @@ def __init__( leg2_ex_div=leg2_ex_div, leg2_notional=leg2_notional, leg2_amortization=leg2_amortization, - leg2_convention=leg2_convention, + # leg2_convention=leg2_convention, # rate and credit premium_accrued=premium_accrued, fixed_rate=fixed_rate, diff --git a/python/rateslib/instruments/fly.py b/python/rateslib/instruments/fly.py index 9feb0140e..ab2afdc85 100644 --- a/python/rateslib/instruments/fly.py +++ b/python/rateslib/instruments/fly.py @@ -24,7 +24,7 @@ from rateslib.periods.utils import _maybe_fx_converted if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Any, CurvesT_, DualTypes, diff --git a/python/rateslib/instruments/fra.py b/python/rateslib/instruments/fra.py index d7fbaa447..ac1dce2fa 100644 --- a/python/rateslib/instruments/fra.py +++ b/python/rateslib/instruments/fra.py @@ -30,7 +30,7 @@ from rateslib.scheduling import Adjuster if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DataFrame, @@ -48,7 +48,6 @@ bool_, datetime, datetime_, - int_, str_, ) @@ -175,8 +174,9 @@ class FRA(_BaseInstrument): fixed_rate : float or None The fixed rate applied to the :class:`~rateslib.legs.FixedLeg`. If `None` will be set to mid-market when curves are provided. - leg2_method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. + leg2_fixing_method: int, :green:`optional (set by 'defaults')` + The ``fixing_method`` used by the *Instrument*. This will be IBOR with a defined + publication lag. The default is "IBOR(2)" with a two-day lag. leg2_fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -184,7 +184,7 @@ class FRA(_BaseInstrument): leg2_fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. leg2_rate_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` See :ref:`Fixings `. The value of the rate fixing. If a scalar, is used directly. If a string identifier, links @@ -321,7 +321,7 @@ def __init__( # rate parameters fixed_rate: DualTypes_ = NoInput(0), leg2_rate_fixings: FixingsRates_ = NoInput(0), - leg2_method_param: int_ = NoInput(0), + leg2_fixing_method: FloatFixingMethod | str_ = NoInput(0), leg2_fixing_frequency: Frequency | str_ = NoInput(0), leg2_fixing_series: FloatRateSeries | str_ = NoInput(0), # meta parameters @@ -345,9 +345,9 @@ def __init__( # rate fixed_rate=fixed_rate, leg2_rate_fixings=leg2_rate_fixings, - leg2_method_param=leg2_method_param, leg2_fixing_series=leg2_fixing_series, leg2_fixing_frequency=leg2_fixing_frequency, + leg2_fixing_method=leg2_fixing_method, # meta curves=self._parse_curves(curves), metric=metric, @@ -364,7 +364,6 @@ def __init__( leg2_ex_div=NoInput.inherit, leg2_convention=NoInput.inherit, leg2_float_spread=0.0, - leg2_fixing_method=FloatFixingMethod.IBOR, leg2_spread_compound_method=SpreadCompoundMethod.NoneSimple, leg2_notional=NoInput.negate, leg2_currency=NoInput.inherit, @@ -378,6 +377,7 @@ def __init__( ) default_args = dict( notional=defaults.notional, + leg2_fixing_method=FloatFixingMethod.IBOR(2), metric="rate", ) self._kwargs = _KWArgs( diff --git a/python/rateslib/instruments/fx_forward.py b/python/rateslib/instruments/fx_forward.py index 97dd8cfff..00bb93bdd 100644 --- a/python/rateslib/instruments/fx_forward.py +++ b/python/rateslib/instruments/fx_forward.py @@ -30,7 +30,7 @@ from rateslib.periods.utils import _validate_base_curve if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CurvesT_, DataFrame, DualTypes, diff --git a/python/rateslib/instruments/fx_options/brokerfly.py b/python/rateslib/instruments/fx_options/brokerfly.py index c672ea1d9..7c81c3883 100644 --- a/python/rateslib/instruments/fx_options/brokerfly.py +++ b/python/rateslib/instruments/fx_options/brokerfly.py @@ -21,7 +21,7 @@ from rateslib.instruments.fx_options.strangle import FXStrangle if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CalInput, CurvesT_, diff --git a/python/rateslib/instruments/fx_options/call_put.py b/python/rateslib/instruments/fx_options/call_put.py index d328cbf7b..25738be7c 100644 --- a/python/rateslib/instruments/fx_options/call_put.py +++ b/python/rateslib/instruments/fx_options/call_put.py @@ -44,7 +44,7 @@ import numpy as np # pragma: no cover - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover FX_, Any, CalInput, @@ -85,7 +85,7 @@ class _PricingMetrics: class _BaseFXOption(_BaseInstrument, metaclass=ABCMeta): """ - An abstract base class for implementing *FXOptions*. + Abstract base class for implementing *FXOptions*. See :class:`~rateslib.instruments.FXCall` and :class:`~rateslib.instruments.FXPut`. """ diff --git a/python/rateslib/instruments/fx_options/risk_reversal.py b/python/rateslib/instruments/fx_options/risk_reversal.py index fd0325d84..8980e1c14 100644 --- a/python/rateslib/instruments/fx_options/risk_reversal.py +++ b/python/rateslib/instruments/fx_options/risk_reversal.py @@ -21,7 +21,7 @@ from rateslib.instruments.protocols import _KWArgs if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CalInput, CurvesT_, diff --git a/python/rateslib/instruments/fx_options/straddle.py b/python/rateslib/instruments/fx_options/straddle.py index 79b78ce61..2e0819df5 100644 --- a/python/rateslib/instruments/fx_options/straddle.py +++ b/python/rateslib/instruments/fx_options/straddle.py @@ -19,7 +19,7 @@ from rateslib.instruments.fx_options.risk_reversal import _BaseFXOptionStrat if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DualTypes, diff --git a/python/rateslib/instruments/fx_options/strangle.py b/python/rateslib/instruments/fx_options/strangle.py index 5d402c192..022c99bb3 100644 --- a/python/rateslib/instruments/fx_options/strangle.py +++ b/python/rateslib/instruments/fx_options/strangle.py @@ -32,7 +32,7 @@ from rateslib.splines import evaluate if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CalInput, CurvesT_, diff --git a/python/rateslib/instruments/fx_swap.py b/python/rateslib/instruments/fx_swap.py index 474811c64..bf3e1b048 100644 --- a/python/rateslib/instruments/fx_swap.py +++ b/python/rateslib/instruments/fx_swap.py @@ -31,7 +31,7 @@ from rateslib.scheduling import Schedule if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CalInput, CurvesT_, diff --git a/python/rateslib/instruments/fx_vol_value.py b/python/rateslib/instruments/fx_vol_value.py index cafdad3fb..c2726cdcb 100644 --- a/python/rateslib/instruments/fx_vol_value.py +++ b/python/rateslib/instruments/fx_vol_value.py @@ -26,7 +26,7 @@ from rateslib.periods.utils import _validate_fx_as_forwards if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CurvesT_, DualTypes, diff --git a/python/rateslib/instruments/iirs.py b/python/rateslib/instruments/iirs.py index 7a963a84f..2aed2e9f5 100644 --- a/python/rateslib/instruments/iirs.py +++ b/python/rateslib/instruments/iirs.py @@ -27,13 +27,13 @@ from rateslib.legs import FixedLeg, FloatLeg if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DataFrame, DualTypes, DualTypes_, - FixingsRates_, + FloatRateSeries, Frequency, FXForwards_, IndexMethod, @@ -209,8 +209,6 @@ class IIRS(_BaseInstrument): leg2_fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for each period. - leg2_method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. leg2_fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -218,7 +216,7 @@ class IIRS(_BaseInstrument): leg2_fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. leg2_float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in each period rate determination. leg2_spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` @@ -342,9 +340,10 @@ def __init__( fixed_rate: DualTypes_ = NoInput(0), leg2_float_spread: DualTypes_ = NoInput(0), leg2_spread_compound_method: str_ = NoInput(0), - leg2_rate_fixings: FixingsRates_ = NoInput(0), + leg2_rate_fixings: LegFixings = NoInput(0), leg2_fixing_method: str_ = NoInput(0), - leg2_method_param: int_ = NoInput(0), + leg2_fixing_frequency: Frequency | str_ = NoInput(0), + leg2_fixing_series: FloatRateSeries | str_ = NoInput(0), # meta params curves: CurvesT_ = NoInput(0), spec: str_ = NoInput(0), @@ -376,7 +375,8 @@ def __init__( leg2_spread_compound_method=leg2_spread_compound_method, leg2_rate_fixings=leg2_rate_fixings, leg2_fixing_method=leg2_fixing_method, - leg2_method_param=leg2_method_param, + leg2_fixing_series=leg2_fixing_series, + leg2_fixing_frequency=leg2_fixing_frequency, leg2_effective=leg2_effective, leg2_termination=leg2_termination, leg2_frequency=leg2_frequency, diff --git a/python/rateslib/instruments/irs.py b/python/rateslib/instruments/irs.py index 518c3bc23..c390f918f 100644 --- a/python/rateslib/instruments/irs.py +++ b/python/rateslib/instruments/irs.py @@ -29,7 +29,7 @@ from rateslib.legs import FixedLeg, FloatLeg if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DataFrame, @@ -194,8 +194,6 @@ class IRS(_BaseInstrument): leg2_fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for each period. - leg2_method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. leg2_fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -203,7 +201,7 @@ class IRS(_BaseInstrument): leg2_fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. leg2_float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in each period rate determination. leg2_spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` @@ -214,6 +212,9 @@ class IRS(_BaseInstrument): See :ref:`Fixings `. The value of the rate fixing. If a scalar, is used directly. If a string identifier, links to the central ``fixings`` object and data loader. + leg2_zero_periods: bool, :green:`optional (set as False)` + Used to define whether to use a multi-period IBOR classification. See + :class:`~rateslib.legs.FloatLeg` for examples. .. note:: @@ -374,9 +375,9 @@ def __init__( leg2_spread_compound_method: str_ = NoInput(0), leg2_rate_fixings: LegFixings = NoInput(0), leg2_fixing_method: str_ = NoInput(0), - leg2_method_param: int_ = NoInput(0), leg2_fixing_frequency: Frequency | str_ = NoInput(0), leg2_fixing_series: FloatRateSeries | str_ = NoInput(0), + leg2_zero_periods: bool_ = NoInput(0), # meta parameters curves: CurvesT_ = NoInput(0), spec: str_ = NoInput(0), @@ -427,9 +428,9 @@ def __init__( leg2_spread_compound_method=leg2_spread_compound_method, leg2_rate_fixings=leg2_rate_fixings, leg2_fixing_method=leg2_fixing_method, - leg2_method_param=leg2_method_param, leg2_fixing_series=leg2_fixing_series, leg2_fixing_frequency=leg2_fixing_frequency, + leg2_zero_periods=leg2_zero_periods, # meta curves=self._parse_curves(curves), ) diff --git a/python/rateslib/instruments/ndf.py b/python/rateslib/instruments/ndf.py index 2a513fa11..d6ea12da9 100644 --- a/python/rateslib/instruments/ndf.py +++ b/python/rateslib/instruments/ndf.py @@ -31,7 +31,7 @@ from rateslib.scheduling.frequency import _get_fx_expiry_and_delivery_and_payment if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Adjuster, CurvesT_, DataFrame, diff --git a/python/rateslib/instruments/ndxcs.py b/python/rateslib/instruments/ndxcs.py index 2221dbe8f..267a0caea 100644 --- a/python/rateslib/instruments/ndxcs.py +++ b/python/rateslib/instruments/ndxcs.py @@ -29,7 +29,7 @@ from rateslib.legs import FixedLeg, FloatLeg if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DataFrame, @@ -236,8 +236,6 @@ class NDXCS(_BaseInstrument): fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for each period. - method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -245,7 +243,7 @@ class NDXCS(_BaseInstrument): fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in each period rate determination. spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` @@ -259,7 +257,6 @@ class NDXCS(_BaseInstrument): leg2_fixed : bool, :green:`optional (set as False)` leg2_fixed_rate : float or None leg2_fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` - leg2_method_param: int, :green:`optional (set by 'defaults')` leg2_fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` leg2_fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` leg2_float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` @@ -533,7 +530,6 @@ def __init__( spread_compound_method: str_ = NoInput(0), rate_fixings: LegFixings = NoInput(0), fixing_method: str_ = NoInput(0), - method_param: int_ = NoInput(0), fixing_frequency: Frequency | str_ = NoInput(0), fixing_series: FloatRateSeries | str_ = NoInput(0), leg2_fixed: bool_ = NoInput(0), @@ -543,7 +539,6 @@ def __init__( leg2_spread_compound_method: str_ = NoInput(0), leg2_rate_fixings: LegFixings = NoInput(0), leg2_fixing_method: str_ = NoInput(0), - leg2_method_param: int_ = NoInput(0), leg2_fixing_frequency: Frequency | str_ = NoInput(0), leg2_fixing_series: FloatRateSeries | str_ = NoInput(0), # meta parameters @@ -598,7 +593,6 @@ def __init__( spread_compound_method=spread_compound_method, rate_fixings=rate_fixings, fixing_method=fixing_method, - method_param=method_param, fixing_frequency=fixing_frequency, fixing_series=fixing_series, leg2_fixed_rate=leg2_fixed_rate, @@ -606,7 +600,6 @@ def __init__( leg2_spread_compound_method=leg2_spread_compound_method, leg2_rate_fixings=leg2_rate_fixings, leg2_fixing_method=leg2_fixing_method, - leg2_method_param=leg2_method_param, leg2_fixing_frequency=leg2_fixing_frequency, leg2_fixing_series=leg2_fixing_series, # meta @@ -663,7 +656,6 @@ def __init__( "spread_compound_method", "rate_fixings", "fixing_method", - "method_param", "fixing_frequency", "fixing_series", ] diff --git a/python/rateslib/instruments/portfolio.py b/python/rateslib/instruments/portfolio.py index f2ef8a55f..8b4871c9e 100644 --- a/python/rateslib/instruments/portfolio.py +++ b/python/rateslib/instruments/portfolio.py @@ -25,7 +25,7 @@ from rateslib.periods.utils import _maybe_fx_converted if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Any, CurvesT_, DualTypes, diff --git a/python/rateslib/instruments/protocols/analytic_delta.py b/python/rateslib/instruments/protocols/analytic_delta.py index 883eee3e3..2f356bae7 100644 --- a/python/rateslib/instruments/protocols/analytic_delta.py +++ b/python/rateslib/instruments/protocols/analytic_delta.py @@ -24,7 +24,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurvesT_, DualTypes, FXForwards_, diff --git a/python/rateslib/instruments/protocols/analytic_fixings.py b/python/rateslib/instruments/protocols/analytic_fixings.py index 799820db1..48ca8873e 100644 --- a/python/rateslib/instruments/protocols/analytic_fixings.py +++ b/python/rateslib/instruments/protocols/analytic_fixings.py @@ -25,7 +25,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurvesT_, FXForwards_, Solver_, diff --git a/python/rateslib/instruments/protocols/cashflows.py b/python/rateslib/instruments/protocols/cashflows.py index 9c3f63d00..e95f299c9 100644 --- a/python/rateslib/instruments/protocols/cashflows.py +++ b/python/rateslib/instruments/protocols/cashflows.py @@ -28,7 +28,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Any, CurvesT_, FXForwards_, @@ -199,7 +199,9 @@ def _cashflows_from_legs( with warnings.catch_warnings(): # TODO: pandas 2.1.0 has a FutureWarning for concatenating DataFrames with Null entries warnings.filterwarnings("ignore", category=FutureWarning) - _: DataFrame = concat(dfs_filtered, keys=["leg1", "leg2"]) + _: DataFrame = concat( + dfs_filtered, keys=[f"leg{i + 1}" for i in range(len(dfs_filtered))] + ) return _ def _cashflows_from_instruments(self, *args: Any, **kwargs: Any) -> DataFrame: diff --git a/python/rateslib/instruments/protocols/fixings.py b/python/rateslib/instruments/protocols/fixings.py index 3778125c6..54470a508 100644 --- a/python/rateslib/instruments/protocols/fixings.py +++ b/python/rateslib/instruments/protocols/fixings.py @@ -23,7 +23,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurvesT_, DualTypes, FXForwards_, diff --git a/python/rateslib/instruments/protocols/kwargs.py b/python/rateslib/instruments/protocols/kwargs.py index 57b517b79..e17f21dbb 100644 --- a/python/rateslib/instruments/protocols/kwargs.py +++ b/python/rateslib/instruments/protocols/kwargs.py @@ -18,7 +18,7 @@ from rateslib.scheduling import Schedule if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Any, str_, ) diff --git a/python/rateslib/instruments/protocols/npv.py b/python/rateslib/instruments/protocols/npv.py index 7a742ab3e..a1b772548 100644 --- a/python/rateslib/instruments/protocols/npv.py +++ b/python/rateslib/instruments/protocols/npv.py @@ -24,7 +24,7 @@ from rateslib.periods.utils import _maybe_fx_converted if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurvesT_, DualTypes, FXForwards_, diff --git a/python/rateslib/instruments/protocols/pricing.py b/python/rateslib/instruments/protocols/pricing.py index 5159fab91..948aa1876 100644 --- a/python/rateslib/instruments/protocols/pricing.py +++ b/python/rateslib/instruments/protocols/pricing.py @@ -20,7 +20,7 @@ from rateslib.enums.generics import NoInput, _drb if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( FX_, Any, CurvesT_, diff --git a/python/rateslib/instruments/protocols/rate.py b/python/rateslib/instruments/protocols/rate.py index 4e88932e7..0bc94fa71 100644 --- a/python/rateslib/instruments/protocols/rate.py +++ b/python/rateslib/instruments/protocols/rate.py @@ -16,7 +16,7 @@ from rateslib.enums.generics import NoInput if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurvesT_, DualTypes, FXForwards_, diff --git a/python/rateslib/instruments/protocols/sensitivities.py b/python/rateslib/instruments/protocols/sensitivities.py index f0ea96325..12092fc66 100644 --- a/python/rateslib/instruments/protocols/sensitivities.py +++ b/python/rateslib/instruments/protocols/sensitivities.py @@ -21,7 +21,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurvesT_, DataFrame, Dual, diff --git a/python/rateslib/instruments/protocols/utils.py b/python/rateslib/instruments/protocols/utils.py index 91720b542..6d0e48b0a 100644 --- a/python/rateslib/instruments/protocols/utils.py +++ b/python/rateslib/instruments/protocols/utils.py @@ -16,7 +16,7 @@ from rateslib.enums.generics import NoInput if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurveOption_, ) diff --git a/python/rateslib/instruments/sbs.py b/python/rateslib/instruments/sbs.py index c54b5ec8b..524ae44a4 100644 --- a/python/rateslib/instruments/sbs.py +++ b/python/rateslib/instruments/sbs.py @@ -27,7 +27,7 @@ from rateslib.legs import FloatLeg if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DataFrame, @@ -91,7 +91,7 @@ class SBS(_BaseInstrument): } The available pricing ``metric`` are in *{'leg1', 'leg2'}* which will return a *float spread* - on the specified leg. + on the specified leg. The default is to price the spread on *leg1*. .. role:: red @@ -194,8 +194,6 @@ class SBS(_BaseInstrument): fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for each period. - method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -203,7 +201,7 @@ class SBS(_BaseInstrument): fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in each period rate determination. spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` @@ -215,7 +213,6 @@ class SBS(_BaseInstrument): The value of the rate fixing. If a scalar, is used directly. If a string identifier, links to the central ``fixings`` object and data loader. leg2_fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` - leg2_method_param: int, :green:`optional (set by 'defaults')` leg2_fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` leg2_fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` leg2_float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` @@ -319,14 +316,12 @@ def __init__( spread_compound_method: str_ = NoInput(0), rate_fixings: LegFixings = NoInput(0), fixing_method: str_ = NoInput(0), - method_param: int_ = NoInput(0), fixing_frequency: Frequency | str_ = NoInput(0), fixing_series: FloatRateSeries | str_ = NoInput(0), leg2_float_spread: DualTypes_ = NoInput(0), leg2_spread_compound_method: str_ = NoInput(0), leg2_rate_fixings: LegFixings = NoInput(0), leg2_fixing_method: str_ = NoInput(0), - leg2_method_param: int_ = NoInput(0), leg2_fixing_frequency: Frequency | str_ = NoInput(0), leg2_fixing_series: FloatRateSeries | str_ = NoInput(0), # meta parameters @@ -342,7 +337,6 @@ def __init__( spread_compound_method=spread_compound_method, rate_fixings=rate_fixings, fixing_method=fixing_method, - method_param=method_param, stub=stub, front_stub=front_stub, back_stub=back_stub, @@ -365,7 +359,6 @@ def __init__( leg2_spread_compound_method=leg2_spread_compound_method, leg2_rate_fixings=leg2_rate_fixings, leg2_fixing_method=leg2_fixing_method, - leg2_method_param=leg2_method_param, leg2_effective=leg2_effective, leg2_termination=leg2_termination, leg2_frequency=leg2_frequency, diff --git a/python/rateslib/instruments/spread.py b/python/rateslib/instruments/spread.py index 83eb7213f..23c1f8a26 100644 --- a/python/rateslib/instruments/spread.py +++ b/python/rateslib/instruments/spread.py @@ -24,7 +24,7 @@ from rateslib.periods.utils import _maybe_fx_converted if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Any, CurvesT_, DualTypes, diff --git a/python/rateslib/instruments/stir_future.py b/python/rateslib/instruments/stir_future.py index e66d7d89a..1243885ba 100644 --- a/python/rateslib/instruments/stir_future.py +++ b/python/rateslib/instruments/stir_future.py @@ -34,7 +34,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DataFrame, @@ -166,8 +166,6 @@ class STIRFuture(_BaseInstrument): leg2_fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for each period. - leg2_method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. leg2_fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -175,7 +173,7 @@ class STIRFuture(_BaseInstrument): leg2_fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. leg2_float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in each period rate determination. leg2_spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` @@ -327,7 +325,6 @@ def __init__( leg2_spread_compound_method: str_ = NoInput(0), leg2_rate_fixings: FixingsRates_ = NoInput(0), leg2_fixing_method: str_ = NoInput(0), - leg2_method_param: int_ = NoInput(0), leg2_fixing_frequency: Frequency | str_ = NoInput(0), leg2_fixing_series: FloatRateSeries | str_ = NoInput(0), # meta parameters @@ -357,7 +354,6 @@ def __init__( leg2_spread_compound_method=leg2_spread_compound_method, leg2_rate_fixings=leg2_rate_fixings, leg2_fixing_method=leg2_fixing_method, - leg2_method_param=leg2_method_param, leg2_fixing_series=leg2_fixing_series, leg2_fixing_frequency=leg2_fixing_frequency, # meta diff --git a/python/rateslib/instruments/value.py b/python/rateslib/instruments/value.py index f72f7305e..c21dded52 100644 --- a/python/rateslib/instruments/value.py +++ b/python/rateslib/instruments/value.py @@ -27,7 +27,7 @@ from rateslib.scheduling import dcf if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CurvesT_, DualTypes, diff --git a/python/rateslib/instruments/xcs.py b/python/rateslib/instruments/xcs.py index cc5316c9e..17fc4a5c7 100644 --- a/python/rateslib/instruments/xcs.py +++ b/python/rateslib/instruments/xcs.py @@ -30,7 +30,7 @@ from rateslib.legs import FixedLeg, FloatLeg if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DataFrame, @@ -223,8 +223,6 @@ class XCS(_BaseInstrument): fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for each period. - method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -232,7 +230,7 @@ class XCS(_BaseInstrument): fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in each period rate determination. spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` @@ -246,7 +244,6 @@ class XCS(_BaseInstrument): leg2_fixed : bool, :green:`optional (set as False)` leg2_fixed_rate : float or None leg2_fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` - leg2_method_param: int, :green:`optional (set by 'defaults')` leg2_fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` leg2_fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` leg2_float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` @@ -504,7 +501,6 @@ def __init__( spread_compound_method: str_ = NoInput(0), rate_fixings: FixingsRates_ = NoInput(0), fixing_method: str_ = NoInput(0), - method_param: int_ = NoInput(0), fixing_frequency: Frequency | str_ = NoInput(0), fixing_series: FloatRateSeries | str_ = NoInput(0), fx_fixings: LegFixings = NoInput(0), @@ -515,7 +511,6 @@ def __init__( leg2_spread_compound_method: str_ = NoInput(0), leg2_rate_fixings: LegFixings = NoInput(0), leg2_fixing_method: str_ = NoInput(0), - leg2_method_param: int_ = NoInput(0), leg2_fixing_frequency: Frequency | str_ = NoInput(0), leg2_fixing_series: FloatRateSeries | str_ = NoInput(0), leg2_fx_fixings: LegFixings = NoInput(0), @@ -592,7 +587,6 @@ def __init__( spread_compound_method=spread_compound_method, rate_fixings=rate_fixings, fixing_method=fixing_method, - method_param=method_param, fixing_frequency=fixing_frequency, fixing_series=fixing_series, leg2_fixed_rate=leg2_fixed_rate, @@ -600,7 +594,6 @@ def __init__( leg2_spread_compound_method=leg2_spread_compound_method, leg2_rate_fixings=leg2_rate_fixings, leg2_fixing_method=leg2_fixing_method, - leg2_method_param=leg2_method_param, leg2_fixing_frequency=leg2_fixing_frequency, leg2_fixing_series=leg2_fixing_series, # meta @@ -642,7 +635,6 @@ def __init__( "spread_compound_method", "rate_fixings", "fixing_method", - "method_param", "fixing_frequency", "fixing_series", ] diff --git a/python/rateslib/instruments/yoyis.py b/python/rateslib/instruments/yoyis.py new file mode 100644 index 000000000..848e1c8f8 --- /dev/null +++ b/python/rateslib/instruments/yoyis.py @@ -0,0 +1,603 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from rateslib import defaults +from rateslib.dual.utils import _dual_float +from rateslib.enums.generics import NoInput, _drb +from rateslib.enums.parameters import LegIndexBase +from rateslib.instruments.protocols import _BaseInstrument +from rateslib.instruments.protocols.kwargs import _convert_to_schedule_kwargs, _KWArgs +from rateslib.instruments.protocols.pricing import ( + _Curves, + _maybe_get_curve_maybe_from_solver, + _Vol, +) +from rateslib.legs import FixedLeg + +if TYPE_CHECKING: + from rateslib.local_types import ( # pragma: no cover + CalInput, + CurvesT_, + DataFrame, + DualTypes, + DualTypes_, + Frequency, + FXForwards_, + IndexMethod, + LegFixings, + RollDay, + Sequence, + Solver_, + VolT_, + _BaseLeg, + bool_, + datetime, + datetime_, + float_, + int_, + str_, + ) + + +class YoYIS(_BaseInstrument): + r""" + A *year-on-year indexed swap (YoYIS)* composing two :class:`~rateslib.legs.FixedLeg` with the + second having ``index_params``. + + .. rubric:: Examples + + .. ipython:: python + :suppress: + + from rateslib.instruments import YoYIS + from rateslib import fixings + from datetime import datetime as dt + from pandas import Series + + .. ipython:: python + + fixings.add("CPI_UK", Series(index=[dt(1999, 10, 1), dt(2000, 10, 1), dt(2001, 10, 1), dt(2002, 10, 1)], data=[110.0, 120.0, 125.0, 127.0])) + yoyis = YoYIS( + effective=dt(2000, 1, 1), + termination="3y", + frequency="A", + fixed_rate=2.0, + convention="One", + leg2_index_fixings="CPI_UK", + leg2_index_lag=3, + leg2_index_method="monthly", + ) + yoyis.cashflows() + + .. ipython:: python + :suppress: + + fixings.pop("CPI_UK") + + .. rubric:: Pricing + + An *YoYIS* requires a *disc curve* on both legs (which should be the same *Curve*), and a + *leg2 index curve* for index forecasting on the second *FixedLeg*. + The following input formats are allowed: + + .. code-block:: python + + curves = [index_curve, disc_curve] # two curves are applied in order + curves = { # dict form is explicit + "disc_curve": disc_curve, + "leg2_index_curve": index_curve, + } + + .. role:: red + + .. role:: green + + Parameters + ---------- + . + + .. note:: + + The following define generalised **scheduling** parameters. + + effective : datetime, :red:`required` + The unadjusted effective date. If given as adjusted, unadjusted alternatives may be + inferred. + termination : datetime, str, :red:`required` + The unadjusted termination date. If given as adjusted, unadjusted alternatives may be + inferred. If given as string tenor will be calculated from ``effective``. + frequency : Frequency, str, :red:`required` + The frequency of the schedule. + If given as string will derive a :class:`~rateslib.scheduling.Frequency` aligning with: + monthly ("M"), quarterly ("Q"), semi-annually ("S"), annually("A") or zero-coupon ("Z"), or + a set number of calendar or business days ("_D", "_B"), weeks ("_W"), months ("_M") or + years ("_Y"). + Where required, the :class:`~rateslib.scheduling.RollDay` is derived as per ``roll`` + and business day calendar as per ``calendar``. + stub : StubInference, str in {"ShortFront", "LongFront", "ShortBack", "LongBack"}, :green:`optional` + The stub type used if stub inference is required. If given as string will derive a + :class:`~rateslib.scheduling.StubInference`. + front_stub : datetime, :green:`optional` + The unadjusted date for the start stub period. If given as adjusted, unadjusted + alternatives may be inferred. + back_stub : datetime, :green:`optional` + The unadjusted date for the back stub period. If given as adjusted, unadjusted + alternatives may be inferred. + See notes for combining ``stub``, ``front_stub`` and ``back_stub`` + and any automatic stub inference. + roll : RollDay, int in [1, 31], str in {"eom", "imm", "som"}, :green:`optional` + The roll day of the schedule. If not given or not available in ``frequency`` will be + inferred for monthly frequency variants. + eom : bool, :green:`optional` + Use an end of month preference rather than regular rolls for ``roll`` inference. Set by + default. Not required if ``roll`` is defined. + modifier : Adjuster, str in {"NONE", "F", "MF", "P", "MP"}, :green:`optional` + The :class:`~rateslib.scheduling.Adjuster` used for adjusting unadjusted schedule dates + into adjusted dates. If given as string must define simple date rolling rules. + calendar : calendar, str, :green:`optional` + The business day calendar object to use. If string will call + :meth:`~rateslib.scheduling.get_calendar`. + payment_lag: Adjuster, int, :green:`optional` + The :class:`~rateslib.scheduling.Adjuster` to use to map adjusted schedule dates into + a payment date. If given as integer will define the number of business days to + lag payments by. + payment_lag_exchange: Adjuster, int, :green:`optional` + The :class:`~rateslib.scheduling.Adjuster` to use to map adjusted schedule dates into + additional payment date. If given as integer will define the number of business days to + lag payments by. + ex_div: Adjuster, int, :green:`optional` + The :class:`~rateslib.scheduling.Adjuster` to use to map adjusted schedule dates into + additional dates, which may be used, for example by fixings schedules. If given as integer + will define the number of business days to lag dates by. + convention: str, :green:`optional (set by 'defaults')` + The day count convention applied to calculations of period accrual dates. + See :meth:`~rateslib.scheduling.dcf`. + leg2_effective : datetime, :green:`optional (inherited from leg1)` + leg2_termination : datetime, str, :green:`optional (inherited from leg1)` + leg2_frequency : Frequency, str, :green:`optional (inherited from leg1)` + leg2_stub : StubInference, str, :green:`optional (inherited from leg1)` + leg2_front_stub : datetime, :green:`optional (inherited from leg1)` + leg2_back_stub : datetime, :green:`optional (inherited from leg1)` + leg2_roll : RollDay, int, str, :green:`optional (inherited from leg1)` + leg2_eom : bool, :green:`optional (inherited from leg1)` + leg2_modifier : Adjuster, str, :green:`optional (inherited from leg1)` + leg2_calendar : calendar, str, :green:`optional (inherited from leg1)` + leg2_payment_lag: Adjuster, int, :green:`optional (inherited from leg1)` + leg2_payment_lag_exchange: Adjuster, int, :green:`optional (inherited from leg1)` + leg2_ex_div: Adjuster, int, :green:`optional (inherited from leg1)` + leg2_convention: str, :green:`optional (inherited from leg1)` + + .. note:: + + The following define generalised **settlement** parameters. + + currency : str, :green:`optional (set by 'defaults')` + The local settlement currency of the *Instrument* (3-digit code). + notional : float, Dual, Dual2, Variable, :green:`optional (set by 'defaults')` + The initial leg notional, defined in units of *reference currency*. + amortization: float, Dual, Dual2, Variable, str, Amortization, :green:`optional (set as zero)` + Set a non-constant notional per *Period*. If a scalar value, adjusts the ``notional`` of + each successive period by that same value. Should have + sign equal to that of notional if the notional is to reduce towards zero. + leg2_notional : float, Dual, Dual2, Variable, :green:`optional (negatively inherited from leg1)` + leg2_amortization : float, Dual, Dual2, Variable, str, Amortization, :green:`optional (negatively inherited from leg1)` + + .. note:: + + The following are **rate parameters**. + + fixed_rate : float or None + The fixed rate applied to the :class:`~rateslib.legs.FixedLeg`. If `None` + will be set to mid-market when curves are provided. + + .. note:: + + The following parameters define **indexation**. + + leg2_index_method : IndexMethod, str, :green:`optional (set by 'defaults')` + The interpolation method, or otherwise, to determine index values from reference dates. + leg2_index_lag: int, :green:`optional (set by 'defaults')` + The indexation lag, in months, applied to the determination of index values. + leg2_index_fixings: float, Dual, Dual2, Variable, Series, str, 2-tuple or list, :green:`optional` + The index value for the reference date. + Best practice is to supply this value as string identifier relating to the global + ``fixings`` object. + + .. note:: + + The following are **meta parameters**. + + curves : _BaseCurve, str, dict, _Curves, Sequence, :green:`optional` + Pricing objects passed directly to the *Instrument's* methods' ``curves`` argument. See + **Pricing**. + spec: str, :green:`optional` + A collective group of parameters. See + :ref:`default argument specifications `. + + Notes + ------- + + A *YoYIS* has a nominal :class:`~rateslib.legs.FixedLeg` with a specific ``fixed_rate``, and + a second *Leg* whose cash flows are defined by some index values. *Rateslib* constructs this + object as a second :class:`~rateslib.legs.FixedLeg` which inherits specific properties, + namely: + + - The ``leg2_index_base_type`` is *LegIndexBase.PeriodOnPeriod*, to ensure that indexing is not + calculated from one single ``leg2_index_base`` value, but by consecutive dates. + - The ``leg2_fixed_rate`` is 100% to provide a coupon amount that matches the notional. + - The ``leg2_index_only`` parameter is *True* to ensure that the cashflow paid only accounts for + indexation and does not pay that 100% of notional. + + Under this definition the unindexed reference cashflow of each period of *Leg2* is the notional + adjusted by the DCF: + + .. math:: + + \mathbb{E^Q} [\bar{C}_t] = -N_i d_i + + and the indexed reference cashflow, accounting for indexation only, is: + + .. math:: + + -N_i d_i ( \frac{I_v(m_i)}{I_v(m_{i-1})} - 1 ) + + which matches the definition of the indexed *Leg* of a *YoYIS*. + + """ # noqa: E501 + + _rate_scalar = 1.0 + + @property + def fixed_rate(self) -> DualTypes_: + """The fixed rate of *Leg1*.""" + return self.leg1.fixed_rate + + @fixed_rate.setter + def fixed_rate(self, value: DualTypes_) -> None: + self.kwargs.leg1["fixed_rate"] = value + self.leg1.fixed_rate = value + + @property + def leg1(self) -> FixedLeg: + """The :class:`~rateslib.legs.FixedLeg` of the *Instrument*.""" + return self._leg1 + + @property + def leg2(self) -> FixedLeg: + """The second :class:`~rateslib.legs.FixedLeg` of the *Instrument* with indexation.""" + return self._leg2 + + @property + def legs(self) -> Sequence[_BaseLeg]: + """A list of the *Legs* of the *Instrument*.""" + return self._legs + + def __init__( + self, + effective: datetime_ = NoInput(0), + termination: datetime | str_ = NoInput(0), + frequency: Frequency | str_ = NoInput(0), + *, + stub: str_ = NoInput(0), + front_stub: datetime_ = NoInput(0), + back_stub: datetime_ = NoInput(0), + roll: int | RollDay | str_ = NoInput(0), + eom: bool_ = NoInput(0), + modifier: str_ = NoInput(0), + calendar: CalInput = NoInput(0), + payment_lag: int_ = NoInput(0), + payment_lag_exchange: int_ = NoInput(0), + ex_div: int_ = NoInput(0), + convention: str_ = NoInput(0), + leg2_effective: datetime_ = NoInput(1), + leg2_termination: datetime | str_ = NoInput(1), + leg2_frequency: Frequency | str_ = NoInput(1), + leg2_stub: str_ = NoInput(1), + leg2_front_stub: datetime_ = NoInput(1), + leg2_back_stub: datetime_ = NoInput(1), + leg2_roll: int | RollDay | str_ = NoInput(1), + leg2_eom: bool_ = NoInput(1), + leg2_modifier: str_ = NoInput(1), + leg2_calendar: CalInput = NoInput(1), + leg2_payment_lag: int_ = NoInput(1), + leg2_payment_lag_exchange: int_ = NoInput(1), + leg2_convention: str_ = NoInput(1), + leg2_ex_div: int_ = NoInput(1), + # settlement params + currency: str_ = NoInput(0), + notional: float_ = NoInput(0), + amortization: float_ = NoInput(0), + leg2_notional: float_ = NoInput(-1), + leg2_amortization: float_ = NoInput(-1), + # index params + leg2_index_lag: int_ = NoInput(0), + leg2_index_method: IndexMethod | str_ = NoInput(0), + leg2_index_fixings: LegFixings = NoInput(0), + # rate params + fixed_rate: DualTypes_ = NoInput(0), + # meta params + curves: CurvesT_ = NoInput(0), + spec: str_ = NoInput(0), + ) -> None: + user_args = dict( + effective=effective, + termination=termination, + frequency=frequency, + fixed_rate=fixed_rate, + leg2_index_lag=leg2_index_lag, + leg2_index_method=leg2_index_method, + leg2_index_fixings=leg2_index_fixings, + stub=stub, + front_stub=front_stub, + back_stub=back_stub, + roll=roll, + eom=eom, + modifier=modifier, + calendar=calendar, + payment_lag=payment_lag, + payment_lag_exchange=payment_lag_exchange, + ex_div=ex_div, + notional=notional, + currency=currency, + amortization=amortization, + convention=convention, + leg2_effective=leg2_effective, + leg2_termination=leg2_termination, + leg2_frequency=leg2_frequency, + leg2_stub=leg2_stub, + leg2_front_stub=leg2_front_stub, + leg2_back_stub=leg2_back_stub, + leg2_roll=leg2_roll, + leg2_eom=leg2_eom, + leg2_modifier=leg2_modifier, + leg2_calendar=leg2_calendar, + leg2_payment_lag=leg2_payment_lag, + leg2_payment_lag_exchange=leg2_payment_lag_exchange, + leg2_ex_div=leg2_ex_div, + leg2_notional=leg2_notional, + leg2_amortization=leg2_amortization, + leg2_convention=leg2_convention, + curves=self._parse_curves(curves), + ) + instrument_args = dict( # these are hard coded arguments specific to this instrument + leg2_currency=NoInput(1), + initial_exchange=False, + leg2_initial_exchange=False, + final_exchange=False, + leg2_final_exchange=False, + leg2_index_base_type=LegIndexBase.PeriodOnPeriod, + leg2_fixed_rate=100.0, # combined with index_only this acts similarly to a cashflow + leg2_index_only=True, # but it is impacted by the DCF of the period. + vol=_Vol(), + ) + + default_args = dict( + notional=defaults.notional, + payment_lag=defaults.payment_lag_specific[type(self).__name__], + payment_lag_exchange=defaults.payment_lag_exchange, + index_lag=defaults.index_lag, + index_method=defaults.index_method, + ) + self._kwargs = _KWArgs( + spec=spec, + user_args={**user_args, **instrument_args}, + default_args=default_args, + meta_args=["curves", "vol"], + ) + + self._leg1 = FixedLeg(**_convert_to_schedule_kwargs(self.kwargs.leg1, 1)) + self._leg2 = FixedLeg(**_convert_to_schedule_kwargs(self.kwargs.leg2, 1)) + self._legs = [self._leg1, self._leg2] + + def rate( + self, + *, + curves: CurvesT_ = NoInput(0), + solver: Solver_ = NoInput(0), + fx: FXForwards_ = NoInput(0), + vol: VolT_ = NoInput(0), + base: str_ = NoInput(0), + settlement: datetime_ = NoInput(0), + forward: datetime_ = NoInput(0), + metric: str_ = NoInput(0), + ) -> DualTypes: + _curves = self._parse_curves(curves) + + leg2_npv: DualTypes = self.leg2.local_npv( + rate_curve=NoInput(0), + disc_curve=_maybe_get_curve_maybe_from_solver( + self.kwargs.meta["curves"], _curves, "leg2_disc_curve", solver + ), + index_curve=_maybe_get_curve_maybe_from_solver( + self.kwargs.meta["curves"], _curves, "leg2_index_curve", solver + ), + settlement=settlement, + forward=forward, + ) + + return ( + self.leg1.spread( + target_npv=-leg2_npv, # - leg1_npv, + rate_curve=NoInput(0), + disc_curve=_maybe_get_curve_maybe_from_solver( + self.kwargs.meta["curves"], _curves, "disc_curve", solver + ), + index_curve=NoInput(0), + settlement=settlement, + forward=forward, + ) + / 100 + ) + + def spread( + self, + *, + curves: CurvesT_ = NoInput(0), + solver: Solver_ = NoInput(0), + fx: FXForwards_ = NoInput(0), + vol: VolT_ = NoInput(0), + base: str_ = NoInput(0), + settlement: datetime_ = NoInput(0), + forward: datetime_ = NoInput(0), + ) -> DualTypes: + _curves = self._parse_curves(curves) + + leg1_npv: DualTypes = self.leg1.local_npv( + rate_curve=NoInput(0), + disc_curve=_maybe_get_curve_maybe_from_solver( + self.kwargs.meta["curves"], _curves, "disc_curve", solver + ), + index_curve=NoInput(0), + settlement=settlement, + forward=forward, + ) + return self.leg2.spread( + target_npv=-leg1_npv, + rate_curve=NoInput(0), + disc_curve=_maybe_get_curve_maybe_from_solver( + self.kwargs.meta["curves"], _curves, "leg2_disc_curve", solver + ), + index_curve=_maybe_get_curve_maybe_from_solver( + self.kwargs.meta["curves"], _curves, "leg2_index_curve", solver + ), + settlement=settlement, + forward=forward, + ) + + def npv( + self, + *, + curves: CurvesT_ = NoInput(0), + solver: Solver_ = NoInput(0), + fx: FXForwards_ = NoInput(0), + vol: VolT_ = NoInput(0), + base: str_ = NoInput(0), + local: bool = False, + settlement: datetime_ = NoInput(0), + forward: datetime_ = NoInput(0), + ) -> DualTypes | dict[str, DualTypes]: + self._set_pricing_mid( + curves=curves, + solver=solver, + settlement=settlement, + forward=forward, + ) + return super().npv( + curves=curves, + solver=solver, + fx=fx, + vol=vol, + base=base, + local=local, + settlement=settlement, + forward=forward, + ) + + def _set_pricing_mid( + self, + curves: CurvesT_ = NoInput(0), + solver: Solver_ = NoInput(0), + settlement: datetime_ = NoInput(0), + forward: datetime_ = NoInput(0), + ) -> None: + # the test for an unpriced IIRS is that its fixed rate is not set. + if isinstance(self.kwargs.leg1["fixed_rate"], NoInput): + # set a fixed rate for the purpose of generic methods NPV will be zero. + mid_market_rate = self.rate( + curves=curves, + solver=solver, + settlement=settlement, + forward=forward, + ) + self.leg1.fixed_rate = _dual_float(mid_market_rate) + + def _parse_curves(self, curves: CurvesT_) -> _Curves: + """ + An IIRS has three curve requirements: an index_curve, a leg2_rate_curve and a + disc_curve used by both legs. + """ + if isinstance(curves, NoInput): + return _Curves() + elif isinstance(curves, dict): + return _Curves( + disc_curve=curves.get("disc_curve", NoInput(0)), + index_curve=curves.get("index_curve", NoInput(0)), + leg2_index_curve=_drb( + curves.get("index_curve", NoInput(0)), + curves.get("leg2_index_curve", NoInput(0)), + ), + leg2_disc_curve=_drb( + curves.get("disc_curve", NoInput(0)), + curves.get("leg2_disc_curve", NoInput(0)), + ), + ) + elif isinstance(curves, list | tuple): + if len(curves) == 2: + return _Curves( + disc_curve=curves[1], + leg2_index_curve=curves[0], + leg2_disc_curve=curves[1], + ) + else: + raise ValueError( + f"{type(self).__name__} requires 2 curve types. Got {len(curves)}." + ) + elif isinstance(curves, _Curves): + return curves + else: # `curves` is just a single input which is copied across all curves + raise ValueError(f"{type(self).__name__} requires 2 curve types. Got 1.") + + def _parse_vol(self, vol: VolT_) -> _Vol: + return _Vol() + + def cashflows( + self, + *, + curves: CurvesT_ = NoInput(0), + solver: Solver_ = NoInput(0), + fx: FXForwards_ = NoInput(0), + vol: VolT_ = NoInput(0), + base: str_ = NoInput(0), + settlement: datetime_ = NoInput(0), + forward: datetime_ = NoInput(0), + ) -> DataFrame: + return super()._cashflows_from_legs( + curves=curves, + solver=solver, + fx=fx, + vol=vol, + base=base, + settlement=settlement, + forward=forward, + ) + + def local_analytic_rate_fixings( + self, + *, + curves: CurvesT_ = NoInput(0), + solver: Solver_ = NoInput(0), + fx: FXForwards_ = NoInput(0), + vol: VolT_ = NoInput(0), + settlement: datetime_ = NoInput(0), + forward: datetime_ = NoInput(0), + ) -> DataFrame: + return self._local_analytic_rate_fixings_from_legs( + curves=curves, + solver=solver, + fx=fx, + vol=vol, + settlement=settlement, + forward=forward, + ) diff --git a/python/rateslib/instruments/zcis.py b/python/rateslib/instruments/zcis.py index 2c69fa71e..d8e6a4e4d 100644 --- a/python/rateslib/instruments/zcis.py +++ b/python/rateslib/instruments/zcis.py @@ -26,7 +26,7 @@ from rateslib.legs import ZeroFixedLeg, ZeroIndexLeg if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DataFrame, diff --git a/python/rateslib/instruments/zcs.py b/python/rateslib/instruments/zcs.py index 4824fdc8d..228185148 100644 --- a/python/rateslib/instruments/zcs.py +++ b/python/rateslib/instruments/zcs.py @@ -27,7 +27,7 @@ from rateslib.legs import ZeroFixedLeg, ZeroFloatLeg if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalInput, CurvesT_, DataFrame, @@ -185,8 +185,6 @@ class ZCS(_BaseInstrument): leg2_fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for each period. - leg2_method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. leg2_fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -194,7 +192,7 @@ class ZCS(_BaseInstrument): leg2_fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. leg2_float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in each period rate determination. leg2_spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` @@ -312,7 +310,6 @@ def __init__( leg2_spread_compound_method: str_ = NoInput(0), leg2_rate_fixings: FixingsRates_ = NoInput(0), leg2_fixing_method: str_ = NoInput(0), - leg2_method_param: int_ = NoInput(0), leg2_fixing_frequency: Frequency | str_ = NoInput(0), leg2_fixing_series: FloatRateSeries | str_ = NoInput(0), # meta parameters @@ -359,7 +356,6 @@ def __init__( leg2_spread_compound_method=leg2_spread_compound_method, leg2_rate_fixings=leg2_rate_fixings, leg2_fixing_method=leg2_fixing_method, - leg2_method_param=leg2_method_param, leg2_fixing_series=leg2_fixing_series, leg2_fixing_frequency=leg2_fixing_frequency, # meta diff --git a/python/rateslib/legs/amortization.py b/python/rateslib/legs/amortization.py index 211b4c700..0aa450646 100644 --- a/python/rateslib/legs/amortization.py +++ b/python/rateslib/legs/amortization.py @@ -17,7 +17,7 @@ from rateslib.enums.generics import NoInput if TYPE_CHECKING: - from rateslib.typing import DualTypes, DualTypes_, NoInput # pragma: no cover + from rateslib.local_types import DualTypes, DualTypes_, NoInput # pragma: no cover class _AmortizationType(Enum): diff --git a/python/rateslib/legs/credit.py b/python/rateslib/legs/credit.py index 884d279b1..792cb8637 100644 --- a/python/rateslib/legs/credit.py +++ b/python/rateslib/legs/credit.py @@ -21,8 +21,7 @@ from rateslib.periods import CreditPremiumPeriod, CreditProtectionPeriod if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover - FX_, + from rateslib.local_types import ( # pragma: no cover Any, CurveOption_, DualTypes, @@ -41,7 +40,31 @@ class CreditPremiumLeg(_BaseLeg, _WithExDiv): """ - Define a *Leg* containing :class:`~rateslib.periods.CreditPremiumPeriod`. + A *Leg* containing :class:`~rateslib.periods.CreditPremiumPeriod`. + + .. rubric:: Examples + + .. ipython:: python + :suppress: + + from rateslib import Schedule + from rateslib.legs import CreditPremiumLeg + from datetime import datetime as dt + + .. ipython:: python + + cpl = CreditPremiumLeg( + schedule=Schedule( + effective=dt(2000, 3, 20), + termination=dt(2001, 3, 20), + frequency="Q", + modifier="FEX", + ), + convention="Act360", + fixed_rate=1.0, + notional=10e6, + ) + cpl.cashflows() .. role:: red @@ -88,15 +111,6 @@ class CreditPremiumLeg(_BaseLeg, _WithExDiv): premium_accrued: bool, :green:`optional (set by 'defaults')` Whether an accrued premium is paid on the event of mid-period credit default. - - Notes - ----- - TODO - - Examples - -------- - See :ref:`Leg Examples` - """ @property @@ -112,6 +126,8 @@ def periods(self) -> list[CreditPremiumPeriod]: @property def fixed_rate(self) -> DualTypes_: + """The fixed rate parameter of each composited + :class:`~rateslib.periods.CreditPremiumPeriod`.""" return self._fixed_rate @fixed_rate.setter @@ -122,10 +138,14 @@ def fixed_rate(self, value: DualTypes_) -> None: @property def schedule(self) -> Schedule: + """The :class:`~rateslib.scheduling.Schedule` object of *Leg*.""" return self._schedule @property def amortization(self) -> Amortization: + """ + The :class:`~rateslib.legs.Amortization` object associated with the schedule. + """ return self._amortization def accrued(self, settlement: datetime) -> DualTypes: @@ -226,50 +246,51 @@ def spread( class CreditProtectionLeg(_BaseLeg): """ - Create a credit protection leg composed of :class:`~rateslib.periods.CreditProtectionPeriod` s. + A *Leg* containing :class:`~rateslib.periods.CreditProtectionPeriod`. - Parameters - ---------- - args : tuple - Required positional args to :class:`BaseLeg`. - kwargs : dict - Required keyword arguments to :class:`BaseLeg`. + .. rubric:: Examples - Notes - ----- - The NPV of a credit protection leg is the sum of the period NPVs. + .. ipython:: python + :suppress: - .. math:: + from rateslib import dt, CreditProtectionLeg, Schedule - P = \\sum_{i=1}^n P_i + .. ipython:: python - The analytic delta is the sum of the period analytic deltas. + cpl = CreditProtectionLeg( + schedule=Schedule( + effective=dt(2000, 3, 20), + termination=dt(2001, 3, 30), + frequency="Z", + ), + notional=10e6, + ) + cpl.cashflows() - .. math:: + .. role:: red - A = -\\frac{\\partial P}{\\partial S} = \\sum_{i=1}^n -\\frac{\\partial P_i}{\\partial S} + .. role:: green - Examples - -------- + Parameters + ---------- + schedule: Schedule, :red:`required` + The :class:`~rateslib.scheduling.Schedule` object which structures contiguous *Periods*. + The schedule object also contains data for payment dates, payment dates for notional + exchanges and ex-dividend dates for each period. - .. ipython:: python - :suppress: + .. note:: - from rateslib.curves import Curve - from rateslib.scheduling import Schedule - from rateslib.legs import CreditProtectionLeg - from datetime import datetime as dt + The following define generalised **settlement** parameters. - .. ipython:: python + currency : str, :green:`optional (set by 'defaults')` + The local settlement currency of the leg (3-digit code). + notional : float, Dual, Dual2, Variable, :green:`optional (set by 'defaults')` + The initial leg notional, defined in units of *reference currency*. + amortization: float, Dual, Dual2, Variable, str, Amortization, :green:`optional (set as zero)` + Set a non-constant notional per *Period*. If a scalar value, adjusts the ``notional`` of + each successive period by that same value. Should have + sign equal to that of notional if the notional is to reduce towards zero. - disc_curve = Curve({dt(2022, 1, 1): 1.0, dt(2023, 1, 1): 0.98}) - hazard_curve = Curve({dt(2022, 1, 1): 1.0, dt(2023, 1, 1): 0.995}) - protection_leg = CreditProtectionLeg( - schedule=Schedule(dt(2022, 1, 1), "9M", "Z"), - notional=1000000, - ) - protection_leg.cashflows(rate_curve=hazard_curve, disc_curve=disc_curve) - protection_leg.npv(rate_curve=hazard_curve, disc_curve=disc_curve) """ # noqa: E501 @property @@ -285,10 +306,14 @@ def periods(self) -> list[CreditProtectionPeriod]: @property def schedule(self) -> Schedule: + """The :class:`~rateslib.scheduling.Schedule` object of *Leg*.""" return self._schedule @property def amortization(self) -> Amortization: + """ + The :class:`~rateslib.legs.Amortization` object associated with the schedule. + """ return self._amortization def __init__( @@ -300,7 +325,7 @@ def __init__( amortization: DualTypes_ | list[DualTypes] | Amortization | str = NoInput(0), currency: str_ = NoInput(0), # period - convention: str_ = NoInput(0), + # convention: str_ = NoInput(0), ) -> None: self._schedule = schedule self._notional: DualTypes = _drb(defaults.notional, notional) @@ -308,7 +333,7 @@ def __init__( amortization, self._notional, self.schedule.n_periods ) self._currency: str = _drb(defaults.base_currency, currency).lower() - self._convention: str = _drb(defaults.convention, convention) + # self._convention: str = _drb(defaults.convention, convention) self._regular_periods = tuple( [ @@ -322,7 +347,7 @@ def __init__( start=self.schedule.aschedule[i], end=self.schedule.aschedule[i + 1], frequency=self.schedule.frequency_obj, - convention=self._convention, + # convention=self._convention, termination=self.schedule.aschedule[-1], stub=self.schedule._stubs[i], roll=NoInput(0), # defined by Frequency @@ -342,7 +367,7 @@ def analytic_rec_risk( self, rate_curve: _BaseCurve_ = NoInput(0), disc_curve: _BaseCurve_ = NoInput(0), - fx: FX_ = NoInput(0), + fx: FXForwards_ = NoInput(0), base: str_ = NoInput(0), ) -> float: """ diff --git a/python/rateslib/legs/custom.py b/python/rateslib/legs/custom.py index 037eb855e..0b3f69744 100644 --- a/python/rateslib/legs/custom.py +++ b/python/rateslib/legs/custom.py @@ -17,7 +17,7 @@ from rateslib.periods.protocols import _BasePeriod if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, DualTypes, Sequence, diff --git a/python/rateslib/legs/fixed.py b/python/rateslib/legs/fixed.py index 8635bcff6..9e1a2ed8a 100644 --- a/python/rateslib/legs/fixed.py +++ b/python/rateslib/legs/fixed.py @@ -21,7 +21,7 @@ ) from rateslib.data.fixings import _leg_fixings_to_list from rateslib.enums.generics import NoInput, _drb -from rateslib.enums.parameters import LegMtm, _get_let_mtm +from rateslib.enums.parameters import LegMtm, _get_leg_mtm from rateslib.legs.amortization import Amortization, _AmortizationType, _get_amortization from rateslib.legs.protocols import ( _BaseLeg, @@ -36,9 +36,10 @@ from rateslib.periods.protocols import ( _BasePeriod, ) +from rateslib.rs import LegIndexBase if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CurveOption_, DualTypes, @@ -143,8 +144,8 @@ class FixedLeg(_BaseLeg, _WithExDiv): settlement. The *reference currency* is implied from ``pair``. Must include ``currency``. fx_fixings: float, Dual, Dual2, Variable, Series, str, 2-tuple or list, :green:`optional` The value of the :class:`~rateslib.data.fixings.FXFixing` for each *Period* according - to non-deliverability. Review the **notes** section non-deliverability. This should only - ever be entered as either: + to non-deliverability. Review the **notes** section non-deliverability, and + :ref:`fixings `. This should only ever be entered as either: - scalar value: 1.15, - fixings series: "Reuters_ZBS", @@ -170,10 +171,12 @@ class FixedLeg(_BaseLeg, _WithExDiv): index_fixings: float, Dual, Dual2, Variable, Series, str, 2-tuple or list, :green:`optional` The index value for the reference date. Best practice is to supply this value as string identifier relating to the global - ``fixings`` object. + ``fixings`` object. See :ref:`fixings `. index_only: bool, :green:`optional (set as False)` A flag which indicates that the nominal amount is deducted from the cashflow leaving only the indexed up quantity. + index_base_type: LegIndexBase, :green:`optional` (set as 'Initial')` + A parameter to define how the ``index_base_date`` is set on each period. Notes ----- @@ -579,6 +582,7 @@ def __init__( index_method: IndexMethod | str_ = NoInput(0), index_fixings: LegFixings = NoInput(0), index_only: bool = False, + index_base_type: LegIndexBase = LegIndexBase.Initial, ) -> None: self._fixed_rate = fixed_rate del fixed_rate @@ -594,7 +598,7 @@ def __init__( del currency self._convention: str = _drb(defaults.convention, convention) del convention - self._mtm = _get_let_mtm(mtm) + self._mtm = _get_leg_mtm(mtm) del mtm index_fixings_ = _leg_fixings_to_list(index_fixings, self.schedule.n_periods) @@ -650,7 +654,9 @@ def __init__( index_lag=index_lag, index_method=index_method, index_fixings=index_fixings_[-1], - index_base_date=self.schedule.aschedule[0], + index_base_date=self.schedule.aschedule[0] + if index_base_type is LegIndexBase.Initial + else self.schedule.aschedule[-2], index_reference_date=self.schedule.aschedule[-1], index_only=index_only, ) @@ -686,7 +692,9 @@ def __init__( index_lag=index_lag, index_method=index_method, index_fixings=index_fixings_[i], - index_base_date=self.schedule.aschedule[0], + index_base_date=self.schedule.aschedule[0] + if index_base_type is LegIndexBase.Initial + else self.schedule.aschedule[i], index_reference_date=self.schedule.aschedule[i + 1], index_only=index_only, ) @@ -719,7 +727,9 @@ def __init__( index_lag=index_lag, index_method=index_method, index_fixings=index_fixings_[i], - index_base_date=self.schedule.aschedule[0], + index_base_date=self.schedule.aschedule[0] + if index_base_type is LegIndexBase.Initial + else self.schedule.aschedule[i], index_reference_date=self.schedule.aschedule[i + 1], index_only=index_only, ) @@ -748,7 +758,9 @@ def __init__( index_lag=index_lag, index_method=index_method, index_fixings=index_fixings_[i], - index_base_date=self.schedule.aschedule[0], + index_base_date=self.schedule.aschedule[0] + if index_base_type is LegIndexBase.Initial + else self.schedule.aschedule[i], index_reference_date=self.schedule.aschedule[i + 1], index_only=index_only, ) @@ -874,11 +886,13 @@ class ZeroFixedLeg(_BaseLeg): settlement. The *reference currency* is implied from ``pair``. Must include ``currency``. fx_fixings: float, Dual, Dual2, Variable, Series, str, 2-tuple or list, :green:`optional` The value of the :class:`~rateslib.data.fixings.FXFixing` for each *Period* according - to non-deliverability. Review the **notes** section non-deliverability. + to non-deliverability. + Review the **notes** section non-deliverability on a :class:`~rateslib.legs.FixedLeg`. + See also :ref:`fixings `. mtm: bool, :green:`optional (set to False)` Define whether the non-deliverability depends on a single :class:`~rateslib.data.fixings.FXFixing` defined at the start of the *Leg*, or the end. - Review the **notes** section non-deliverability. + Review the **notes** section non-deliverability on a :class:`~rateslib.legs.FixedLeg`. .. note:: @@ -897,7 +911,7 @@ class ZeroFixedLeg(_BaseLeg): index_fixings: float, Dual, Dual2, Variable, Series, str, 2-tuple or list, :green:`optional` The index value for the reference date. Best practice is to supply this value as string identifier relating to the global - ``fixings`` object. + ``fixings`` object. See :ref:`fixings `. """ @property @@ -1066,8 +1080,22 @@ def spread( settlement: datetime_ = NoInput(0), forward: datetime_ = NoInput(0), ) -> DualTypes: - disc_curve_ = _disc_required_maybe_from_curve(rate_curve, disc_curve) + # scale target_npv accounting for notional exchanges + _ = self.fixed_rate + self.fixed_rate = 0.0 + local_npv = self.local_npv( + rate_curve=rate_curve, + disc_curve=disc_curve, + index_curve=index_curve, + fx=fx, + forward=forward, + settlement=settlement, + ) + self.fixed_rate = _ + rate_target_npv = target_npv - local_npv + # evaluate settlement relative to ex-div + disc_curve_ = _disc_required_maybe_from_curve(rate_curve, disc_curve) if not isinstance(settlement, NoInput): if settlement > self.settlement_params.ex_dividend: raise ZeroDivisionError( @@ -1082,19 +1110,22 @@ def spread( else: w_fwd = disc_curve_[forward] - immediate_target_npv = target_npv * w_fwd + immediate_target_npv = rate_target_npv * w_fwd unindexed_target_npv = immediate_target_npv / self._regular_periods[0].index_up( 1.0, index_curve=index_curve ) unindexed_reference_target_npv = unindexed_target_npv / self._regular_periods[ 0 ].convert_deliverable(1.0, fx=fx) + target_cashflow = ( + unindexed_reference_target_npv / disc_curve_[self.settlement_params.payment] + ) f = self.schedule.periods_per_annum d = self._regular_periods[0].dcf N = self.settlement_params.notional - w = disc_curve_[self.settlement_params.payment] - R = ((-unindexed_reference_target_npv / (N * w) + 1) ** (1 / (d * f)) - 1) * f * 10000.0 + + R = ((-target_cashflow / N + 1) ** (1 / (d * f)) - 1) * f * 10000.0 return R @@ -1179,11 +1210,13 @@ class ZeroIndexLeg(_BaseLeg): settlement. The *reference currency* is implied from ``pair``. Must include ``currency``. fx_fixings: float, Dual, Dual2, Variable, Series, str, 2-tuple or list, :green:`optional` The value of the :class:`~rateslib.data.fixings.FXFixing` for each *Period* according - to non-deliverability. Review the **notes** section non-deliverability. + to non-deliverability. + Review the **notes** section non-deliverability on a :class:`~rateslib.legs.FixedLeg`, + and see also :ref:`fiixngs `. mtm: bool, :green:`optional (set to False)` Define whether the non-deliverability depends on a single :class:`~rateslib.data.fixings.FXFixing` defined at the start of the *Leg*, or the end. - Review the **notes** section non-deliverability. + Review the **notes** section non-deliverability on a :class:`~rateslib.legs.FixedLeg`. .. note:: @@ -1202,7 +1235,7 @@ class ZeroIndexLeg(_BaseLeg): index_fixings: float, Dual, Dual2, Variable, Series, str, 2-tuple or list, :green:`optional` The index value for the reference date. Best practice is to supply this value as string identifier relating to the global - ``fixings`` object. + ``fixings`` object. See also :ref:`fixings `. Notes ----- diff --git a/python/rateslib/legs/float.py b/python/rateslib/legs/float.py index 63435ca29..a6e19563a 100644 --- a/python/rateslib/legs/float.py +++ b/python/rateslib/legs/float.py @@ -21,16 +21,24 @@ from rateslib.data.fixings import _leg_fixings_to_list from rateslib.dual import ift_1dim from rateslib.enums.generics import NoInput, _drb -from rateslib.enums.parameters import FloatFixingMethod, LegMtm, SpreadCompoundMethod, _get_let_mtm +from rateslib.enums.parameters import ( + FloatFixingMethod, + LegMtm, + SpreadCompoundMethod, + _get_float_fixing_method, + _get_leg_mtm, +) from rateslib.legs.amortization import Amortization, _AmortizationType, _get_amortization from rateslib.legs.custom import CustomLeg from rateslib.legs.fixed import _fx_delivery from rateslib.legs.protocols import _BaseLeg, _WithExDiv from rateslib.periods import Cashflow, FloatPeriod, MtmCashflow, ZeroFloatPeriod from rateslib.periods.parameters import _FloatRateParams, _SettlementParams +from rateslib.periods.parameters.rate import _init_float_rate_series +from rateslib.scheduling.schedule import Schedule if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CurveOption_, DualTypes, DualTypes_, @@ -40,11 +48,11 @@ FXIndex, IndexMethod, LegFixings, - Schedule, Sequence, _BaseCurve_, _BasePeriod, _FXVolOption_, + bool_, datetime_, int_, str_, @@ -53,16 +61,17 @@ class FloatLeg(_BaseLeg, _WithExDiv): """ - A *Leg* containing :class:`~rateslib.periods.FloatPeriod`. + A *Leg* containing :class:`~rateslib.periods.FloatPeriod` + (or optionally multiple :class:`~rateslib.periods.ZeroFloatPeriod`). .. rubric:: Examples .. ipython:: python :suppress: - from rateslib import fixings, Schedule + from rateslib import fixings, Schedule, Curve, FloatRateSeries from pandas import Series - from rateslib.legs import FloatLeg + from rateslib.legs import FloatLeg, CustomLeg from datetime import datetime as dt .. ipython:: python @@ -120,8 +129,10 @@ class FloatLeg(_BaseLeg, _WithExDiv): settlement. The *reference currency* is implied from ``pair``. Must include ``currency``. fx_fixings: float, Dual, Dual2, Variable, Series, str, 2-tuple or list, :green:`optional` The value of the :class:`~rateslib.data.fixings.FXFixing` for each *Period* according - to non-deliverability. Review the **notes** section non-deliverability. This should only - ever be entered as either: + to non-deliverability. + Review the **notes** section non-deliverability on a :class:`~rateslib.legs.FixedLeg`, and + see also :ref:`fixings `. + This should only ever be entered as either: - scalar value: 1.15, - fixings series: "Reuters_ZBS", @@ -145,8 +156,6 @@ class FloatLeg(_BaseLeg, _WithExDiv): fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for each period. - method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -154,17 +163,20 @@ class FloatLeg(_BaseLeg, _WithExDiv): fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in each period rate determination. spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.SpreadCompoundMethod` used in the calculation - of the period rate when combining a ``float_spread``. Used **only** with RFR type - ``fixing_method``. + of the period rate when combining a ``float_spread``. Used **only** with (non-averaged) + RFR type ``fixing_method``, and when ``zero_periods`` is False. rate_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` See :ref:`Fixings `. The value of the rate fixing. If a scalar, is used directly. If a string identifier, links to the central ``fixings`` object and data loader. + zero_periods: bool, :green:`optional (set as False)` + If *True* a :class:`~rateslib.periods.ZeroFloatPeriod` is used as the regular period + instead of a :class:`~rateslib.periods.FloatPeriod`. See notes. .. note:: @@ -194,7 +206,227 @@ class FloatLeg(_BaseLeg, _WithExDiv): and **notional exchanges** are identical to, and demonstrated in the documentation for, a :class:`~rateslib.legs.FixedLeg` object. - """ + **Classifications** + + There are generally five types of index classification that can be constructed with this *Leg*. + + .. ipython:: python + :suppress: + + curve = Curve({dt(2026, 1, 1): 1.0, dt(2029, 1, 1): 0.86070797}, calendar="nyc", convention="act360") + + .. tabs:: + + .. tab:: RFR + + To construct a standard **RFR** (otherwise known as OIS) type leg, use + any of the non-averaging *'RFR'* variants of the + :class:`~rateslib.enums.FloatFixingMethod` for the ``fixing_method`` parameter. + + Using this ``fixing_method`` the ``fixing_frequency`` is always assumed to be *'1B'* for + overnight (o/n) rates. + + Any ``spread_compound_method`` can be used in combination with these ``fixing_method``. + + Each :class:`~rateslib.periods.FloatPeriod` has an **RFR** classification. + + Below is an example of the conventional float leg on a USD-SOFR IRS. + + .. ipython:: python + + rfr_standard = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 22), + termination="2Y", + frequency="A", + calendar="nyc", + payment_lag=2 + ), + convention="Act360", + fixing_method="rfr_payment_delay", + ) + rfr_standard.cashflows(rate_curve=curve) + + .. warning:: + + Do **not** use ``zero_periods`` in the construction of RFR type legs. + Although it is, technically, possible to construct this type of *Leg* using + ``zero_periods``. Doing so creates an individual :class:`~rateslib.periods.FloatPeriod` + for every single overnight RFR fixing making up each + :class:`~rateslib.periods.ZeroFloatPeriod`. This is inefficient and removes + other features. + + .. tab:: RFR Avg. + + To construct an **RFR averaged** type use an *'average'* type variant of the + :class:`~rateslib.enums.FloatFixingMethod` for the ``fixing_method`` parameter. + + Each :class:`~rateslib.periods.FloatPeriod` has an **average RFR** classification. + + Below is an example of the conventional float leg on an averaged USD-SOFR IRS. + + .. ipython:: python + + rfr_averaged = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 22), + termination="2Y", + frequency="A", + calendar="nyc", + payment_lag=2 + ), + convention="Act360", + fixing_method="rfr_payment_delay_avg", + ) + rfr_averaged.cashflows(rate_curve=curve) + + .. warning:: + + Rates are calculated directly from the provided ``rate_curve``. There are *no + convexity adjustments* applied to account for the difference between compounded + numéraire and averaged result. + + .. tab:: IBOR + + To construct a standard **IBOR** type leg use the *'ibor'* variant of + the :class:`~rateslib.enums.FloatFixingMethod` for the ``fixing_method`` parameter. + The ``fixing_frequency`` defining tenor of the index will default to that of the schedule. + + Each :class:`~rateslib.periods.FloatPeriod` has an **IBOR** or **IBOR Stub** + classification. Stubs can only appear at the front or back of the *Leg* and depend upon + the ``schedule`` directly identifying those periods as *stubs*. + + Below is an example of a standard EURIBOR 3M float leg. + + .. ipython:: python + + ibor_standard = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 22), + termination="1Y", + frequency="Q", + calendar="tgt", + payment_lag=0 + ), + currency="eur", + convention="Act360", + fixing_method="ibor(2)", + ) + ibor_standard.cashflows(rate_curve=curve) + + .. tab:: Unaligned IBOR + + To construct a *Leg* with a different tenor **IBOR** index to that of the schedule, + specify the ``fixing_frequency`` directly. + + Each :class:`~rateslib.periods.FloatPeriod` has an **Misaligned IBOR** or **IBOR Stub** + classification. Stubs can only appear at the front or back of the *Leg* and depend upon + the ``schedule`` directly identifying those periods as *stubs*. Stub *Periods* will have + the usual tenor interpolation applied, as with regular IBOR *Legs*, and does not factor + the misalignment into the calculation. + + Below is an example of a 1Y float leg with quarterly payments with each fixing to + four distinct EURIBOR 6M rates. + + .. ipython:: python + + ibor_misaligned = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 22), + termination="1Y", + frequency="Q", + calendar="tgt", + payment_lag=0, + ), + convention="Act360", + fixing_method="ibor(2)", + fixing_series="eur_ibor", + fixing_frequency="S", # <- frequency of fixing does not match schedule. + ) + ibor_misaligned.cashflows(rate_curve=curve) + + .. tab:: Multi-IBOR + + To construct a *Leg* with multiple IBOR tenor indexes compounded over a single + *Period* set ``zero_periods`` to True. Each *Period* will then be a + :class:`~rateslib.periods.ZeroFloatPeriod`. + + This means that each :class:`~rateslib.periods.ZeroFloatPeriod` will need to construct + a sub- :class:`~rateslib.scheduling.Schedule` to define its IBOR publications. Each + sub- :class:`~rateslib.scheduling.Schedule` has a *frequency* equal to + ``fixing_frequency`` and each *effective* and *termination* dates match the + *start* and *end* unadjusted accrual dates for each *Period* of the main + ``schedule``. When a stub is required, these sub-schedules take steer directly from the + :class:`~rateslib.data.fixings.FloatRateSeries` parameters. + + Note the ``float_spread`` is added to each individual + :class:`~rateslib.periods.FloatPeriod` and then all resultant rates are compounded to + yield the final rate for the :class:`~rateslib.periods.ZeroFloatPeriod` (this an + ISDA compounded type calculation). + + Two use cases of this have been identified; + + - Legacy US-LIBOR single currency basis swaps where the 3M-LIBOR was compounded over + a 6M period to net cashflows with the 6M *Leg*. An example is below: + + .. ipython:: python + + float_leg = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 22), + termination="1Y", + frequency="S", + calendar="nyc", + payment_lag=0 + ), + convention="Act360", + fixing_series="usd_ibor", + fixing_method="ibor(2)", + zero_periods=True, + fixing_frequency="Q", + float_spread=75.0, + ) + float_leg.cashflows(rate_curve=curve) + CustomLeg(float_leg.periods[0].float_periods).cashflows(rate_curve=curve) + + - CNY *IRS* with quarterly payments setting to 7D tenor rate. Note that these periods + are often not perfectly divisible, resulting in stub periods within each + :class:`~rateslib.periods.ZeroFloatPeriod`. The position and treatment of these + stubs can be controlled under the :class:`~rateslib.data.fixings.FloatRateSeries`. + + .. ipython:: python + + float_leg = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 21), + termination=dt(2027, 1, 21), + frequency="Q", + calendar="bjs", + ), + currency="CNY", + fixing_frequency="7d", + fixing_method="ibor(1)", + fixing_series=FloatRateSeries( + lag=1, + convention="Act365F", + calendar="bjs", + tenors=["7D"], + zero_period_stub="shortback", + modifier="F", + eom=False, + ), + zero_periods=True, + ) + + The individual fixing dates of each of these 7D periods are stored on each + *rate fixing* of each :class:`~rateslib.periods.FloatPeriod`. + + .. ipython:: python + + for float_period in float_leg.periods[0].float_periods: + print(float_period.rate_params.rate_fixing.date) + + """ # noqa: E501 @property def rate_params(self) -> _FloatRateParams: @@ -216,7 +448,7 @@ def periods(self) -> list[_BasePeriod]: if self._exchange_periods[0] is not None: periods_.append(self._exchange_periods[0]) - args: tuple[tuple[FloatPeriod | MtmCashflow | Cashflow, ...], ...] = ( + args: tuple[tuple[ZeroFloatPeriod | FloatPeriod | MtmCashflow | Cashflow, ...], ...] = ( self._regular_periods[:-1], ) if self._mtm_exchange_periods is not None: @@ -277,16 +509,23 @@ def __init__( float_spread: DualTypes_ = NoInput(0), rate_fixings: LegFixings = NoInput(0), fixing_method: FloatFixingMethod | str_ = NoInput(0), - method_param: int_ = NoInput(0), spread_compound_method: SpreadCompoundMethod | str_ = NoInput(0), fixing_frequency: Frequency | str_ = NoInput(0), fixing_series: FloatRateSeries | str_ = NoInput(0), + zero_periods: bool_ = NoInput(0), # index params index_base: DualTypes_ = NoInput(0), index_lag: int_ = NoInput(0), index_method: IndexMethod | str_ = NoInput(0), index_fixings: LegFixings = NoInput(0), ) -> None: + zero_periods_ = _drb(False, zero_periods) + del zero_periods + fixing_method_ = _get_float_fixing_method( + method=_drb(defaults.fixing_method, fixing_method) + ) + del fixing_method + self._schedule = schedule del schedule self._notional: DualTypes = _drb(defaults.notional, notional) @@ -299,7 +538,7 @@ def __init__( del currency self._convention: str = _drb(defaults.convention, convention) del convention - self._mtm = _get_let_mtm(mtm) + self._mtm = _get_leg_mtm(mtm) del mtm index_fixings_ = _leg_fixings_to_list(index_fixings, self.schedule.n_periods) @@ -359,49 +598,121 @@ def __init__( ) self._exchange_periods = (_ini_cf, _final_cf) - rate_fixings_list = _leg_fixings_to_list(rate_fixings, self._schedule.n_periods) - self._regular_periods = tuple( - [ - FloatPeriod( - float_spread=float_spread, - rate_fixings=rate_fixings_list[i], - fixing_method=fixing_method, - method_param=method_param, - spread_compound_method=spread_compound_method, - fixing_frequency=fixing_frequency, - fixing_series=fixing_series, - # currency args - payment=self.schedule.pschedule[i + 1], - currency=self._currency, - notional=self.amortization.outstanding[i], - ex_dividend=self.schedule.pschedule3[i + 1], - # period params - start=self.schedule.aschedule[i], - end=self.schedule.aschedule[i + 1], - frequency=self.schedule.frequency_obj, - convention=self._convention, - termination=self.schedule.aschedule[-1], - stub=self.schedule._stubs[i], - roll=NoInput(0), # defined by Frequency - calendar=self.schedule.calendar, - adjuster=self.schedule.accrual_adjuster, - # non-deliverable : Not allowed with notional exchange - pair=pair, - fx_fixings=fx_fixings_[0] - if self._mtm == LegMtm.Initial - else fx_fixings_[i + _mtm_param], - delivery=_fx_delivery(i, self._mtm, self.schedule, False, False), - # index params - index_base=index_base, - index_lag=index_lag, - index_method=index_method, - index_fixings=index_fixings_[i], - index_base_date=self._schedule.aschedule[0], - index_reference_date=self._schedule.aschedule[i + 1], + if not zero_periods_: + rate_fixings_list = _leg_fixings_to_list(rate_fixings, self._schedule.n_periods) + self._regular_periods: tuple[FloatPeriod | ZeroFloatPeriod, ...] = tuple( + [ + FloatPeriod( + float_spread=float_spread, + rate_fixings=rate_fixings_list[i], + fixing_method=fixing_method_, + spread_compound_method=spread_compound_method, + fixing_frequency=fixing_frequency, + fixing_series=fixing_series, + # currency args + payment=self.schedule.pschedule[i + 1], + currency=self._currency, + notional=self.amortization.outstanding[i], + ex_dividend=self.schedule.pschedule3[i + 1], + # period params + start=self.schedule.aschedule[i], + end=self.schedule.aschedule[i + 1], + frequency=self.schedule.frequency_obj, + convention=self._convention, + termination=self.schedule.aschedule[-1], + stub=self.schedule._stubs[i], + roll=NoInput(0), # defined by Frequency + calendar=self.schedule.calendar, + adjuster=self.schedule.accrual_adjuster, + # non-deliverable : Not allowed with notional exchange + pair=pair, + fx_fixings=fx_fixings_[0] + if self._mtm == LegMtm.Initial + else fx_fixings_[i + _mtm_param], + delivery=_fx_delivery(i, self._mtm, self.schedule, False, False), + # index params + index_base=index_base, + index_lag=index_lag, + index_method=index_method, + index_fixings=index_fixings_[i], + index_base_date=self._schedule.aschedule[0], + index_reference_date=self._schedule.aschedule[i + 1], + ) + for i in range(self._schedule.n_periods) + ] + ) + else: + if isinstance(fixing_frequency, NoInput): + raise ValueError( + "A `fixing_frequency` must be given to `FloatLeg` when " + "`zero_periods` is True.\nWhen using `zero_periods` the intention is to " + "create multiple floating rate periods on the leg which themselves are " + "constructed from multiple floating rate fixings compounded up.\n" + "Therefore more parameters are required to properly specify the scheduling.\n" + "See Notes." ) - for i in range(self._schedule.n_periods) - ] - ) + fixing_series_ = _init_float_rate_series( + fixing_series=fixing_series, + calendar=self._schedule.calendar, + convention=self._convention, + fixing_method=fixing_method_, + adjuster=self.schedule.accrual_adjuster, + ) + del fixing_series + # TODO: this fixings to list must account for sub zero periods - quite tricky + rate_fixings_list = _leg_fixings_to_list(rate_fixings, self._schedule.n_periods) + self._regular_periods = tuple( + [ + ZeroFloatPeriod( + schedule=Schedule( + # BBG appears to use the `aschedule` for defining these periods. + # rateslib uses the `uschedule` because it is more consistent from + # outer period to outer period, but more real life example are + # required to fully qualify what should be used here. + # Additionally if adjusted dates were used, rateslib inference means it + # might assert unadjusted start dates which may not align with the + # outer schedule. Matching unadjusted dates mitigates inconsistency. + effective=self.schedule.uschedule[i], + termination=self.schedule.uschedule[i + 1], + frequency=fixing_frequency, + payment_lag=self.schedule.payment_adjuster, + payment_lag_exchange=self.schedule.payment_adjuster2, + extra_lag=self.schedule.payment_adjuster3 + if self.schedule.payment_adjuster3 is not None + else NoInput(0), + calendar=self.schedule.calendar, + stub=fixing_series_.zero_period_stub, + ), + float_spread=float_spread, + rate_fixings=rate_fixings_list[i], + fixing_method=fixing_method_, + spread_compound_method=spread_compound_method, + fixing_frequency=fixing_frequency, + fixing_series=fixing_series_, + # currency args + currency=self._currency, + notional=self.amortization.outstanding[i], + # period params + convention=self._convention, + # non-deliverable : Not allowed with notional exchange + pair=pair, + fx_fixings=fx_fixings_[0] + if self._mtm == LegMtm.Initial + else fx_fixings_[i + _mtm_param], + delivery=_fx_delivery(i, self._mtm, self.schedule, False, False), + # index params + index_base=index_base, + index_lag=index_lag, + index_method=index_method, + index_fixings=index_fixings_[i], + index_base_date=self._schedule.aschedule[0], + index_reference_date=self._schedule.aschedule[i + 1], + # meta + metric="simple", # to ensure correct cals in the cashflow for the Leg + ) + for i in range(self._schedule.n_periods) + ] + ) # amortization exchanges if not final_exchange_ or self.amortization._type == _AmortizationType.NoAmortization: @@ -479,7 +790,7 @@ def _is_linear(self) -> bool: """ # ruff: noqa: SIM103 if ( - self.rate_params.fixing_method != FloatFixingMethod.IBOR + not isinstance(self.rate_params.fixing_method, FloatFixingMethod.IBOR) and self.rate_params.spread_compound_method != SpreadCompoundMethod.NoneSimple ): return False @@ -616,8 +927,6 @@ class ZeroFloatLeg(_BaseLeg): fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for each period. - method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -625,7 +934,7 @@ class ZeroFloatLeg(_BaseLeg): fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in each period rate determination. spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` @@ -635,7 +944,7 @@ class ZeroFloatLeg(_BaseLeg): rate_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` See :ref:`Fixings `. The value of the rate fixing. If a scalar, is used directly. If a string identifier, links - to the central ``fixings`` object and data loader. + to the central ``fixings`` object and data loader. See also :ref:`fixings `. .. note:: @@ -648,11 +957,12 @@ class ZeroFloatLeg(_BaseLeg): settlement. The *reference currency* is implied from ``pair``. Must include ``currency``. fx_fixings: float, Dual, Dual2, Variable, Series, str, 2-tuple or list, :green:`optional` The value of the :class:`~rateslib.data.fixings.FXFixing` for each *Period* according - to non-deliverability. Review the **notes** section non-deliverability. + to non-deliverability. Review the **notes** section non-deliverability + on a :class:`~rateslib.legs.FixedLeg` and see also :ref:`fixings `. mtm: bool, :green:`optional (set to False)` Define whether the non-deliverability depends on a single :class:`~rateslib.data.fixings.FXFixing` defined at the start of the *Leg*, or the end. - Review the **notes** section non-deliverability. + Review the **notes** section non-deliverability on a :class:`~rateslib.legs.FixedLeg`. .. note:: @@ -671,7 +981,7 @@ class ZeroFloatLeg(_BaseLeg): index_fixings: float, Dual, Dual2, Variable, Series, str, 2-tuple or list, :green:`optional` The index value for the reference date. Best practice is to supply this value as string identifier relating to the global - ``fixings`` object. + ``fixings`` object. See also :ref:`fixings `. """ @property @@ -735,7 +1045,6 @@ def __init__( float_spread: DualTypes_ = NoInput(0), rate_fixings: DualTypes | Series[DualTypes] | str_ = NoInput(0), # type: ignore[type-var] fixing_method: FloatFixingMethod | str_ = NoInput(0), - method_param: int_ = NoInput(0), spread_compound_method: SpreadCompoundMethod | str_ = NoInput(0), fixing_frequency: Frequency | str_ = NoInput(0), fixing_series: FloatRateSeries | str_ = NoInput(0), @@ -820,7 +1129,6 @@ def __init__( float_spread=float_spread, rate_fixings=rate_fixings, fixing_method=fixing_method, - method_param=method_param, spread_compound_method=spread_compound_method, fixing_frequency=fixing_frequency, fixing_series=fixing_series, diff --git a/python/rateslib/legs/protocols/analytic_delta.py b/python/rateslib/legs/protocols/analytic_delta.py index dbf42e683..777f9dabf 100644 --- a/python/rateslib/legs/protocols/analytic_delta.py +++ b/python/rateslib/legs/protocols/analytic_delta.py @@ -19,7 +19,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CurveOption_, DualTypes, FXForwards_, diff --git a/python/rateslib/legs/protocols/analytic_fixings.py b/python/rateslib/legs/protocols/analytic_fixings.py index efd4c8b91..7103f79c5 100644 --- a/python/rateslib/legs/protocols/analytic_fixings.py +++ b/python/rateslib/legs/protocols/analytic_fixings.py @@ -19,7 +19,7 @@ from rateslib.enums.generics import NoInput if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurveOption_, FXForwards_, Sequence, diff --git a/python/rateslib/legs/protocols/cashflows.py b/python/rateslib/legs/protocols/cashflows.py index 10c662284..6786d7bfa 100644 --- a/python/rateslib/legs/protocols/cashflows.py +++ b/python/rateslib/legs/protocols/cashflows.py @@ -19,7 +19,7 @@ from rateslib.enums.generics import NoInput if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurveOption_, FXForwards_, Schedule, diff --git a/python/rateslib/legs/protocols/fixings.py b/python/rateslib/legs/protocols/fixings.py index 9d97d7891..1a11ffc73 100644 --- a/python/rateslib/legs/protocols/fixings.py +++ b/python/rateslib/legs/protocols/fixings.py @@ -24,7 +24,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurveOption_, DualTypes, FXForwards_, diff --git a/python/rateslib/legs/protocols/npv.py b/python/rateslib/legs/protocols/npv.py index dea09c1b5..6e194bba8 100644 --- a/python/rateslib/legs/protocols/npv.py +++ b/python/rateslib/legs/protocols/npv.py @@ -20,7 +20,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( CurveOption_, DualTypes, FXForwards_, diff --git a/python/rateslib/typing.py b/python/rateslib/local_types.py similarity index 98% rename from python/rateslib/typing.py rename to python/rateslib/local_types.py index 63d81de89..f3a0fb956 100644 --- a/python/rateslib/typing.py +++ b/python/rateslib/local_types.py @@ -94,6 +94,7 @@ from rateslib.periods import FloatPeriod as FloatPeriod from rateslib.periods import FXCallPeriod as FXCallPeriod from rateslib.periods import FXPutPeriod as FXPutPeriod +from rateslib.periods import ZeroFloatPeriod as ZeroFloatPeriod from rateslib.periods import _BaseFXOptionPeriod as _BaseFXOptionPeriod from rateslib.periods.parameters import _FloatRateParams as _FloatRateParams from rateslib.periods.parameters import _IndexParams as _IndexParams @@ -113,6 +114,7 @@ NullInterpolator, UnionCal, ) +from rateslib.rs import StubInference as StubInference CurveInterpolator: TypeAlias = "FlatBackwardInterpolator | FlatForwardInterpolator | LinearInterpolator | LogLinearInterpolator | LinearZeroRateInterpolator | NullInterpolator" @@ -120,6 +122,7 @@ from rateslib.rs import Dual as Dual from rateslib.rs import Dual2 as Dual2 from rateslib.rs import Frequency as Frequency +from rateslib.rs import LegIndexBase as LegIndexBase from rateslib.rs import PPSplineDual as PPSplineDual from rateslib.rs import PPSplineDual2 as PPSplineDual2 from rateslib.rs import PPSplineF64 as PPSplineF64 diff --git a/python/rateslib/periods/cashflow.py b/python/rateslib/periods/cashflow.py index 97dd6c8ba..75dfbb2a0 100644 --- a/python/rateslib/periods/cashflow.py +++ b/python/rateslib/periods/cashflow.py @@ -31,7 +31,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CurveOption_, DualTypes, @@ -113,6 +113,7 @@ class Cashflow(_BasePeriodStatic): fx_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the :class:`~rateslib.data.fixings.FXFixing`. If a scalar is used directly. If a string identifier will link to the central ``fixings`` object and data loader. + See :ref:`fixings `. delivery: datetime, :green:`optional (set as 'payment')` The settlement delivery date of the :class:`~rateslib.data.fixings.FXFixing`. @@ -133,7 +134,7 @@ class Cashflow(_BasePeriodStatic): index_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The index value for the reference date. If a scalar value this is used directly. If a string identifier will link to the - central ``fixings`` object and data loader. + central ``fixings`` object and data loader. See :ref:`fixings `. index_base_date: datetime, :green:`optional` The reference date for determining the base index value. Not required if ``_index_base`` value is given directly. @@ -295,11 +296,11 @@ class MtmCashflow(_BasePeriodStatic): fx_fixings_start: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the first :class:`~rateslib.data.fixings.FXFixing`. If a scalar, is used directly. If a string identifier will link to the central ``fixings`` object and - data loader. + data loader. See :ref:`fixings `. fx_fixings_end: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the second :class:`~rateslib.data.fixings.FXFixing`. If a scalar, is used directly. If a string identifier will link to the central ``fixings`` object and - data loader. + data loader. See :ref:`fixings `. .. note:: @@ -318,7 +319,7 @@ class MtmCashflow(_BasePeriodStatic): index_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The index value for the reference date. If a scalar value this is used directly. If a string identifier will link to the - central ``fixings`` object and data loader. + central ``fixings`` object and data loader. See :ref:`fixings `. index_base_date: datetime, :green:`optional` The reference date for determining the base index value. Not required if ``_index_base`` value is given directly. diff --git a/python/rateslib/periods/credit.py b/python/rateslib/periods/credit.py index a5949e4c6..2f80d021f 100644 --- a/python/rateslib/periods/credit.py +++ b/python/rateslib/periods/credit.py @@ -11,13 +11,11 @@ from __future__ import annotations -from dataclasses import replace from datetime import timedelta from typing import TYPE_CHECKING import rateslib.errors as err from rateslib import defaults -from rateslib.dual import Variable, gradient from rateslib.dual.utils import _dual_float from rateslib.enums.generics import Err, NoInput, Ok, Result, _drb from rateslib.periods.parameters import ( @@ -27,15 +25,15 @@ _SettlementParams, ) from rateslib.periods.protocols import _BasePeriod -from rateslib.periods.utils import _try_validate_base_curve, _validate_credit_curves -from rateslib.scheduling import Frequency, get_calendar +from rateslib.periods.protocols.npv import _screen_ex_div_and_forward +from rateslib.periods.utils import _maybe_local, _try_validate_base_curve, _validate_credit_curves +from rateslib.scheduling import Convention, Frequency, get_calendar from rateslib.scheduling.adjuster import _get_adjuster from rateslib.scheduling.convention import _get_convention from rateslib.scheduling.frequency import _get_frequency if TYPE_CHECKING: # pragma: no cover - from rateslib.typing import ( - FX_, + from rateslib.local_types import ( Adjuster, CalInput, CurveOption_, @@ -131,6 +129,9 @@ class CreditPremiumPeriod(_BasePeriod): stub: bool, str, :green:`optional (set as False)` Whether the *Period* is defined as a stub according to some external :class:`~rateslib.scheduling.Schedule`. + roll: RollDay, int, str, :green:`optional (set by 'frequency')` + The rollday associated with any monthly :class:`~rateslib.scheduling.Frequency`, if + not directly associated with that object. adjuster: Adjuster, :green:`optional` The date :class:`~rateslib.scheduling.Adjuster` applied to unadjusted dates in the external :class:`~rateslib.scheduling.Schedule` to arrive at adjusted accrual dates. @@ -433,8 +434,6 @@ class CreditProtectionPeriod(_BasePeriod): The identified end date of the *Period*. frequency: Frequency, str, :red:`required` The :class:`~rateslib.scheduling.Frequency` associated with the *Period*. - convention: Convention, str, :green:`optional` (set by 'defaults') - The day count :class:`~rateslib.scheduling.Convention` associated with the *Period*. termination: datetime, :green:`optional` The termination date of an external :class:`~rateslib.scheduling.Schedule`. calendar: Calendar, :green:`optional` @@ -442,6 +441,9 @@ class CreditProtectionPeriod(_BasePeriod): stub: bool, str, :green:`optional (set as False)` Whether the *Period* is defined as a stub according to some external :class:`~rateslib.scheduling.Schedule`. + roll: RollDay, int, str, :green:`optional (set by 'frequency')` + The rollday associated with any monthly :class:`~rateslib.scheduling.Frequency`, if + not directly associated with that object. adjuster: Adjuster, :green:`optional` The date :class:`~rateslib.scheduling.Adjuster` applied to unadjusted dates in the external :class:`~rateslib.scheduling.Schedule` to arrive at adjusted accrual dates. @@ -470,7 +472,7 @@ def __init__( start: datetime, end: datetime, frequency: Frequency | str, - convention: str_ = NoInput(0), + # convention: str_ = NoInput(0), termination: datetime_ = NoInput(0), stub: bool = False, roll: RollDay | int | str_ = NoInput(0), @@ -494,7 +496,7 @@ def __init__( _calendar=get_calendar(calendar), _adjuster=NoInput(0) if isinstance(adjuster, NoInput) else _get_adjuster(adjuster), _stub=stub, - _convention=_get_convention(_drb(defaults.convention, convention)), + _convention=Convention.One, # _get_convention(_drb(defaults.convention, convention)), _termination=termination, ) @@ -550,7 +552,16 @@ def immediate_local_npv( fx_vol: _FXVolOption_ = NoInput(0), ) -> DualTypes: rate_curve_, disc_curve_ = _validate_credit_curves(rate_curve, disc_curve).unwrap() + quadrature = self._quadrature(rate_curve_, disc_curve_) + cf = self.cashflow(rate_curve=rate_curve) + return quadrature * cf + def _quadrature( + self, + rate_curve_: _BaseCurve, + disc_curve_: _BaseCurve, + ) -> DualTypes: + """determine the integral component of the NPV function using discretised intervals""" discretization = rate_curve_.meta.credit_discretization if self.period_params.start < rate_curve_.nodes.initial: @@ -570,9 +581,7 @@ def immediate_local_npv( value += 0.5 * (v1 + v2) * (q1 - q2) # value += v2 * (q1 - q2) - # curves are pre-validated so will not error - cf = self.cashflow(rate_curve=rate_curve) - return value * cf + return value def try_immediate_local_analytic_delta( self, @@ -589,38 +598,56 @@ def analytic_rec_risk( self, rate_curve: _BaseCurve_ = NoInput(0), disc_curve: _BaseCurve_ = NoInput(0), - fx: FX_ = NoInput(0), + fx: FXForwards_ = NoInput(0), base: str_ = NoInput(0), - ) -> float: + settlement: datetime_ = NoInput(0), + forward: datetime_ = NoInput(0), + ) -> DualTypes: """ Calculate the exposure of the NPV to a change in recovery rate. - For parameters see - :meth:`BasePeriod.analytic_delta()` + .. role:: red + + .. role:: green + + Parameters + ---------- + rate_curve: _BaseCurve, :red:`required` + Used to forecast credit parameters, such as hazard rates and recovery rates. + disc_curve: _BaseCurve, :red:`required` + Used to discount cashflows. + fx: FXForwards, :green:`optional` + The :class:`~rateslib.fx.FXForwards` object used for currency conversion. + base: str, :green:`optional` + The currency to convert the *local settlement* value into. + settlement: datetime, :green:`optional` + The assumed settlement date of the *PV* determination. Used only to evaluate + *ex-dividend* status. + forward: datetime, :green:`optional` + The future date to project the *PV* to using the ``disc_curve``. Returns ------- - float + float, Dual, Dual2 """ - c_res = _validate_credit_curves(rate_curve, disc_curve) - if isinstance(c_res, Err): - c_res.unwrap() - else: - rate_curve_, disc_curve_ = c_res.unwrap() - - haz_curve = rate_curve_.copy() - haz_curve._meta = replace( # type: ignore[misc] - rate_curve_.meta, - _credit_recovery_rate=Variable( - _dual_float(rate_curve_.meta.credit_recovery_rate), ["__rec_rate__"], [] - ), + rate_curve_, disc_curve_ = _validate_credit_curves(rate_curve, disc_curve).unwrap() + quadrature = self._quadrature(rate_curve_, disc_curve_) + local_immediate_value = quadrature * self.settlement_params.notional * 0.01 + + local_value = _screen_ex_div_and_forward( + local_value=Ok(local_immediate_value), + rate_curve=rate_curve, + disc_curve=disc_curve, + ex_dividend=self.settlement_params.ex_dividend, + settlement=settlement, + forward=forward, ) - pv: DualTypes = self.npv( # type: ignore[assignment] - rate_curve=haz_curve, - disc_curve=disc_curve_, - fx=fx, # type: ignore[arg-type] - base=base, + ret: DualTypes = _maybe_local( # type: ignore[assignment] # local is False + value=local_value.unwrap(), local=False, + currency=self.settlement_params.currency, + fx=fx, + base=base, + forward=forward, ) - _: float = _dual_float(gradient(pv, ["__rec_rate__"], order=1)[0]) - return _ * 0.01 + return ret diff --git a/python/rateslib/periods/fixed_period.py b/python/rateslib/periods/fixed_period.py index 527dd8ebd..7a48d870e 100644 --- a/python/rateslib/periods/fixed_period.py +++ b/python/rateslib/periods/fixed_period.py @@ -35,7 +35,7 @@ from rateslib.scheduling.frequency import _get_frequency if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CalInput, CurveOption_, @@ -131,6 +131,9 @@ class FixedPeriod(_BasePeriodStatic): stub: bool, str, :green:`optional (set as False)` Whether the *Period* is defined as a stub according to some external :class:`~rateslib.scheduling.Schedule`. + roll: RollDay, int, str, :green:`optional (set by 'frequency')` + The rollday associated with any monthly :class:`~rateslib.scheduling.Frequency`, if + not directly associated with that object. adjuster: Adjuster, :green:`optional` The date :class:`~rateslib.scheduling.Adjuster` applied to unadjusted dates in the external :class:`~rateslib.scheduling.Schedule` to arrive at adjusted accrual dates. @@ -153,6 +156,7 @@ class FixedPeriod(_BasePeriodStatic): fx_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the :class:`~rateslib.data.fixings.FXFixing`. If a scalar is used directly. If a string identifier will link to the central ``fixings`` object and data loader. + See :ref:`fixings `. delivery: datetime, :green:`optional (set as 'payment')` The settlement delivery date of the :class:`~rateslib.data.fixings.FXFixing`. @@ -173,7 +177,7 @@ class FixedPeriod(_BasePeriodStatic): index_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The index value for the reference date. If a scalar value this is used directly. If a string identifier will link to the - central ``fixings`` object and data loader. + central ``fixings`` object and data loader. See :ref:`fixings `. index_base_date: datetime, :green:`optional` The reference date for determining the base index value. Not required if ``_index_base`` value is given directly. @@ -458,6 +462,7 @@ class ZeroFixedPeriod(_BasePeriodStatic): fx_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the :class:`~rateslib.data.fixings.FXFixing`. If a scalar is used directly. If a string identifier will link to the central ``fixings`` object and data loader. + See :ref:`fixings `. delivery: datetime, :green:`optional (set as 'payment')` The settlement delivery date of the :class:`~rateslib.data.fixings.FXFixing`. @@ -479,6 +484,7 @@ class ZeroFixedPeriod(_BasePeriodStatic): The index value for the reference date. If a scalar value this is used directly. If a string identifier will link to the central ``fixings`` object and data loader. + See :ref:`fixings `. index_only: bool, :green:`optional (set as False)` A flag which determines non-payment of notional on supported *Periods*. @@ -693,7 +699,7 @@ def cashflows( Returns ------- - dict of values + dict[Any] """ d = super().cashflows( rate_curve=rate_curve, diff --git a/python/rateslib/periods/float_period.py b/python/rateslib/periods/float_period.py index d6dc9ad91..97915f2c5 100644 --- a/python/rateslib/periods/float_period.py +++ b/python/rateslib/periods/float_period.py @@ -50,7 +50,7 @@ from rateslib.scheduling.frequency import _get_frequency, _get_tenor_from_frequency if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, Arr1dObj, CalInput, @@ -98,8 +98,8 @@ class FloatPeriod(_BasePeriodStatic): .. ipython:: python :suppress: - from rateslib.periods import FloatPeriod - from rateslib import fixings + from rateslib import FloatPeriod, Frequency, fixings, FloatRateSeries + from rateslib.enums import SpreadCompoundMethod, FloatFixingMethod from datetime import datetime as dt from pandas import Series @@ -113,8 +113,7 @@ class FloatPeriod(_BasePeriodStatic): notional=1e6, convention="Act360", frequency="S", - fixing_method="ibor", - method_param=0, + fixing_method="ibor(0)", rate_fixings="MY_RATE_INDEX" ) period.cashflows() @@ -160,6 +159,9 @@ class FloatPeriod(_BasePeriodStatic): stub: bool, str, :green:`optional (set as False)` Whether the *Period* is defined as a stub according to some external :class:`~rateslib.scheduling.Schedule`. + roll: RollDay, int, str, :green:`optional (set by 'frequency')` + The rollday associated with any monthly :class:`~rateslib.scheduling.Frequency`, if + not directly associated with that object. adjuster: Adjuster, :green:`optional` The date :class:`~rateslib.scheduling.Adjuster` applied to unadjusted dates in the external :class:`~rateslib.scheduling.Schedule` to arrive at adjusted accrual dates. @@ -171,8 +173,6 @@ class FloatPeriod(_BasePeriodStatic): fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for the period. - method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -180,17 +180,17 @@ class FloatPeriod(_BasePeriodStatic): fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in the period rate determination. If not given is set to zero. spread_compound_method: SpreadCompoundMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.SpreadCompoundMethod` used in the calculation - of the period rate when combining a ``float_spread``. Used **only** with RFR type - ``fixing_method``. + of the period rate when combining a ``float_spread``. Used **only** with (non-averaging) + RFR type ``fixing_method``. rate_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the rate fixing. If a scalar, is used directly. If a string identifier, links - to the central ``fixings`` object and data loader. + to the central ``fixings`` object and data loader. See :ref:`fixings `. .. note:: @@ -203,6 +203,7 @@ class FloatPeriod(_BasePeriodStatic): fx_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the :class:`~rateslib.data.fixings.FXFixing`. If a scalar is used directly. If a string identifier will link to the central ``fixings`` object and data loader. + See :ref:`fixings `. delivery: datetime, :green:`optional (set as 'payment')` The settlement delivery date of the :class:`~rateslib.data.fixings.FXFixing`. @@ -223,7 +224,7 @@ class FloatPeriod(_BasePeriodStatic): index_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The index value for the reference date. If a scalar value this is used directly. If a string identifier will link to the - central ``fixings`` object and data loader. + central ``fixings`` object and data loader. See :ref:`fixings `. index_base_date: datetime, :green:`optional` The reference date for determining the base index value. Not required if ``_index_base`` value is given directly. @@ -233,43 +234,141 @@ class FloatPeriod(_BasePeriodStatic): index_only: bool, :green:`optional (set as False)` A flag which determines non-payment of notional on supported *Periods*. + Notes + ----- + + **Five** different classifications of *FloatPeriod* are possible to construct. + + .. tabs:: + + .. tab:: RFR - .. Examples - -------- - - A typical RFR type :class:`~rateslib.periods.FloatPeriod`. - - .. ipython:: python - :supress: - - from rateslib.periods import FloatPeriod - from rateslib.data.fixings import FloatRateIndex - from datetime import datetime as dt - - .. ipython:: python - - period = FloatPeriod( - start=dt(2025, 9, 22), - end=dt(2025, 10, 20), - payment=dt(2025, 10, 22), - frequency="1M", - ) + A standard *RFR* period consists of multiple *'1B'* overnight fixings compounded + over the *Period* to determine the *rate*. It is specified by using any non-averaging + *RFR* ``fixing_method``. This variant constructs an + :class:`~rateslib.data.fixings.RFRFixing` as the object to coordinate *rate* + calculation. It will depend on ``spread_compound_method`` to incorporate a + ``float_spread`` into the calculation. The ``fixing_frequency`` is *'1B'* under this + method. + + .. ipython:: python + + fp = FloatPeriod( + start=dt(2026, 1, 22), + end=dt(2027, 1, 22), + payment=dt(2027, 1, 25), + frequency=Frequency.Months(12, None), # <- or "A" + fixing_method=FloatFixingMethod.RFRPaymentDelay(), # <- or "rfr_payment_delay" + float_spread=5.0, + spread_compound_method=SpreadCompoundMethod.NoneSimple, # <- or "NoneSimple" + ) + fp.rate_params.rate_fixing + + .. tab:: Average RFR + + This type is the same as **RFR** but uses an averaging ``fixing_method`` variant. + ``spread_compound_method`` cannot be used and can only be *'NoneSimple'*. + + .. ipython:: python + + fp = FloatPeriod( + start=dt(2026, 1, 22), + end=dt(2027, 1, 22), + payment=dt(2027, 1, 25), + frequency=Frequency.Months(12, None), # <- or "A" + fixing_method=FloatFixingMethod.RFRPaymentDelayAverage(), # <- or "rfr_payment_delay_avg" + float_spread=5.0, + ) + fp.rate_params.rate_fixing + + .. warning:: + + The :meth:`~rateslib.periods.FloatPeriod.rate` method does **not** make any + *convexity adjustments* for an averaging type versus the numéraire compounding type + and determines a *rate* under the direct calculations from a provided *rate Curve*. + + .. tab:: IBOR + + This type, for legacy tenor **IBOR** rates, such as US-LIBOR, GBP-LIBOR, and existing + tenor rates such as EURIBOR, STIBOR, NIBOR, BB3M etc. uses a single fixing period. It is + specified by an *'ibor'* ``fixing_method``. + + When the period is regular it will create an :class:`~rateslib.data.fixings.IBORFixing` + with a ``fixing_frequency`` that aligns with that of the *Period*. + + .. ipython:: python + + fp = FloatPeriod( + start=dt(2026, 1, 22), + end=dt(2026, 4, 22), + payment=dt(2026, 4, 22), + frequency=Frequency.Months(3, None), # <- or "Q" + fixing_method=FloatFixingMethod.IBOR(2), # <- or "ibor(2)" + float_spread=5.0, + ) + fp.rate_params.rate_fixing + + .. tab:: Misaligned IBOR + + The ``fixing_frequency`` and ``fixing_series`` allow custom definitions of an IBOR + *FloatPeriod* to be created, such as using a 6M tenor with a 3M period, or using + mixed accrual calendars that do not align with the IBOR definition. + + .. ipython:: python + + fp = FloatPeriod( + start=dt(2026, 2, 4), + end=dt(2026, 5, 7), # <- Tokyo holidays on 4th, 5th, 6th May + payment=dt(2026, 5, 7), + frequency=Frequency.Months(3, None), # <- or "Q" + fixing_method=FloatFixingMethod.IBOR(2), # <- or "ibor(2)" + calendar="tyo,nyc", + float_spread=5.0, + fixing_series="usd_ibor", # <- or define your own FloatRateSeries + fixing_frequency=Frequency.Months(6, None), # <- or "S" + ) + fp.rate_params.rate_fixing + + .. tab:: IBOR Stubs + + IBOR stub periods can also be created which utilise an + :class:`~rateslib.data.fixings.IBORStubFixing`, for *rate* determination. These + must be identified by the ``stub`` flag. + *IBOR* stubs depend upon the ``tenors`` definition with the ``fixing_series`` + (or by ['1W', '1M', '3M', '6M', '12M'] when omitted) + + When using these in combinations with ``fixings`` all necessary date timeseries must + be available under the appropriate ``identifier``, e.g. *'STIBOR_1M'* and *'STIBOR_2M'*. + + .. ipython:: python + + fixings.add("STIBOR_1M", Series(data=[1.0], index=[dt(2026, 2, 2)])) + fixings.add("STIBOR_2M", Series(data=[2.0], index=[dt(2026, 2, 2)])) + fp = FloatPeriod( + start=dt(2026, 2, 4), + end=dt(2026, 3, 12), + payment=dt(2026, 3, 12), + frequency=Frequency.Months(6, None), # <- or "S" + stub=True, + fixing_method=FloatFixingMethod.IBOR(2), # <- or "ibor(2)" + calendar="stk", + float_spread=5.0, + fixing_series=FloatRateSeries( + lag=2, calendar="stk", modifier="MF", convention="act360", + eom=False, tenors=["2D", "1W", "1M", "2M", "3M", "6M"], + ), + rate_fixings="STIBOR", + ) + fp.rate_params.rate_fixing + fp.rate_params.rate_fixing.value - A typical IBOR tenor type :class:`~rateslib.periods.FloatPeriod`. - - .. ipython:: python + .. ipython:: python + :suppress: - period = FloatPeriod( - start=dt(2025, 9, 22), - end=dt(2025, 10, 22), - payment=dt(2025, 10, 22), - frequency="1M", - currency="eur", - fixing_method="IBOR", - fixing_series="eur_IBOR", - ) + fixings.pop("STIBOR_1M") + fixings.pop("STIBOR_2M") - """ + """ # noqa: E501 @property def rate_params(self) -> _FloatRateParams: @@ -286,7 +385,6 @@ def __init__( float_spread: DualTypes_ = NoInput(0), rate_fixings: DualTypes | Series[DualTypes] | str_ = NoInput(0), # type: ignore[type-var] fixing_method: FloatFixingMethod | str_ = NoInput(0), - method_param: int_ = NoInput(0), spread_compound_method: SpreadCompoundMethod | str_ = NoInput(0), fixing_frequency: Frequency | str_ = NoInput(0), fixing_series: FloatRateSeries | str_ = NoInput(0), @@ -351,7 +449,6 @@ def __init__( _index_reference_date=_drb(self.period_params.end, index_reference_date), ) self._rate_params = _init_FloatRateParams( - _method_param=method_param, _float_spread=float_spread, _spread_compound_method=spread_compound_method, _fixing_method=fixing_method, @@ -366,6 +463,21 @@ def __init__( _period_frequency=self.period_params.frequency, _period_stub=self.period_params.stub, ) + if self.rate_params.spread_compound_method in [ + SpreadCompoundMethod.ISDACompounding, + SpreadCompoundMethod.ISDAFlatCompounding, + ] and type(self.rate_params.fixing_method) in [ + FloatFixingMethod.IBOR, + FloatFixingMethod.RFRPaymentDelayAverage, + FloatFixingMethod.RFRLookbackAverage, + FloatFixingMethod.RFRLockoutAverage, + FloatFixingMethod.RFRObservationShiftAverage, + ]: + raise ValueError( + f"The input for `spread_compound_method`: " + f"{self.rate_params.spread_compound_method} is not compatible with the " + f"`fixing_method`: {self.rate_params.fixing_method}." + ) def unindexed_reference_cashflow( self, @@ -426,7 +538,7 @@ def try_unindexed_reference_cashflow_analytic_rate_fixings( if isinstance(rate_curve, NoInput): return Err(ValueError(err.VE_NEEDS_RATE_CURVE)) - if self.rate_params.fixing_method == FloatFixingMethod.IBOR: + if isinstance(self.rate_params.fixing_method, FloatFixingMethod.IBOR): return _UnindexedReferenceCashflowFixingsSensitivity._ibor( self=self, rate_curve=rate_curve ) @@ -485,7 +597,6 @@ def try_rate(self, rate_curve: CurveOption_) -> Result[DualTypes]: rate_curve=NoInput(0) if rate_curve is None else rate_curve, rate_fixings=self.rate_params.rate_fixing.identifier, fixing_method=self.rate_params.fixing_method, - method_param=self.rate_params.method_param, spread_compound_method=self.rate_params.spread_compound_method, float_spread=self.rate_params.float_spread, stub=self.period_params.stub, @@ -500,7 +611,6 @@ def try_rate(self, rate_curve: CurveOption_) -> Result[DualTypes]: rate_curve=NoInput(0), rate_fixings=rate_fixing, fixing_method=self.rate_params.fixing_method, - method_param=self.rate_params.method_param, spread_compound_method=self.rate_params.spread_compound_method, float_spread=self.rate_params.float_spread, stub=self.period_params.stub, @@ -554,10 +664,9 @@ class ZeroFloatPeriod(_BasePeriodStatic): )) period = ZeroFloatPeriod( schedule=Schedule(dt(2000, 1, 1), "2Y", "S"), - fixing_method="IBOR", + fixing_method="IBOR(0)", rate_fixings="MY_RATE_INDEX", convention="Act360", - method_param=0, ) period.cashflows() @@ -580,6 +689,16 @@ class ZeroFloatPeriod(_BasePeriodStatic): Parameters ---------- . + .. note:: + + The following parameters are scheduling **period** parameters + + schedule: Schedule, :red:`required` + The :class:`~rateslib.scheduling.Schedule` defining the individual *Periods*, including + the *payment* and *ex-dividend* dates. + convention: Convention, str, :green:`optional (set by 'defaults')` + The day count :class:`~rateslib.scheduling.Convention` associated with the *Period*. + .. note:: The following define generalised **settlement** parameters. @@ -589,14 +708,6 @@ class ZeroFloatPeriod(_BasePeriodStatic): notional: float, Dual, Dual2, Variable, :green:`optional (set by 'defaults')` The notional amount of the *Period* expressed in ``notional currency``. - .. note:: - - The following parameters are scheduling **period** parameters - - schedule: Schedule, :red:`required` - The :class:`~rateslib.scheduling.Schedule` defining the individual *Periods*, including - the *payment* and *ex-dividend* dates. - .. note:: The following define **floating rate** parameters. @@ -604,8 +715,6 @@ class ZeroFloatPeriod(_BasePeriodStatic): fixing_method: FloatFixingMethod, str, :green:`optional (set by 'defaults')` The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for the period. - method_param: int, :green:`optional (set by 'defaults')` - A specific parameter that is used by the specific ``fixing_method``. fixing_frequency: Frequency, str, :green:`optional (set by 'frequency' or '1B')` The :class:`~rateslib.scheduling.Frequency` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given is assumed to match the @@ -613,7 +722,7 @@ class ZeroFloatPeriod(_BasePeriodStatic): fixing_series: FloatRateSeries, str, :green:`optional (implied by other parameters)` The :class:`~rateslib.data.fixings.FloatRateSeries` as a component of the :class:`~rateslib.data.fixings.FloatRateIndex`. If not given inherits attributes given - such as the ``calendar``, ``convention``, ``method_param`` etc. + such as the ``calendar``, ``convention``, ``fixing_method`` etc. float_spread: float, Dual, Dual2, Variable, :green:`optional (set as 0.0)` The amount (in bps) added to the rate in the period rate determination. If not given is set to zero. @@ -623,7 +732,7 @@ class ZeroFloatPeriod(_BasePeriodStatic): ``fixing_method``. rate_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the rate fixing. If a scalar, is used directly. If a string identifier, links - to the central ``fixings`` object and data loader. + to the central ``fixings`` object and data loader. See :ref:`fixings `. .. note:: @@ -636,6 +745,7 @@ class ZeroFloatPeriod(_BasePeriodStatic): fx_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the :class:`~rateslib.data.fixings.FXFixing`. If a scalar is used directly. If a string identifier will link to the central ``fixings`` object and data loader. + See :ref:`fixings `. delivery: datetime, :green:`optional (set as 'payment')` The settlement delivery date of the :class:`~rateslib.data.fixings.FXFixing`. @@ -656,10 +766,23 @@ class ZeroFloatPeriod(_BasePeriodStatic): index_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The index value for the reference date. If a scalar value this is used directly. If a string identifier will link to the - central ``fixings`` object and data loader. + central ``fixings`` object and data loader. See :ref:`fixings `. + index_base_date: datetime, :green:`optional (set as aschedule[0])` + The reference date for determining the base index value. Not used if ``_index_base`` + value is given directly. + index_reference_date: datetime, :green:`optional (set as aschedule[1])` + The reference date for determining the index value. Not used if ``_index_fixings`` + is given as a scalar value. index_only: bool, :green:`optional (set as False)` A flag which determines non-payment of notional on supported *Periods*. + .. note:: + + The following are meta parameters + + metric: str, :green:`optional (set as 'compounding')` + The type of calculation to use in the :meth:`~rateslib.periods.ZeroFloatPeriod.rate` method. + """ # noqa: E501 @property @@ -667,6 +790,11 @@ def rate_params(self) -> _FloatRateParams: """The :class:`~rateslib.periods.parameters._FixedRateParams` of the *Period*.""" return self.float_periods[0].rate_params + @property + def rate_metric(self) -> str: + """The type of calculation to perform in :meth:`~rateslib.periods.ZeroFloatPeriod.rate`.""" + return self._rate_metric + @property def period_params(self) -> _PeriodParams: """The :class:`~rateslib.periods.parameters._PeriodParams` of the *Period*.""" @@ -715,15 +843,14 @@ def float_periods(self) -> list[FloatPeriod]: def __init__( self, + schedule: Schedule, *, float_spread: DualTypes_ = NoInput(0), rate_fixings: DualTypes | Series[DualTypes] | str_ = NoInput(0), # type: ignore[type-var] fixing_method: FloatFixingMethod | str_ = NoInput(0), - method_param: int_ = NoInput(0), spread_compound_method: SpreadCompoundMethod | str_ = NoInput(0), fixing_frequency: Frequency | str_ = NoInput(0), fixing_series: FloatRateSeries | str_ = NoInput(0), - schedule: Schedule, # currency args: notional: DualTypes_ = NoInput(0), currency: str_ = NoInput(0), @@ -738,8 +865,13 @@ def __init__( index_lag: int_ = NoInput(0), index_method: IndexMethod | str_ = NoInput(0), index_fixings: DualTypes | Series[DualTypes] | str_ = NoInput(0), # type: ignore[type-var] + index_base_date: datetime_ = NoInput(0), + index_reference_date: datetime_ = NoInput(0), index_only: bool_ = NoInput(0), + # meta-args: + metric: str_ = NoInput(0), ) -> None: + self._rate_metric: str = _drb("compounding", metric).lower() self._schedule = schedule self._settlement_params = _init_SettlementParams_with_fx_pair( _currency=_drb(defaults.base_currency, currency).lower(), @@ -760,7 +892,9 @@ def __init__( _frequency=self.schedule.frequency_obj, _calendar=self.schedule.calendar, _adjuster=self.schedule.modifier, - _stub=True, + _stub=not self.schedule.frequency_obj.is_uregular( + self.schedule.uschedule[0], self.schedule.uschedule[-1] + ), _convention=_get_convention(_drb(defaults.convention, convention)), _termination=self.schedule.aschedule[-1], ) @@ -770,8 +904,8 @@ def __init__( _index_method=index_method, _index_fixings=index_fixings, _index_only=index_only, - _index_base_date=self.schedule.aschedule[0], - _index_reference_date=self.schedule.aschedule[-1], + _index_base_date=_drb(self.schedule.aschedule[0], index_base_date), + _index_reference_date=_drb(self.schedule.aschedule[-1], index_reference_date), ) rate_fixings_ = _leg_fixings_to_list(rate_fixings, self.schedule.n_periods) self._float_periods: list[FloatPeriod] = [ @@ -779,7 +913,6 @@ def __init__( float_spread=float_spread, rate_fixings=rate_fixings_[i], fixing_method=fixing_method, - method_param=method_param, spread_compound_method=spread_compound_method, fixing_frequency=fixing_frequency, fixing_series=fixing_series, @@ -816,10 +949,16 @@ def try_rate( except Exception as e: return Err(e) - f = self.schedule.periods_per_annum - r = np.prod(1.0 + np.array(r_i) * np.array(d_i) / 100.0) - r = r ** (1.0 / (self.dcf * f)) - r = (r - 1) * f * 100.0 + if self.rate_metric == "compounding": + f = self.schedule.periods_per_annum + r = np.prod(1.0 + np.array(r_i) * np.array(d_i) / 100.0) + r = r ** (1.0 / (self.dcf * f)) + r = (r - 1) * f * 100.0 + elif self.rate_metric == "simple": + r = np.prod(1.0 + np.array(r_i) * np.array(d_i) / 100.0) + r = (r - 1.0) * 100.0 / self.dcf + else: + return Err(ValueError("`rate_metric` must be 'simple' or 'compounding'.")) return Ok(r) def rate(self, *, rate_curve: CurveOption_ = NoInput(0)) -> DualTypes: @@ -1032,7 +1171,7 @@ def _ibor_stub( rate_curve=rate_curve_1, frequency_str=tenors[0], ) - if tenors[0] == tenors[1]: + if len(tenors) == 1 or tenors[0] == tenors[1]: return df1_res # then no multiple curves for the stub else: rate_curve_2: _BaseCurve = _get_ibor_curve_from_dict2(tenors[1], rate_curve) @@ -1120,13 +1259,13 @@ def _rfr_drdr_approximation( z = self.rate_params.float_spread fixing_method = self.rate_params.fixing_method spread_compound_method = self.rate_params.spread_compound_method - method_param = self.rate_params.method_param + method_param = self.rate_params.fixing_method.method_param() # approximate sensitivity to each fixing z = z / 100.0 d = d_hat_i.sum() - if fixing_method in [ + if type(fixing_method) in [ FloatFixingMethod.RFRLockoutAverage, FloatFixingMethod.RFRObservationShiftAverage, FloatFixingMethod.RFRLookbackAverage, @@ -1153,7 +1292,6 @@ def _rfr_drdr_approximation( fixing_rates=r_i, fixing_dcfs=d_hat_i, fixing_method=fixing_method, - method_param=method_param, spread_compound_method=spread_compound_method, float_spread=self.rate_params.float_spread, ).unwrap() @@ -1177,7 +1315,10 @@ def _rfr_drdr_approximation( r_i_ = r_i.to_numpy() drdri = d_hat_i / (1 + d_hat_i * r_i_ / 100.0) * ((r_star - z) / 100.0 * d + 1) / d - if fixing_method in [FloatFixingMethod.RFRLockoutAverage, FloatFixingMethod.RFRLockout]: + if type(fixing_method) in [ + FloatFixingMethod.RFRLockoutAverage, + FloatFixingMethod.RFRLockout, + ]: for i in range(method_param): drdri[-(method_param + 1)] += drdri[-(i + 1)] drdri[-(i + 1)] = 0.0 diff --git a/python/rateslib/periods/float_rate.py b/python/rateslib/periods/float_rate.py index ab665d3ee..6ded06466 100644 --- a/python/rateslib/periods/float_rate.py +++ b/python/rateslib/periods/float_rate.py @@ -28,7 +28,7 @@ from rateslib.scheduling.frequency import _get_frequency if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CurveOption_, DualTypes, DualTypes_, @@ -50,8 +50,7 @@ def rate_value( rate_fixings: DualTypes_ | str = NoInput(0), frequency: Frequency | str_ = NoInput(0), rate_series: FloatRateSeries | str_ = NoInput(0), - fixing_method: FloatFixingMethod | str = FloatFixingMethod.RFRPaymentDelay, - method_param: int = 0, + fixing_method: FloatFixingMethod | str = FloatFixingMethod.RFRPaymentDelay(), spread_compound_method: SpreadCompoundMethod | str = SpreadCompoundMethod.NoneSimple, float_spread: DualTypes = 0.0, stub: bool = False, @@ -64,7 +63,6 @@ def rate_value( frequency=frequency, rate_fixings=rate_fixings, fixing_method=fixing_method, - method_param=method_param, spread_compound_method=spread_compound_method, float_spread=float_spread, stub=stub, @@ -79,8 +77,7 @@ def try_rate_value( rate_series: FloatRateSeries | str_ = NoInput(0), frequency: Frequency | str_ = NoInput(0), rate_fixings: DualTypes | Series[DualTypes] | str_ = NoInput(0), # type: ignore[type-var] - fixing_method: FloatFixingMethod | str = FloatFixingMethod.RFRPaymentDelay, - method_param: int = 0, + fixing_method: FloatFixingMethod | str = FloatFixingMethod.RFRPaymentDelay(), spread_compound_method: SpreadCompoundMethod | str = SpreadCompoundMethod.NoneSimple, float_spread: DualTypes = 0.0, stub: bool = False, @@ -93,14 +90,14 @@ def try_rate_value( fm = _get_float_fixing_method(fixing_method) scm = _get_spread_compound_method(spread_compound_method) rs = _get_float_rate_series_or_blank(rate_series) - if fm == FloatFixingMethod.IBOR: + if type(fm) is FloatFixingMethod.IBOR: return _IBORRate._rate( start=start, end=end, rate_curve=rate_curve, rate_fixings=rate_fixings, - method_param=method_param, float_spread=_drb(0.0, float_spread), + lag=fm.method_param(), stub=stub, rate_series=rs, frequency=_get_frequency(frequency, NoInput(0), NoInput(0)), @@ -116,7 +113,6 @@ def try_rate_value( rate_curve=rate_curve_, rate_fixings=rate_fixings, fixing_method=fm, - method_param=method_param, spread_compound_method=scm, float_spread=float_spread, rate_series=rs, diff --git a/python/rateslib/periods/fx_volatility.py b/python/rateslib/periods/fx_volatility.py index 8679e67ef..41b5960d5 100644 --- a/python/rateslib/periods/fx_volatility.py +++ b/python/rateslib/periods/fx_volatility.py @@ -12,10 +12,10 @@ from __future__ import annotations from abc import ABCMeta, abstractmethod +from datetime import timezone from typing import TYPE_CHECKING import numpy as np -from pytz import UTC import rateslib.errors as err from rateslib import defaults @@ -69,7 +69,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, Arr1dF64, DualTypes, @@ -87,6 +87,8 @@ str_, ) +UTC = timezone.utc + class _BaseFXOptionPeriod(_BasePeriodStatic, _WithAnalyticFXOptionGreeks, metaclass=ABCMeta): r""" @@ -930,6 +932,7 @@ class FXCallPeriod(_BaseFXOptionPeriod): option_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the option :class:`~rateslib.data.fixings.FXFixing`. If a scalar, is used directly. If a string identifier, links to the central ``fixings`` object and data loader. + See :ref:`fixings `. ex_dividend: datetime, :green:`optional (set as 'delivery')` The ex-dividend date of the settled cashflow. @@ -1031,6 +1034,7 @@ class FXPutPeriod(_BaseFXOptionPeriod): option_fixings: float, Dual, Dual2, Variable, Series, str, :green:`optional` The value of the option :class:`~rateslib.data.fixings.FXFixing`. If a scalar, is used directly. If a string identifier, links to the central ``fixings`` object and data loader. + See :ref:`fixings `. ex_dividend: datetime, :green:`optional (set as 'delivery')` The ex-dividend date of the settled cashflow. diff --git a/python/rateslib/periods/parameters/fx_volatility.py b/python/rateslib/periods/parameters/fx_volatility.py index 307d19562..3a6700381 100644 --- a/python/rateslib/periods/parameters/fx_volatility.py +++ b/python/rateslib/periods/parameters/fx_volatility.py @@ -19,7 +19,7 @@ from rateslib.enums.parameters import FXOptionMetric, _get_fx_option_metric if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( DualTypes, DualTypes_, FXDeltaMethod, diff --git a/python/rateslib/periods/parameters/index.py b/python/rateslib/periods/parameters/index.py index fe2356f52..7e189e05d 100644 --- a/python/rateslib/periods/parameters/index.py +++ b/python/rateslib/periods/parameters/index.py @@ -32,7 +32,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Any, DualTypes, DualTypes_, diff --git a/python/rateslib/periods/parameters/mtm.py b/python/rateslib/periods/parameters/mtm.py index d890726d6..071b763c2 100644 --- a/python/rateslib/periods/parameters/mtm.py +++ b/python/rateslib/periods/parameters/mtm.py @@ -20,7 +20,7 @@ from rateslib.periods.parameters.settlement import _init_fx_fixing if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( DualTypes, FXFixing, FXForwards_, diff --git a/python/rateslib/periods/parameters/period.py b/python/rateslib/periods/parameters/period.py index 16a83af7b..057fd530d 100644 --- a/python/rateslib/periods/parameters/period.py +++ b/python/rateslib/periods/parameters/period.py @@ -20,7 +20,7 @@ from rateslib.scheduling import Convention, Frequency, dcf if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Adjuster_, CalTypes, datetime, diff --git a/python/rateslib/periods/parameters/rate.py b/python/rateslib/periods/parameters/rate.py index 497c003ce..3c3f36d83 100644 --- a/python/rateslib/periods/parameters/rate.py +++ b/python/rateslib/periods/parameters/rate.py @@ -38,12 +38,12 @@ _get_float_fixing_method, _get_spread_compound_method, ) -from rateslib.scheduling import Convention, Frequency +from rateslib.scheduling import Convention, Frequency, StubInference from rateslib.scheduling.adjuster import _convert_to_adjuster from rateslib.scheduling.frequency import _get_frequency, _get_tenor_from_frequency if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Adjuster, Adjuster_, CalTypes, @@ -51,7 +51,6 @@ DualTypes_, PeriodFixings, datetime, - int_, str_, ) @@ -60,7 +59,6 @@ def _init_FloatRateParams( _float_spread: DualTypes_, _rate_fixings: PeriodFixings, _fixing_method: FloatFixingMethod | str_, - _method_param: int_, _spread_compound_method: SpreadCompoundMethod | str_, _fixing_frequency: Frequency | str_, _fixing_series: FloatRateSeries | str_, @@ -78,30 +76,18 @@ def _init_FloatRateParams( spread_compound_method = _get_spread_compound_method( _drb(defaults.spread_compound_method, _spread_compound_method) ) - if isinstance(_method_param, NoInput): - method_param = defaults.fixing_method_param[fixing_method] - else: - method_param = _method_param - if isinstance(_fixing_series, NoInput): - # modifier is defaulted to days only type if RFR based - fixing_series = FloatRateSeries( - lag=method_param, - calendar=_period_calendar, - convention=_period_convention, - modifier=_convert_to_adjuster( - modifier=_drb(defaults.modifier, _period_adjuster), - settlement=False, - mod_days=fixing_method != FloatFixingMethod.IBOR, - ), - eom=defaults.eom, - ) - else: - fixing_series = _get_float_rate_series(_fixing_series) + fixing_series: FloatRateSeries = _init_float_rate_series( + fixing_series=_fixing_series, + calendar=_period_calendar, + convention=_period_convention, + adjuster=_period_adjuster, + fixing_method=fixing_method, + ) float_spread = _drb(0.0, _float_spread) if isinstance(_fixing_frequency, NoInput): - if fixing_method == FloatFixingMethod.IBOR: + if type(fixing_method) is FloatFixingMethod.IBOR: fixing_frequency = _period_frequency else: fixing_frequency = Frequency.BusDays(1, fixing_series.calendar) @@ -115,7 +101,7 @@ def _init_FloatRateParams( series=fixing_series, ) - if fixing_method == FloatFixingMethod.IBOR and not _period_stub: + if type(fixing_method) is FloatFixingMethod.IBOR and not _period_stub: if isinstance(_rate_fixings, Series): result = IBORFixing._lookup( timeseries=_rate_fixings, @@ -141,7 +127,7 @@ def _init_FloatRateParams( value=_rate_fixings if not isinstance(_rate_fixings, str) else NoInput(0), identifier=identifier, ) - elif fixing_method == FloatFixingMethod.IBOR and _period_stub: + elif type(fixing_method) is FloatFixingMethod.IBOR and _period_stub: if isinstance(_rate_fixings, Series): result = IBORFixing._lookup( timeseries=_rate_fixings, @@ -171,7 +157,6 @@ def _init_FloatRateParams( accrual_start=_accrual_start, accrual_end=_accrual_end, fixing_method=fixing_method, - method_param=method_param, fixing_calendar=fixing_index.calendar, ) dcfs_dcf = _RFRRate._get_dcf_values( @@ -184,7 +169,6 @@ def _init_FloatRateParams( result = RFRFixing._lookup( timeseries=_rate_fixings, fixing_method=fixing_method, - method_param=method_param, spread_compound_method=spread_compound_method, float_spread=float_spread, dates_obs=np.array( @@ -199,7 +183,6 @@ def _init_FloatRateParams( accrual_start=_accrual_start, accrual_end=_accrual_end, fixing_method=fixing_method, - method_param=method_param, value=result, identifier=NoInput(0), ) @@ -213,7 +196,6 @@ def _init_FloatRateParams( accrual_start=_accrual_start, accrual_end=_accrual_end, fixing_method=fixing_method, - method_param=method_param, float_spread=float_spread, spread_compound_method=spread_compound_method, value=_rate_fixings if not isinstance(_rate_fixings, str) else NoInput(0), @@ -226,11 +208,52 @@ def _init_FloatRateParams( _fixing_series=fixing_series, _fixing_frequency=fixing_frequency, _fixing_method=fixing_method, - _method_param=method_param, _rate_fixing=rate_fixing, ) +def _init_float_rate_series( + fixing_series: FloatRateSeries | str_, + calendar: CalTypes, + convention: Convention, + fixing_method: FloatFixingMethod, + adjuster: Adjuster | NoInput, +) -> FloatRateSeries: + if not isinstance(fixing_series, NoInput): + fixing_series_ = _get_float_rate_series(fixing_series) + del fixing_series + + if ( + isinstance(fixing_method, FloatFixingMethod.IBOR) + and fixing_method.method_param() != fixing_series_.lag + ): + raise ValueError( + "A `fixing_series` has been provided with a publication `lag` that does not " + f"match the `param` of the `fixing_method`.\nGot {fixing_series_.lag} and " + f"{fixing_method.method_param()} respectively." + ) + return fixing_series_ + + else: + # modifier is defaulted to days only type if RFR based + if type(fixing_method) is FloatFixingMethod.IBOR: + lag = fixing_method.method_param() + else: + lag = 0 + return FloatRateSeries( + lag=lag, + calendar=calendar, + convention=convention, + modifier=_convert_to_adjuster( + modifier=_drb(defaults.modifier, adjuster), + settlement=False, + mod_days=not isinstance(fixing_method, FloatFixingMethod.IBOR), + ), + eom=defaults.eom, + zero_period_stub=StubInference.ShortBack, # TODO: hard coded default replaced? + ) + + class _CreditParams: """ Parameters associated with credit related *Periods*. @@ -284,8 +307,6 @@ class _FloatRateParams: _fixing_method: FloatFixingMethod The :class:`~rateslib.enums.parameters.FloatFixingMethod` describing the determination of the floating rate for the period. - _method_param: int - A specific parameter that is used by the specific ``fixing_method``. _fixing_series: FloatRateSeries, The :class:`~rateslib.enums.parameters.FloatRateSeries` of the :class:`~rateslib.enums.parameters.FloatRateIndex` defining the specific interest @@ -308,7 +329,6 @@ def __init__( self, *, _fixing_method: FloatFixingMethod, - _method_param: int, _fixing_series: FloatRateSeries, _fixing_frequency: Frequency, _float_spread: DualTypes, @@ -323,7 +343,6 @@ def __init__( series=_fixing_series, ) self._float_spread: DualTypes = _float_spread - self._method_param: int = _method_param self._rate_fixing: IBORFixing | IBORStubFixing | RFRFixing = _rate_fixing self._validate_combinations_args() @@ -343,7 +362,7 @@ def fixing_index(self) -> FloatRateIndex: @cached_property def fixing_date(self) -> datetime: """The relevant date of the (first) rate fixing for the *Period*.""" - if self.fixing_method in [ + if type(self.fixing_method) in [ FloatFixingMethod.RFRPaymentDelay, FloatFixingMethod.RFRPaymentDelayAverage, FloatFixingMethod.RFRLockout, @@ -399,7 +418,7 @@ def accrual_start(self) -> datetime: The accrual start date for the *Period*. Fixing dates will be measured relative to this date under appropriate calendars and - ``method_param`` + ``fixing_method`` """ return self.rate_fixing.accrual_start @@ -408,7 +427,7 @@ def accrual_end(self) -> datetime: """The accrual end date for the *Period*. Final fixing dates (or IBOR stub weights) will be measured relative to this date under - appropriate calendars and ``method_param``. + appropriate calendars and ``fixing_method``. """ return self.rate_fixing.accrual_end @@ -423,11 +442,6 @@ def fixing_method(self) -> FloatFixingMethod: the floating rate for the period.""" return self._fixing_method - @property - def method_param(self) -> int: - """A parameter used by the ``fixing_method``.""" - return self._method_param - @property def float_spread(self) -> DualTypes: """The amount (in bps) added to the rate in the period rate determination.""" @@ -458,21 +472,15 @@ def _validate_combinations_args(self) -> None: ------- tuple """ - if self.method_param != 0 and self.fixing_method in [ - FloatFixingMethod.RFRPaymentDelay, - FloatFixingMethod.RFRPaymentDelayAverage, - ]: - raise ValueError( - "`method_param` should not be used (or a value other than 0) when " - f"using a `fixing_method` of 'RFRPaymentDelay' type, got {self.method_param}. " - f"Configure the `payment_lag` option instead to have the " - f"appropriate effect.", - ) - elif self.method_param < 1 and self.fixing_method in [ - FloatFixingMethod.RFRLockout, - FloatFixingMethod.RFRLockoutAverage, - ]: + if ( + type(self.fixing_method) + in [ + FloatFixingMethod.RFRLockout, + FloatFixingMethod.RFRLockoutAverage, + ] + and self.fixing_method.method_param() < 1 + ): raise ValueError( f'`method_param` must be >0 for "RFRLockout" type `fixing_method`, ' - f"got {self.method_param}", + f"got {self.fixing_method.method_param()}", ) diff --git a/python/rateslib/periods/parameters/settlement.py b/python/rateslib/periods/parameters/settlement.py index 147601f0c..61903299c 100644 --- a/python/rateslib/periods/parameters/settlement.py +++ b/python/rateslib/periods/parameters/settlement.py @@ -25,7 +25,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, DualTypes, DualTypes_, diff --git a/python/rateslib/periods/protocols/analytic_delta.py b/python/rateslib/periods/protocols/analytic_delta.py index a4dabe640..7c1c52d5d 100644 --- a/python/rateslib/periods/protocols/analytic_delta.py +++ b/python/rateslib/periods/protocols/analytic_delta.py @@ -28,7 +28,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CurveOption_, DualTypes, FXForwards_, diff --git a/python/rateslib/periods/protocols/analytic_fixings.py b/python/rateslib/periods/protocols/analytic_fixings.py index 42061b499..91609f0ab 100644 --- a/python/rateslib/periods/protocols/analytic_fixings.py +++ b/python/rateslib/periods/protocols/analytic_fixings.py @@ -24,7 +24,7 @@ from rateslib.periods.protocols.npv import _screen_ex_div_and_forward if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CurveOption_, FXForwards_, Result, diff --git a/python/rateslib/periods/protocols/analytic_greeks.py b/python/rateslib/periods/protocols/analytic_greeks.py index 3b7246a60..21c222cc0 100644 --- a/python/rateslib/periods/protocols/analytic_greeks.py +++ b/python/rateslib/periods/protocols/analytic_greeks.py @@ -26,7 +26,7 @@ from rateslib.splines import evaluate if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, DualTypes, DualTypes_, diff --git a/python/rateslib/periods/protocols/cashflows.py b/python/rateslib/periods/protocols/cashflows.py index af94cdc08..b37e0ddef 100644 --- a/python/rateslib/periods/protocols/cashflows.py +++ b/python/rateslib/periods/protocols/cashflows.py @@ -35,7 +35,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover Any, CurveOption_, DualTypes, @@ -158,7 +158,7 @@ def cashflows( Returns ------- - dict of values + dict[Any] """ standard_elements = _standard_elements(self=self) period_elements = _period_elements(self=self) @@ -316,7 +316,7 @@ def cashflows( Returns ------- - dict of values + dict[Any] """ standard_elements = _standard_elements(self=self) period_elements = _period_elements(self=self) diff --git a/python/rateslib/periods/protocols/fixings.py b/python/rateslib/periods/protocols/fixings.py index daa7d4a25..785b19879 100644 --- a/python/rateslib/periods/protocols/fixings.py +++ b/python/rateslib/periods/protocols/fixings.py @@ -31,7 +31,7 @@ from rateslib.periods.protocols.npv import _WithNPV if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CurveOption_, DualTypes, FXForwards_, @@ -96,7 +96,6 @@ def reset_fixings(self, state: int_ = NoInput(0)) -> None: payment=dt(2026, 1, 16), frequency="M", fixing_method="rfr_payment_delay", - method_param=0, rate_fixings="sofr" ) fixings.add( diff --git a/python/rateslib/periods/protocols/npv.py b/python/rateslib/periods/protocols/npv.py index 5c36b2593..6bee914d3 100644 --- a/python/rateslib/periods/protocols/npv.py +++ b/python/rateslib/periods/protocols/npv.py @@ -29,7 +29,7 @@ ) if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover FX_, CurveOption_, DualTypes, diff --git a/python/rateslib/periods/utils.py b/python/rateslib/periods/utils.py index 4c7ef87a4..a74ebb114 100644 --- a/python/rateslib/periods/utils.py +++ b/python/rateslib/periods/utils.py @@ -24,7 +24,7 @@ from rateslib.fx_volatility import FXDeltaVolSmile, FXDeltaVolSurface, FXSabrSmile, FXSabrSurface if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( FX_, Any, CurveOption_, diff --git a/python/rateslib/rs.pyi b/python/rateslib/rs.pyi index 70765609a..a3712e32b 100644 --- a/python/rateslib/rs.pyi +++ b/python/rateslib/rs.pyi @@ -16,13 +16,24 @@ from typing import TYPE_CHECKING, Any from typing_extensions import Self if TYPE_CHECKING: - from rateslib.typing import Arr1dF64, Arr2dF64, CalTypes, CurveInterpolator, DualTypes, Number + from rateslib.local_types import ( + Arr1dF64, + Arr2dF64, + CalTypes, + CurveInterpolator, + DualTypes, + Number, + ) class ADOrder: Zero: ADOrder One: ADOrder Two: ADOrder +class LegIndexBase: + Initial: LegIndexBase + PeriodOnPeriod: LegIndexBase + class Imm: Wed3_HMUZ: Imm Wed3: Imm @@ -36,6 +47,7 @@ class Imm: Wed1_Post9_HMUZ: Imm Eom: Imm Leap: Imm + Som: Imm def next(self, date: datetime) -> datetime: ... def validate(self, date: datetime) -> bool: ... @@ -47,7 +59,7 @@ class _Scheduling: def next(self, date: datetime) -> datetime: ... def uprevious(self, udate: datetime) -> datetime: ... def previous(self, date: datetime) -> datetime: ... - def uregular(self, ueffective: datetime, utermination: datetime) -> datetime: ... + def uregular(self, ueffective: datetime, utermination: datetime) -> list[datetime]: ... def infer_ustub( self, ueffective: datetime, utermination: datetime, short: bool, front: bool ) -> datetime: ... @@ -56,6 +68,7 @@ class _Scheduling: class _FrequencyMixins: def string(self) -> str: ... def is_stub(self, ustart: datetime, uend: datetime, front: bool) -> bool: ... + def is_uregular(self, ueffective: datetime, utermination: datetime) -> bool: ... class Frequency(_Scheduling, _FrequencyMixins): class CalDays(Frequency): @@ -81,6 +94,7 @@ class StubInference: LongFront: StubInference ShortBack: StubInference LongBack: StubInference + NeitherSide: StubInference def to_json(self) -> str: ... @@ -198,6 +212,50 @@ class Adjuster(_Adjustment): def to_json(self) -> str: ... +class _MethodParam: + def method_param(self) -> int: ... + +class FloatFixingMethod(_MethodParam): + class RFRPaymentDelay(FloatFixingMethod): ... + + class RFRObservationShift(FloatFixingMethod): + param: int + def __init__(self, param: int) -> None: ... + + class RFRLockout(FloatFixingMethod): + param: int + def __init__(self, param: int) -> None: ... + + class RFRLookback(FloatFixingMethod): + param: int + def __init__(self, param: int) -> None: ... + + class RFRPaymentDelayAverage(FloatFixingMethod): ... + + class RFRObservationShiftAverage(FloatFixingMethod): + param: int + def __init__(self, param: int) -> None: ... + + class RFRLockoutAverage(FloatFixingMethod): + param: int + def __init__(self, param: int) -> None: ... + + class RFRLookbackAverage(FloatFixingMethod): + param: int + def __init__(self, param: int) -> None: ... + + class IBOR(FloatFixingMethod): + param: int + def __init__(self, param: int) -> None: ... + + def to_json(self) -> str: ... + +class CalendarManager: + def add(self, name: str, calendar: Cal) -> None: ... + def pop(self, name: str) -> Cal | UnionCal: ... + def get(self, name: str) -> NamedCal: ... + def keys(self) -> list[str]: ... + class _DateRoll: def add_bus_days(self, date: datetime, days: int, settlement: bool) -> datetime: ... def add_cal_days(self, date: datetime, days: int, adjuster: Adjuster) -> datetime: ... @@ -215,6 +273,8 @@ class _DateRoll: def is_settlement(self, date: datetime) -> bool: ... def lag_bus_days(self, date: datetime, days: int, settlement: bool) -> datetime: ... def to_json(self) -> str: ... + def print(self, year: int, month: int | None = None) -> str: ... + def print_compare(self, comparator: Cal | UnionCal | NamedCal, year: int) -> str: ... class _CalendarAdjustment: def adjust(self, date: datetime, adjuster: Adjuster) -> datetime: ... @@ -228,6 +288,8 @@ class Cal(_DateRoll, _CalendarAdjustment): class UnionCal(_DateRoll, _CalendarAdjustment): calendars: list[Cal] = ... settlement_calendars: list[Cal] = ... + @classmethod + def from_name(cls, name: str) -> UnionCal: ... def __init__( self, calendars: list[Cal], @@ -235,8 +297,10 @@ class UnionCal(_DateRoll, _CalendarAdjustment): ) -> None: ... class NamedCal(_DateRoll, _CalendarAdjustment): - union_cal: UnionCal = ... + inner: UnionCal | Cal = ... + name: str = ... def __init__(self, name: str) -> None: ... + def inner_ptr_eq(self, other: NamedCal) -> bool: ... class Ccy: def __init__(self, name: str) -> None: ... diff --git a/python/rateslib/scheduling/__init__.py b/python/rateslib/scheduling/__init__.py index c36765656..069ff1ef1 100644 --- a/python/rateslib/scheduling/__init__.py +++ b/python/rateslib/scheduling/__init__.py @@ -12,7 +12,17 @@ from __future__ import annotations import rateslib.rs -from rateslib.rs import Adjuster, Cal, Frequency, Imm, NamedCal, RollDay, StubInference, UnionCal +from rateslib.rs import ( + Adjuster, + Cal, + CalendarManager, + Frequency, + Imm, + NamedCal, + RollDay, + StubInference, + UnionCal, +) from rateslib.scheduling.calendars import get_calendar from rateslib.scheduling.convention import Convention from rateslib.scheduling.dcfs import dcf @@ -21,28 +31,35 @@ from rateslib.scheduling.schedule import Schedule # Patch the namespace for pyo3 pickling: see https://github.com/PyO3/pyo3/discussions/5226 -rateslib.rs.RollDay_Day = rateslib.rs.RollDay.Day # type: ignore[attr-defined] -rateslib.rs.RollDay_IMM = rateslib.rs.RollDay.IMM # type: ignore[attr-defined] - -rateslib.rs.PyAdjuster_Actual = rateslib.rs.Adjuster.Actual # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_Following = rateslib.rs.Adjuster.Following # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_ModifiedFollowing = rateslib.rs.Adjuster.ModifiedFollowing # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_Previous = rateslib.rs.Adjuster.Previous # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_ModifiedPrevious = rateslib.rs.Adjuster.ModifiedPrevious # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_FollowingSettle = rateslib.rs.Adjuster.FollowingSettle # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_ModifiedFollowingSettle = rateslib.rs.Adjuster.ModifiedFollowingSettle # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_PreviousSettle = rateslib.rs.Adjuster.PreviousSettle # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_ModifiedPreviousSettle = rateslib.rs.Adjuster.ModifiedPreviousSettle # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_BusDaysLagSettle = rateslib.rs.Adjuster.BusDaysLagSettle # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_CalDaysLagSettle = rateslib.rs.Adjuster.CalDaysLagSettle # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_FollowingExLast = rateslib.rs.Adjuster.FollowingExLast # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_FollowingExLastSettle = rateslib.rs.Adjuster.FollowingExLastSettle # type: ignore[attr-defined] -rateslib.rs.PyAdjuster_BusDaysLagSettleInAdvance = rateslib.rs.Adjuster.BusDaysLagSettleInAdvance # type: ignore[attr-defined] - -rateslib.rs.Frequency_CalDays = rateslib.rs.Frequency.CalDays # type: ignore[attr-defined] -rateslib.rs.Frequency_BusDays = rateslib.rs.Frequency.BusDays # type: ignore[attr-defined] -rateslib.rs.Frequency_Months = rateslib.rs.Frequency.Months # type: ignore[attr-defined] -rateslib.rs.Frequency_Zero = rateslib.rs.Frequency.Zero # type: ignore[attr-defined] +# rateslib.rs.RollDay_Day = rateslib.rs.RollDay.Day # type: ignore[attr-defined] +# rateslib.rs.RollDay_IMM = rateslib.rs.RollDay.IMM # type: ignore[attr-defined] + + +class PicklingContainer: + pass + + +rateslib.rs.PyAdjuster = PicklingContainer() # type: ignore[attr-defined] + +rateslib.rs.PyAdjuster.Actual = rateslib.rs.Adjuster.Actual # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.Following = rateslib.rs.Adjuster.Following # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.ModifiedFollowing = rateslib.rs.Adjuster.ModifiedFollowing # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.Previous = rateslib.rs.Adjuster.Previous # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.ModifiedPrevious = rateslib.rs.Adjuster.ModifiedPrevious # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.FollowingSettle = rateslib.rs.Adjuster.FollowingSettle # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.ModifiedFollowingSettle = rateslib.rs.Adjuster.ModifiedFollowingSettle # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.PreviousSettle = rateslib.rs.Adjuster.PreviousSettle # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.ModifiedPreviousSettle = rateslib.rs.Adjuster.ModifiedPreviousSettle # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.BusDaysLagSettle = rateslib.rs.Adjuster.BusDaysLagSettle # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.CalDaysLagSettle = rateslib.rs.Adjuster.CalDaysLagSettle # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.FollowingExLast = rateslib.rs.Adjuster.FollowingExLast # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.FollowingExLastSettle = rateslib.rs.Adjuster.FollowingExLastSettle # type: ignore[attr-defined] +rateslib.rs.PyAdjuster.BusDaysLagSettleInAdvance = rateslib.rs.Adjuster.BusDaysLagSettleInAdvance # type: ignore[attr-defined] +# +# rateslib.rs.Frequency_CalDays = rateslib.rs.Frequency.CalDays # type: ignore[attr-defined] +# rateslib.rs.Frequency_BusDays = rateslib.rs.Frequency.BusDays # type: ignore[attr-defined] +# rateslib.rs.Frequency_Months = rateslib.rs.Frequency.Months # type: ignore[attr-defined] +# rateslib.rs.Frequency_Zero = rateslib.rs.Frequency.Zero # type: ignore[attr-defined] Imm.__doc__ = """ Enumerable type for International Money-Market (IMM) date definitions. @@ -66,7 +83,7 @@ from rateslib.rs import Adjuster variants = [item for item in Adjuster.__dict__ if \\ "__" != item[:2] and \\ - item not in ['adjust', 'adjusts'] \ + item not in ['adjust', 'adjusts', 'to_json', 'reverse'] \ ] .. ipython:: python @@ -135,28 +152,35 @@ """ NamedCal.__doc__ = """ -A wrapped :class:`~rateslib.scheduling.UnionCal` constructed with a string parsing syntax. +A wrapped :class:`~rateslib.scheduling.Cal` or +:class:`~rateslib.scheduling.UnionCal` constructed with a string parsing syntax. + +This instance can only be constructed from named :class:`~rateslib.scheduling.Cal` objects that +have already been populated to the ``calendars`` :class:`~rateslib.scheduling.CalendarManager`. +Each *NamedCal* uses data shared in memory and does **not** reconstruct or copy the entire +list of holidays for every instantiation of this class. Parameters ---------- name: str The names of the calendars to populate the ``calendars`` and ``settlement_calendars`` arguments of a :class:`~rateslib.scheduling.UnionCal`. The individual calendar names must - pre-exist in the :ref:`defaults `. The pipe operator separates the two - fields. + pre-exist in the :class:`~rateslib.scheduling.CalendarManager`. The pipe operator + separates the two fields. Examples -------- .. ipython:: python :suppress: - from rateslib.scheduling import NamedCal + from rateslib.scheduling import NamedCal, UnionCal .. ipython:: python named_cal = NamedCal("ldn,tgt|fed") - assert len(named_cal.union_cal.calendars) == 2 - assert len(named_cal.union_cal.settlement_calendars) == 1 + assert isinstance(named_cal.inner, UnionCal) + assert len(named_cal.inner.calendars) == 2 + assert len(named_cal.inner.settlement_calendars) == 1 """ __all__ = ( @@ -164,6 +188,7 @@ "Cal", "NamedCal", "UnionCal", + "CalendarManager", "Adjuster", "Convention", "Frequency", diff --git a/python/rateslib/scheduling/adjuster.py b/python/rateslib/scheduling/adjuster.py index abd787b62..b0a30e709 100644 --- a/python/rateslib/scheduling/adjuster.py +++ b/python/rateslib/scheduling/adjuster.py @@ -17,7 +17,7 @@ from rateslib.rs import Adjuster if TYPE_CHECKING: - from rateslib.typing import str_ + from rateslib.local_types import str_ _A = { # Provides the map of all available string to Adjuster conversions. "NONESETTLE": Adjuster.Actual(), diff --git a/python/rateslib/scheduling/calendars.py b/python/rateslib/scheduling/calendars.py index 61fe32ab3..1b889843f 100644 --- a/python/rateslib/scheduling/calendars.py +++ b/python/rateslib/scheduling/calendars.py @@ -13,33 +13,30 @@ from typing import TYPE_CHECKING -from rateslib import defaults +from rateslib import calendars from rateslib.enums.generics import NoInput -from rateslib.rs import Cal, NamedCal, UnionCal from rateslib.scheduling.adjuster import _convert_to_adjuster if TYPE_CHECKING: - from rateslib.typing import CalInput, CalTypes, datetime + from rateslib.local_types import CalInput, CalTypes, datetime def get_calendar( calendar: CalInput, - named: bool = True, ) -> CalTypes: """ - Returns a calendar object either from an available set or a user defined input. + Returns a calendar object, possible constructed by the + :class:`~rateslib.scheduling.CalendarManager`. + + .. role:: red + + .. role:: green Parameters ---------- - calendar : str, Cal, UnionCal, NamedCal + calendar : str, Cal, UnionCal, NamedCal, :red:`required` If `str`, then the calendar is returned from pre-calculated values. If a specific user defined calendar this is returned without modification. - named : bool - If the calendar is more complex than a pre-existing single name calendar, then - this argument determines if a :class:`~rateslib.scheduling.NamedCal` object, which is more - compactly serialized but slower to create, or a :class:`~rateslib.scheduling.UnionCal` - object, which is faster to create but with more verbose serialization is returned. - The default prioritises serialization. Returns ------- @@ -48,24 +45,8 @@ def get_calendar( Notes ----- - The following named calendars are available and have been back tested against the - publication of RFR indexes in the relevant geography. - - - *"all"*: Every day is defined as business day including weekends. - - *"bus"*: Regular weekdays are defined as business days. Saturdays and Sunday are - non-business days. - - *"tgt"*: Target for Europe's ESTR. - - *"osl"*: Oslo for Norway's NOWA. - - *"zur"*: Zurich for Switzerland's SARON. - - *"nyc"*: New York City for US's SOFR. - - *"fed"*: Similar to *"nyc"* but omitting Good Friday. - - *"ldn"*: London for UK's SONIA. - - *"stk"*: Stockholm for Sweden's SWESTR. - - *"tro"*: Toronto for Canada's CORRA. - - *"tyo"*: Tokyo for Japan's TONA. - - *"syd"*: Sydney for Australia's AONIA. - - *"wlg"*: Wellington for New Zealand's OCR and BKBM. - - *"mum"*: Mumbai for India's FBIL o/n rate. + Please see the :ref:`defaults ` section of the documentation to discover + which named calendars are base implemented to *rateslib*. Combined calendars can be created with comma separated input, e.g. *"tgt,nyc"*. This would be the typical calendar assigned to a cross-currency derivative such as a EUR/USD @@ -87,7 +68,7 @@ def get_calendar( .. ipython:: python tgt_cal = get_calendar("tgt") - tgt_cal.holidays[300:312] + print(tgt_cal.print(2023, 5)) tgt_cal.add_bus_days(dt(2023, 1, 3), 5, True) type(tgt_cal) @@ -95,86 +76,19 @@ def get_calendar( .. ipython:: python - tgt_and_nyc_cal = get_calendar("tgt,nyc", named=False) - tgt_and_nyc_cal.holidays[300:312] + tgt_and_nyc_cal = get_calendar("tgt,nyc") + print(tgt_and_nyc_cal.print(2023, 5)) type(tgt_and_nyc_cal) """ if isinstance(calendar, str): - # parse the string in Python and return Rust Cal/UnionCal objects directly - calendar = calendar.replace(" ", "") - if calendar in defaults.calendars: - return defaults.calendars[calendar] - return _parse_str_calendar(calendar, named) + return calendars.get(calendar) elif isinstance(calendar, NoInput): - return defaults.calendars["all"] + return calendars.get("all") else: # calendar is a Calendar object type return calendar -def _parse_str_calendar(calendar: str, named: bool) -> CalTypes: - """Parse the calendar string using Python and construct calendar objects.""" - vectors = calendar.split("|") - if len(vectors) == 1: - return _parse_str_calendar_no_associated(vectors[0], named) - elif len(vectors) == 2: - return _parse_str_calendar_with_associated(vectors[0], vectors[1], named) - else: - raise ValueError("Cannot use more than one pipe ('|') operator in `calendar`.") - - -def _parse_str_calendar_no_associated(calendar: str, named: bool) -> CalTypes: - calendars = calendar.lower().split(",") - if len(calendars) == 1: # only one named calendar is found - return defaults.calendars[calendars[0]] # lookup Hashmap - else: - # combined calendars are not yet predefined so this does not benefit from hashmap speed - if named: - return NamedCal(calendar) - else: - cals = [defaults.calendars[_] for _ in calendars] - cals_: list[Cal] = [] - for cal in cals: - if isinstance(cal, Cal): - cals_.append(cal) - elif isinstance(cal, NamedCal): - cals_.extend(cal.union_cal.calendars) - else: - cals_.extend(cal.calendars) - return UnionCal(cals_, None) - - -def _parse_str_calendar_with_associated( - calendar: str, associated_calendar: str, named: bool -) -> CalTypes: - if named: - return NamedCal(calendar + "|" + associated_calendar) - else: - calendars = calendar.lower().split(",") - cals = [defaults.calendars[_] for _ in calendars] - cals_ = [] - for cal in cals: - if isinstance(cal, Cal): - cals_.append(cal) - elif isinstance(cal, NamedCal): - cals_.extend(cal.union_cal.calendars) - else: - cals_.extend(cal.calendars) - - settlement_calendars = associated_calendar.lower().split(",") - sets = [defaults.calendars[_] for _ in settlement_calendars] - sets_: list[Cal] = [] - for cal in sets: - if isinstance(cal, Cal): - sets_.append(cal) - elif isinstance(cal, NamedCal): - sets_.extend(cal.union_cal.calendars) - else: - sets_.extend(cal.calendars) - - return UnionCal(cals_, sets_) - - def _get_years_and_months(d1: datetime, d2: datetime) -> tuple[int, int]: """ Get the whole number of years and months between two dates diff --git a/python/rateslib/scheduling/dcfs.py b/python/rateslib/scheduling/dcfs.py index 565658b7f..8cc657337 100644 --- a/python/rateslib/scheduling/dcfs.py +++ b/python/rateslib/scheduling/dcfs.py @@ -24,7 +24,7 @@ from rateslib.scheduling.frequency import _get_frequency_none if TYPE_CHECKING: - from rateslib.typing import Any, CalInput, Callable, bool_, datetime_, int_, str_ + from rateslib.local_types import Any, CalInput, Callable, bool_, datetime_, int_, str_ def dcf( diff --git a/python/rateslib/scheduling/frequency.py b/python/rateslib/scheduling/frequency.py index 90f3a4193..0bd5a8442 100644 --- a/python/rateslib/scheduling/frequency.py +++ b/python/rateslib/scheduling/frequency.py @@ -23,7 +23,7 @@ from rateslib.utils.calendars import _get_first_bus_day if TYPE_CHECKING: - from rateslib.typing import CalInput, datetime_, int_, str_ + from rateslib.local_types import CalInput, datetime_, int_, str_ def _get_frequency( @@ -100,7 +100,7 @@ def _get_tenor_from_frequency(frequency: Frequency) -> str: return f"{frequency.number}M" elif isinstance(frequency, Frequency.CalDays): if frequency.number % 7 == 0: - return f"{frequency.number / 7}W" + return f"{int(frequency.number / 7)}W" else: return f"{frequency.number}D" elif isinstance(frequency, Frequency.BusDays): diff --git a/python/rateslib/scheduling/imm.py b/python/rateslib/scheduling/imm.py index ddddaf644..5a6b852a7 100644 --- a/python/rateslib/scheduling/imm.py +++ b/python/rateslib/scheduling/imm.py @@ -19,7 +19,7 @@ from rateslib.rs import Imm if TYPE_CHECKING: - from rateslib.typing import int_, str_ + from rateslib.local_types import int_, str_ _Imm: dict[str, Imm] = { @@ -40,6 +40,7 @@ "wed1_post9_hmuz": Imm.Wed1_Post9_HMUZ, "eom": Imm.Eom, "leap": Imm.Leap, + "som": Imm.Som, } diff --git a/python/rateslib/scheduling/rollday.py b/python/rateslib/scheduling/rollday.py index a52440ecb..940c638e8 100644 --- a/python/rateslib/scheduling/rollday.py +++ b/python/rateslib/scheduling/rollday.py @@ -17,7 +17,7 @@ from rateslib.rs import Adjuster, Imm, RollDay if TYPE_CHECKING: - from rateslib.typing import CalTypes, int_ + from rateslib.local_types import CalTypes, int_ def _get_rollday(roll: RollDay | str | int_) -> RollDay | None: diff --git a/python/rateslib/scheduling/schedule.py b/python/rateslib/scheduling/schedule.py index 02e7cfbf9..2d8c41c69 100644 --- a/python/rateslib/scheduling/schedule.py +++ b/python/rateslib/scheduling/schedule.py @@ -28,7 +28,7 @@ from rateslib.scheduling.rollday import _is_eom_cal if TYPE_CHECKING: - from rateslib.typing import ( + from rateslib.local_types import ( Adjuster_, Any, CalInput, @@ -42,11 +42,12 @@ def _get_stub_inference( stub: str | StubInference, front_stub: datetime_, back_stub: datetime_ -) -> StubInference | None: +) -> StubInference: """ - Convert `stub` as string to a `StubInference` enum based on what stubs are intended to be - inferred and what stab dates are already provided. In a stub is provided as a date it - will never be inferred. + Perform two tasks: + - Convert `stub` as string to a `StubInference` enum. + - Convert a StubInference to NeitherSide if a specific stud date has been provided that + cannot be inferred. Parameters ---------- @@ -59,35 +60,62 @@ def _get_stub_inference( Returns ------- - StubInference or None + StubInference """ - if isinstance(stub, StubInference) or stub is None: - return stub + if isinstance(stub, StubInference): + if stub is StubInference.NeitherSide: + stub_: str = "NEITHER_SIDE" + elif stub is StubInference.ShortFront: + stub_ = "SHORT_FRONT" + elif stub is StubInference.LongFront: + stub_ = "LONG_FRONT" + elif stub is StubInference.ShortBack: + stub_ = "SHORT_BACK" + else: # StubInference.LongBack: + stub_ = "LONG_BACK" + elif stub is None: + stub_ = "NONE" + else: + stub_ = stub.upper() + del stub _map: dict[str, StubInference] = { "SHORTFRONT": StubInference.ShortFront, "LONGFRONT": StubInference.LongFront, "SHORTBACK": StubInference.ShortBack, "LONGBACK": StubInference.LongBack, + "NONE": StubInference.NeitherSide, + "NEITHERSIDE": StubInference.NeitherSide, + "SHORT_FRONT": StubInference.ShortFront, + "LONG_FRONT": StubInference.LongFront, + "SHORT_BACK": StubInference.ShortBack, + "LONG_BACK": StubInference.LongBack, + "NEITHER_SIDE": StubInference.NeitherSide, } - stub = stub.upper() - _ = {v: v in stub for v in _map} + + possibles: dict[str, StubInference] = {v: _map[v] for v in _map if v in stub_} if not isinstance(front_stub, NoInput): # cannot infer front stubs, since it is explicitly provided - _["SHORTFRONT"] = False - _["LONGFRONT"] = False + possibles.pop("SHORTFRONT", None) + possibles.pop("SHORT_FRONT", None) + possibles.pop("LONGFRONT", None) + possibles.pop("LONG_FRONT", None) if not isinstance(back_stub, NoInput): # cannot infer back stubs, since it is explicitly provided - _["SHORTBACK"] = False - _["LONGBACK"] = False - ret: StubInference | None = None - if sum(list(_.values())) > 1: - raise ValueError("Must supply at least one stub date for dual sided inference.") - for k, v in _.items(): - if v: - ret = _map[k] - break - return ret + possibles.pop("SHORTBACK", None) + possibles.pop("SHORT_BACK", None) + possibles.pop("LONGBACK", None) + possibles.pop("LONG_BACK", None) + + if len(possibles) == 0: + return StubInference.NeitherSide # the stub inference is negated by a provided value + elif len(possibles) > 1: + raise ValueError( + "Must supply at least one stub date for dual sided inference.\n" + f"You have likely supplied to many sides to be inferred for `stub`. Got '{stub_}'." + ) + else: + return list(possibles.values())[0] def _get_adjuster_from_modifier(modifier: Adjuster | str_, mod_days: bool) -> Adjuster: @@ -125,65 +153,7 @@ class Schedule: """ Generate a schedule of dates according to a regular pattern and calendar inference. - Parameters - ---------- - effective : datetime, str - The unadjusted effective date. If given as adjusted, unadjusted alternatives may be - inferred. If given as string tenor will be calculated from ``eval_date`` and ``eval_mode``. - termination : datetime, str - The unadjusted termination date. If given as adjusted, unadjusted alternatives may be - inferred. If given as string tenor will be calculated from ``effective``. - frequency : Frequency, str in {"M", "Q", "S", "A", "Z", "_D", "_B", "_W", "_M", "_Y"} - The frequency of the schedule. - If given as string will derive a :class:`~rateslib.scheduling.Frequency` aligning with: - monthly ("M"), quarterly ("Q"), semi-annually ("S"), annually("A") or zero-coupon ("Z"), or - a set number of calendar or business days ("_D", "_B"), weeks ("_W"), months ("_M") or - years ("_Y"). - Where required, the :class:`~rateslib.scheduling.RollDay` is derived as per ``roll`` - and business day calendar as per ``calendar``. - stub : StubInference, str in {"ShortFront", "LongFront", "ShortBack", "LongBack"}, optional - The stub type used if stub inference is required. If given as string will derive a - :class:`~rateslib.scheduling.StubInference`. - front_stub : datetime, optional - The unadjusted date for the start stub period. If given as adjusted, unadjusted - alternatives may be inferred. - back_stub : datetime, optional - The unadjusted date for the back stub period. If given as adjusted, unadjusted - alternatives may be inferred. - See notes for combining ``stub``, ``front_stub`` and ``back_stub`` - and any automatic stub inference. - roll : RollDay, int in [1, 31], str in {"eom", "imm", "som"}, optional - The roll day of the schedule. If not given or not available in ``frequency`` will be - inferred for monthly frequency variants. - eom : bool, optional - Use an end of month preference rather than regular rolls for ``roll`` inference. Set by - default. Not required if ``roll`` is defined. - modifier : Adjuster, str in {"NONE", "F", "MF", "P", "MP"}, optional - The :class:`~rateslib.scheduling.Adjuster` used for adjusting unadjusted schedule dates - into adjusted dates. If given as string must define simple date rolling rules. - calendar : calendar, str, optional - The business day calendar object to use. If string will call - :meth:`~rateslib.scheduling.get_calendar`. - payment_lag: Adjuster, int, optional - The :class:`~rateslib.scheduling.Adjuster` to use to map adjusted schedule dates into - a payment date. If given as integer will define the number of business days to - lag payments by. - payment_lag_exchange: Adjuster, int, optional - The :class:`~rateslib.scheduling.Adjuster` to use to map adjusted schedule dates into - additional payment date. If given as integer will define the number of business days to - lag payments by. - extra_lag: Adjuster, int, optional - The :class:`~rateslib.scheduling.Adjuster` to use to map adjusted schedule dates into - additional dates, which may be used, for example by fixings schedules. If given as integer - will define the number of business days to lag dates by. - eval_date: datetime, optional - Only required if ``effective`` is given as a string tenor, to provide a point of reference. - eval_mode: str in {"swaps_align", "swaptions_align"} - The method for determining the ``effective`` and ``termination`` dates if both are provided - as string tenors. See notes. - - Examples - -------- + .. rubric:: Examples .. ipython:: python :suppress: @@ -228,82 +198,72 @@ class Schedule: ) print(s) - Notes - ----- - **Inference** + .. role:: red - It is not necessary to rely on inference if inputs are defined directly. However three types - of inference will be performed otherwise: + .. role:: green - - **Unadjusted date inference** if any dates including stubs are given as adjusted. - - **Frequency inference** if the ``frequency`` is missing properties, such as ``roll``. - - **Stub date inference** if a regular schedule cannot be defined without stubs one can be - unambiguously implied. - - *Rateslib* always tries to infer *regular* schedules ahead of *irregular* schedules. Failing - that, it always tries to infer dates and rolls as close as possible to those given by a user. - - **Dates given as string tenor - The 1Y1Y problem** - - When generating schedules implied from tenor ``effective`` and ``termination`` dates there - exist different theoretical ways of deriving these dates. *Rateslib* offers two practical - methods for doing this, configurable by setting the ``eval_mode`` argument to either - *"swaps_align"* or *"swaptions_align"*. - - .. tabs:: - - .. tab:: 'swaps_align' - - This method aligns dates with those implied by a sub-component of a par tenor swap. - E.g. a 1Y1Y schedule is expected to align with the second half of a 2Y par swap. - To achieve this, an *unadjusted* ``effective`` date is determined from ``eval_date`` and - an *unadjusted* ``termination`` date is derived from that ``effective`` date. - - For example, today is Tue 15th Aug '23 and spot is Thu 17th Aug '23: - - - A 1Y has effective, termination and roll of: Tue 17th Aug '23, Mon 19th Aug '24, 17. - - A 2Y has effective, termination and roll of: Tue 17th Aug '23, Mon 18th Aug '25, 17. - - A 1Y1Y has effective, termination and roll of: Mon 19th Aug '24, Mon 18th Aug '25, 17. - - .. ipython:: python - - s = Schedule( - effective="1Y", - termination="1Y", - frequency="S", - calendar="tgt", - eval_date=dt(2023, 8, 17), - eval_mode="swaps_align", - ) - print(s) - - .. tab:: 'swaptions_align' - - A 1Y1Y swaption at expiry is evaluated against the 1Y swap as measured per that expiry - date. To define this exactly requires more parameters, but this method replicates - the true swaption expiry instrument about 95% of the time. To achieve this, an - *adjusted* ``effective`` date is determined from the ``eval_date`` and ``modifier``, and - an *unadjusted* ``termination`` date is derived from the ``effective`` date. - - For example, today is Tue 15th Aug '23: - - - A 1Y expiring swaption has an expiry on Thu 15th Aug '24. - - At expiry a spot starting 1Y swap has effective, termination, and roll of: - Mon 19th Aug '24, Tue 19th Aug '25, 19. - - .. ipython:: python + Parameters + ---------- + effective : datetime, str, :red:`required` + The unadjusted effective date. If given as adjusted, unadjusted alternatives may be + inferred. If given as string tenor will be calculated from ``eval_date`` and ``eval_mode``. + termination : datetime, str, :red:`required` + The unadjusted termination date. If given as adjusted, unadjusted alternatives may be + inferred. If given as string tenor will be calculated from ``effective``. + frequency : Frequency, str in {"M", "Q", "S", "A", "Z", "_D", "_B", "_W", "_M", "_Y"}, :red:`required` + The frequency of the schedule. + If given as string will derive a :class:`~rateslib.scheduling.Frequency` aligning with: + monthly ("M"), quarterly ("Q"), semi-annually ("S"), annually("A") or zero-coupon ("Z"), or + a set number of calendar or business days ("_D", "_B"), weeks ("_W"), months ("_M") or + years ("_Y"). + Where required, the :class:`~rateslib.scheduling.RollDay` is derived as per ``roll`` + and business day calendar as per ``calendar``. + stub : StubInference, str in {"ShortFront", "LongFront", "ShortBack", "LongBack"}, :green:`optional (set by defaults)` + The stub type used if stub inference is required. If given as string will derive a + :class:`~rateslib.scheduling.StubInference`. + front_stub : datetime, :green:`optional` + The unadjusted date for the start stub period. If given as adjusted, unadjusted + alternatives may be inferred. + back_stub : datetime, :green:`optional` + The unadjusted date for the back stub period. If given as adjusted, unadjusted + alternatives may be inferred. + See notes for combining ``stub``, ``front_stub`` and ``back_stub`` + and any automatic stub inference. + roll : RollDay, int in [1, 31], str in {"eom", "imm", "som"}, :green:`optional` + The roll day of the schedule. If not given or not available in ``frequency`` will be + inferred for monthly frequency variants. + eom : bool, :green:`optional (set by defaults)` + Use an end of month preference rather than regular rolls for ``roll`` inference. Set by + default. Not required if ``roll`` is defined. + modifier : Adjuster, str in {"NONE", "F", "MF", "P", "MP"}, :green:`optional (set by defaults)` + The :class:`~rateslib.scheduling.Adjuster` used for adjusting unadjusted schedule dates + into adjusted dates. If given as string must define simple date rolling rules. + calendar : calendar, str, :green:`optional (set as 'all')` + The business day calendar object to use. If string will call + :meth:`~rateslib.scheduling.get_calendar`. + payment_lag: Adjuster, int, :green:`optional (set by defaults)` + The :class:`~rateslib.scheduling.Adjuster` to use to map adjusted schedule dates into + a payment date. If given as integer will define the number of business days to + lag payments by. + payment_lag_exchange: Adjuster, int, :green:`optional (set by defaults)` + The :class:`~rateslib.scheduling.Adjuster` to use to map adjusted schedule dates into + additional payment date. If given as integer will define the number of business days to + lag payments by. + extra_lag: Adjuster, int, :green:`optional` + The :class:`~rateslib.scheduling.Adjuster` to use to map adjusted schedule dates into + additional dates, which may be used, for example by fixings schedules. If given as integer + will define the number of business days to lag dates by. + eval_date: datetime, :green:`optional` + Only required if ``effective`` is given as a string tenor, to provide a point of reference. + eval_mode: str in {"swaps_align", "swaptions_align"}, :green:`optional (set by defaults)` + The method for determining the ``effective`` and ``termination`` dates if both are provided + as string tenors. See notes. - s = Schedule( - effective="1Y", - termination="1Y", - frequency="S", - calendar="tgt", - eval_date=dt(2023, 8, 17), - eval_mode="swaptions_align", - ) - print(s) + Notes + ----- + Detailed information is provided within :ref:`the scheduling user guide `. - """ + """ # noqa: E501 _obj: Schedule_rs @@ -357,21 +317,35 @@ def __init__( roll, eom_, ) - - self._obj = Schedule_rs( - effective=effective_, - termination=termination_, - frequency=frequency_, - calendar=calendar_, - accrual_adjuster=accrual_adjuster, - payment_adjuster=payment_adjuster, - payment_adjuster2=payment_adjuster2, - payment_adjuster3=payment_adjuster3, - front_stub=_drb(None, front_stub), - back_stub=_drb(None, back_stub), - eom=eom_, - stub_inference=_get_stub_inference(stub_, front_stub, back_stub), - ) + stub_inference_ = _get_stub_inference(stub_, front_stub, back_stub) + + try: + self._obj = Schedule_rs( + effective=effective_, + termination=termination_, + frequency=frequency_, + calendar=calendar_, + accrual_adjuster=accrual_adjuster, + payment_adjuster=payment_adjuster, + payment_adjuster2=payment_adjuster2, + payment_adjuster3=payment_adjuster3, + front_stub=_drb(None, front_stub), + back_stub=_drb(None, back_stub), + eom=eom_, + stub_inference=stub_inference_, + ) + except ValueError: + raise ValueError( + "A Schedule could not be generated from the parameter combinations:\n" + f"effective: {effective}\n" + f"front stub: {front_stub}\n" + f"back stub: {back_stub}\n" + f"termination: {termination}\n" + f"frequency: {frequency_}\n" + f"stub inference: {stub_inference_}\n" + f"accrual adjuster: {accrual_adjuster}\n" + f"calendar: {calendar_}\n" + ) @classmethod def __init_from_obj__(cls, obj: Schedule_rs) -> Schedule: @@ -387,7 +361,7 @@ def __getnewargs__( datetime, datetime, Frequency, - NoInput, + StubInference, datetime_, datetime_, NoInput, @@ -404,7 +378,7 @@ def __getnewargs__( self.ueffective, self.utermination, self.frequency_obj, - NoInput(0), + StubInference.NeitherSide, NoInput(0) if self.ufront_stub is None else self.ufront_stub, NoInput(0) if self.uback_stub is None else self.uback_stub, NoInput(0), diff --git a/python/rateslib/serialization/utils.py b/python/rateslib/serialization/utils.py index f091849b4..bb41b0afb 100644 --- a/python/rateslib/serialization/utils.py +++ b/python/rateslib/serialization/utils.py @@ -20,7 +20,7 @@ from rateslib.enums.generics import NoInput if TYPE_CHECKING: - from rateslib.typing import Any, DualTypes, Number # pragma: no cover + from rateslib.local_types import Any, DualTypes, Number # pragma: no cover # Dualtypes handles case of rust wrapped Dual/Dual2 datatype intermixed with float. diff --git a/python/rateslib/solver.py b/python/rateslib/solver.py index dbf5372e4..6705493be 100644 --- a/python/rateslib/solver.py +++ b/python/rateslib/solver.py @@ -57,7 +57,7 @@ from numpy import object_ as Nobject # noqa: N812 from numpy.typing import NDArray - from rateslib.typing import ( + from rateslib.local_types import ( FX_, Any, Callable, @@ -199,7 +199,11 @@ def _grad_s_vT_final_iteration_dual(self, algorithm: str | None = None) -> NDArr def _grad_s_vT_final_iteration_analytical(self) -> NDArray[Nf64]: """Uses a pseudoinverse algorithm on floats""" - grad_s_vT: NDArray[Nf64] = np.linalg.pinv(self.J) # type: ignore[assignment] + if self.n == 0: + # then there are no instruments: self is only a Solver container of `pre_solvers` + grad_s_vT: NDArray[Nf64] = np.array([[]], dtype=float) + else: + grad_s_vT = np.linalg.pinv(self.J) # type: ignore[assignment] return grad_s_vT def _grad_s_vT_fixed_point_iteration(self) -> NDArray[Nf64]: @@ -335,10 +339,12 @@ def J2_pre(self) -> NDArray[Nf64]: ] = pre_slvr.J2_pre i, j = i + pre_slvr.pre_n, j + pre_slvr.pre_m - rates = np.array([_[0].rate(**_[1]) for _ in self.instruments]) - # solver is passed in order to extract curves as string - _ = np.array([gradient(r, self.pre_variables, order=2) for r in rates]) - J2[:, :, -self.m :] = np.transpose(_, (1, 2, 0)) + if self.m > 0: + # then self is not only a container for `pre_solvers` + rates = np.array([_[0].rate(**_[1]) for _ in self.instruments]) + # solver is passed in order to extract curves as string + _ = np.array([gradient(r, self.pre_variables, order=2) for r in rates]) + J2[:, :, -self.m :] = np.transpose(_, (1, 2, 0)) self._J2_pre = J2 return self._J2_pre @@ -511,16 +517,21 @@ def grad_s_vT_pre(self) -> NDArray[Nf64]: m, n = pre_solver.pre_m, pre_solver.pre_n grad_s_vT[i : i + m, j : j + n] = pre_solver.grad_s_vT_pre - # create the right column dependencies - grad_v_r = np.array([gradient(r, pre_solver.pre_variables) for r in self.r]).T - block = np.matmul(grad_v_r, self.grad_s_vT) - block = -1 * np.matmul(pre_solver.grad_s_vT_pre, block) - grad_s_vT[i : i + m, -self.n :] = block + # create the right column dependencies, only if self contains some instruments + # and variable of its own and is not only a container of `pre_solvers` + if self.n > 0: + grad_v_r = np.array([gradient(r, pre_solver.pre_variables) for r in self.r]).T + block = np.matmul(grad_v_r, self.grad_s_vT) + block = -1 * np.matmul(pre_solver.grad_s_vT_pre, block) + grad_s_vT[i : i + m, -self.n :] = block i, j = i + m, j + n - # create bottom right block - grad_s_vT[-self.m :, -self.n :] = self.grad_s_vT + if self.n > 0: + # create bottom right block, only if self contains some instruments + # and variables of its own and is not only a container of `pre_solvers` + grad_s_vT[-self.m :, -self.n :] = self.grad_s_vT + self._grad_s_vT_pre = grad_s_vT return self._grad_s_vT_pre @@ -1450,8 +1461,11 @@ def r_pre(self) -> NDArray[Nobject]: # type: ignore[override] r_pre[i : i + m] = pre_solver.r_pre i = i + m - # create bottom right block - r_pre[-self.m :] = self.r + if self.m > 0: + # create bottom right block if solver contains its own instruments and self + # is not just a container of `pre_solvers` + r_pre[-self.m :] = self.r + self._r_pre = r_pre return self._r_pre @@ -1480,21 +1494,25 @@ def error(self) -> Series[float]: ------- Series """ - pre_s: Series[float] | None = None + pre_s: Series[float] = Series() for pre_solver in self.pre_solvers: - if pre_s is None: - pre_s = pre_solver.error + if not pre_s.empty: + pre_s = concat([ser for ser in [pre_solver.error, pre_s] if not ser.empty]) else: - pre_s = concat([pre_solver.error, pre_s]) + pre_s = pre_solver.error - _: Series[float] = Series( - self.x.astype(float) * 100 / self.rate_scalars, - index=MultiIndex.from_tuples([(self.id, inst) for inst in self.instrument_labels]), - ) - if pre_s is None: - s: Series[float] = _ + if self.m > 0: + _: Series[float] = Series( + self.x.astype(float) * 100 / self.rate_scalars, + index=MultiIndex.from_tuples([(self.id, inst) for inst in self.instrument_labels]), + ) + if not pre_s.empty: + s: Series[float] = concat([pre_s, _]) + else: + s = _ else: - s = concat([pre_s, _]) + s = pre_s + return s @property @@ -1885,7 +1903,7 @@ def gamma( .. ipython:: python :suppress: - from rateslib import Solver, Curve + from rateslib import Solver, Curve, SBS, IRS .. ipython:: python @@ -1922,7 +1940,7 @@ def gamma( }, id="s" ) - args = dict(termination="1Y", frequency="A", fixing_method="ibor", leg2_fixing_method="ibor") + args = dict(termination="1Y", frequency="A", fixing_method="ibor(0)", leg2_fixing_method="ibor(0)") instruments = [ SBS(dt(2022, 1, 1), curves=["r", "s", "s", "s"], **args), SBS(dt(2023, 1, 1), curves=["r", "s", "s", "s"], **args), @@ -1934,11 +1952,11 @@ def gamma( SBS(dt(2024, 1, 1), curves=["r", "s", "z", "s"], **args), SBS(dt(2025, 1, 1), curves=["r", "s", "z", "s"], **args), SBS(dt(2026, 1, 1), curves=["r", "s", "z", "s"], **args), - IRS(dt(2022, 1, 1), "1Y", "A", curves=["r", "s"], leg2_fixing_method="ibor"), - IRS(dt(2023, 1, 1), "1Y", "A", curves=["r", "s"], leg2_fixing_method="ibor"), - IRS(dt(2024, 1, 1), "1Y", "A", curves=["r", "s"], leg2_fixing_method="ibor"), - IRS(dt(2025, 1, 1), "1Y", "A", curves=["r", "s"], leg2_fixing_method="ibor"), - IRS(dt(2026, 1, 1), "1Y", "A", curves=["r", "s"], leg2_fixing_method="ibor"), + IRS(dt(2022, 1, 1), "1Y", "A", curves=["r", "s"], leg2_fixing_method="ibor(0)"), + IRS(dt(2023, 1, 1), "1Y", "A", curves=["r", "s"], leg2_fixing_method="ibor(0)"), + IRS(dt(2024, 1, 1), "1Y", "A", curves=["r", "s"], leg2_fixing_method="ibor(0)"), + IRS(dt(2025, 1, 1), "1Y", "A", curves=["r", "s"], leg2_fixing_method="ibor(0)"), + IRS(dt(2026, 1, 1), "1Y", "A", curves=["r", "s"], leg2_fixing_method="ibor(0)"), ] solver = Solver( curves=[curve_r, curve_s, curve_z], @@ -1951,7 +1969,7 @@ def gamma( "r1", "r2", "r3", "r4", "r5", ], ) - irs = IRS(dt(2022, 1, 1), "5Y", "A", notional=-8.3e8, curves=["z", "s"], leg2_fixing_method="ibor", fixed_rate=25.0) + irs = IRS(dt(2022, 1, 1), "5Y", "A", notional=-8.3e8, curves=["z", "s"], leg2_fixing_method="ibor(0)", fixed_rate=25.0) irs.delta(solver=solver) irs.gamma(solver=solver) """ # noqa: E501 @@ -2330,3 +2348,6 @@ def exo_delta( # Licence: Creative Commons - Attribution-NonCommercial-NoDerivatives 4.0 International # Commercial use of this code, and/or copying and redistribution is prohibited. # Contact rateslib at gmail.com if this code is observed outside its intended sphere. + + +__all__ = ["Gradients", "Solver"] diff --git a/python/rateslib/splines/evaluate.py b/python/rateslib/splines/evaluate.py index a0b1323d7..2d6ccbc84 100644 --- a/python/rateslib/splines/evaluate.py +++ b/python/rateslib/splines/evaluate.py @@ -18,7 +18,7 @@ from rateslib.rs import PPSplineDual, PPSplineDual2, PPSplineF64 if TYPE_CHECKING: - from rateslib.typing import DualTypes, Number + from rateslib.local_types import DualTypes, Number def evaluate( diff --git a/python/rateslib/utils/calendars.py b/python/rateslib/utils/calendars.py index 94e129fd8..9ac8ee7d1 100644 --- a/python/rateslib/utils/calendars.py +++ b/python/rateslib/utils/calendars.py @@ -14,7 +14,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from rateslib.typing import ( # pragma: no cover + from rateslib.local_types import ( # pragma: no cover CalTypes, datetime, ) diff --git a/python/rateslib/verify.py b/python/rateslib/verify.py new file mode 100644 index 000000000..5fca6d93e --- /dev/null +++ b/python/rateslib/verify.py @@ -0,0 +1,288 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + +from __future__ import annotations + +import hashlib +import json +import logging +import os +import sys +import warnings +from datetime import datetime, timedelta +from enum import Enum +from json import JSONDecodeError +from pathlib import Path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from rateslib.local_types import ( # pragma: no cover + Any, + ) + +VERSION = "2.6.0" + + +class LicenceNotice(UserWarning): + _no_licence_warning = ( + "\nRateslib is source-available (not open-source) software distributed under a " + "dual-licence model." + "\nNo commercial licence is registered for this installation. Use is therefore permitted " + "for non-commercial purposes only (at-home or university based academic use)." + "\nAny use in commercial, professional, or for-profit environments, including evaluation " + "or trial use, requires a valid commercial licence or an approved evaluation licence." + "\nCertain features may require a registered commercial or evaluation licence in current " + "or future versions." + "\nFor licensing information or to register a licence, please visit: " + "https://rateslib.com/licence" + ) + + _invalid_warning = ( + "\nRateslib is source-available (not open-source) software distributed under a " + "dual-licence model." + "\nAn invalid licence file is detected for this installation. Use is therefore permitted " + "for non-commercial purposes only (at-home or university based academic use)." + "\nAny use in commercial, professional, or for-profit environments, including evaluation " + "or trial use, requires a valid commercial licence or an approved evaluation licence." + "\nCertain features may require a registered commercial or evaluation licence in current " + "or future versions." + "\nFor licensing information or to register a licence, please visit: " + "https://rateslib.com/licence" + ) + + _expired_warning = ( + "\nYour existing licence for rateslib {0} expired on {1}.\n" + "If you wish to extend your licence, please visit https://rateslib.com/licence for further " + "details.\n" + "Otherwise, please uninstall rateslib.\n" + "Expired licence details:\n{2}\n" + ) + + +class _LicenceStatus(Enum): + VALID = 0 + EXPIRED_GRACE = 1 + EXPIRED = 2 + INVALID = 3 + NO_LICENCE = 4 + + +class Licence: + """ + A licence coordinator to control warnings and functionality. + """ + + def __init__(self) -> None: + # search for licences in relevant paths + value = os.getenv("RATESLIB_LICENCE") or _get_licence() + + if value is None: + # then no licence data was found either in environment vars or in the standard path. + self._status = _LicenceStatus.NO_LICENCE + else: + verified_expiry = _verify_licence(value) + + if verified_expiry is None: # i.e. invalid signature key + self._status = _LicenceStatus.INVALID + else: + # measure the expiry relative to today + self._expiry = datetime.strptime(verified_expiry, "%Y-%m-%d") + if self.expiry > datetime.now(): + self._status = _LicenceStatus.VALID + elif self.expiry > datetime.now() - timedelta(days=14): + self._status = _LicenceStatus.EXPIRED_GRACE + else: + self._status = _LicenceStatus.EXPIRED + + if self.status == _LicenceStatus.NO_LICENCE: + self._output(LicenceNotice._no_licence_warning, VERSION) + elif self.status == _LicenceStatus.INVALID: + self._output(LicenceNotice._invalid_warning, VERSION) + elif self.status == _LicenceStatus.EXPIRED: + self._output( + LicenceNotice._expired_warning, + VERSION, + self.expiry.strftime("%Y-%m-%d"), + self.print_licence(), + ) + + def _output(self, text: str, *args: Any) -> None: + warnings.warn(message=text.format(*args), category=LicenceNotice, stacklevel=4) + logger = logging.getLogger(__name__) + logger.info(text.format(*args)) + + @property + def status(self) -> _LicenceStatus: + return self._status + + @property + def expiry(self) -> datetime: + return self._expiry + + @classmethod + def add_licence(cls, licence_text: str) -> None: + """ + Store the provided licence as a file on the local disk. + + Will create or overwrite any existing licence file as necessary. Will raise + PermissionError if writing to disk fails due to restrictions. + + Parameters + ---------- + licence_text: str + The full JSON format str of the provided licence. + + Returns + ------- + None + """ + licence_file = _get_licence_path() + try: + if licence_file.exists(): + current = licence_file.read_text() + if current != licence_text: + print(f"Warning: Existing licence differs. Overwriting {licence_file}") + + # only add if a valid licence string: + try: + valid = _verify_licence(licence_text) + except JSONDecodeError: + raise ValueError( + "The provided licence text does not appear to be valid JSON format or cannot " + f"be decoded as such.\n{licence_text}" + ) + + if not valid: + raise ValueError( + f"The licence key is invalid and has not been saved to disk.\n{licence_text}" + ) + + licence_file.write_text(licence_text) + print(f"License saved at {licence_file}") + except PermissionError: + raise PermissionError( + f"Cannot save licence file to {licence_file}.\n " + f"Check your admin or corporate file permissions." + ) + + @classmethod + def remove_licence(cls) -> bool: + """ + Remove the stored licence file. + + Raises PermissionError if the file cannot be deleted from disk due to restrictions. + + Returns + ------- + bool + *True* on successful removal and *False* if no licence file exists. + """ + licence_file = _get_licence_path() + try: + if licence_file.exists(): + licence_file.unlink() + print(f"License removed from {licence_file}") + return True + else: + print("No licence file found to remove.") + return False + except PermissionError: + raise PermissionError( + f"Cannot remove licence file at {licence_file}. Check your permissions." + ) + + @classmethod + def print_licence(cls) -> str: + """ + Output the licence data to string. + + Returns + ------- + str + The JSON format of the licence. + """ + value = os.getenv("RATESLIB_LICENCE") or _get_licence() + if value is None: + raise ValueError("No rateslib licence data was found on this machine") + else: + return value + + +APP_NAME = "rateslib" +LICENSE_FILENAME = "rateslib_licence.txt" + + +PUBLIC_KEY: tuple[int, int] = ( + 65537, + 86222696103896966718103037502072442336246185093318724988310224539490986842962518392592510336894335238460512594559929385462044884137775548353223089347652775415882082908041940084967476300969806363550378972881577687292674787317782507726743027399965228306794174501671206473081788525064813988527838836758351217651, +) + + +def _rsa_encrypt(message_int: int, public_key: tuple[int, int]) -> int: + e, n = public_key + if not 0 <= message_int < n: + raise ValueError("Message too large for key") + return pow(message_int, e, n) + + +def _get_licence_path() -> Path: + """ + Returns the path where the licence file should be stored. + Cross-platform user-specific location. + """ + if os.name == "nt": # Windows + base = Path(os.getenv("APPDATA", Path.home() / "AppData" / "Roaming")) + elif sys.platform == "darwin": # macOS + base = Path.home() / "Library" / "Application Support" + else: # Linux / Unix + base = Path.home() / ".local" / "share" + + data_dir = base / APP_NAME + data_dir.mkdir(parents=True, exist_ok=True) # Ensure directory exists + return data_dir / LICENSE_FILENAME + + +def _get_licence() -> str | None: + """ + Retrieve the stored licence text, or None if not found. + """ + licence_file = _get_licence_path() + if licence_file.exists(): + return licence_file.read_text() + return None + + +def _verify_licence(licence_plaintext: str) -> str | None: + loaded_dict = json.loads(licence_plaintext) + licence_dict = dict(sorted(loaded_dict.items())) + + hex_s = licence_dict.pop("xkey", None) + if hex_s is None: + return None + + s = int(hex_s, 16) + + m = json.dumps(licence_dict, sort_keys=True) + hex_h = hashlib.sha256(m.encode()).hexdigest() + h = int(hex_h, 16) # h = int.from_bytes(hashlib.sha256(m.encode()).digest()) + + h_ = _rsa_encrypt(s, PUBLIC_KEY) + + if h != h_: + return None + else: + try: + return loaded_dict["expiry"] # type: ignore[no-any-return] + except KeyError: + return None + + +__all__ = ["LicenceNotice", "Licence"] diff --git a/python/tests/instruments/test_instruments_bonds_legacy.py b/python/tests/instruments/test_instruments_bonds_legacy.py index 49658f94a..99a578246 100644 --- a/python/tests/instruments/test_instruments_bonds_legacy.py +++ b/python/tests/instruments/test_instruments_bonds_legacy.py @@ -21,6 +21,7 @@ from rateslib.curves import Curve, LineCurve from rateslib.default import NoInput from rateslib.dual import Dual, Dual2, Variable, gradient +from rateslib.enums import FloatFixingMethod from rateslib.fx import FXForwards, FXRates from rateslib.instruments import ( IRS, @@ -630,6 +631,59 @@ def test_cadgb_price3(self) -> None: assert abs(result - 100.00) < 1e-5 assert abs(stub_cash + 7828.77) < 1e-2 + def test_cadgb_ytm_dirty_calc(self) -> None: + # Cad GB has different Accrual function for a YTM and physical settlement. + # If a price is supplied dirty it is expected to be a physical settlement dirty price + bond = FixedRateBond( + effective=dt(2018, 7, 27), + termination=dt(2029, 6, 1), + fixed_rate=2.25, + spec="ca_gb", + ) + + physical_accrued = bond._accrued( + dt(2019, 6, 10), bond.kwargs.meta["calc_mode"]._settle_accrual + ) + ytm_accrued = bond._accrued(dt(2019, 6, 10), bond.kwargs.meta["calc_mode"]._ytm_accrual) + assert abs(physical_accrued - ytm_accrued) > 1e-4 + + clean_price = 101.00 + clean_ytm = bond.ytm(clean_price, dt(2019, 6, 10)) + dirty_ytm = bond.ytm(clean_price + physical_accrued, dt(2019, 6, 10), dirty=True) + assert abs(clean_ytm - dirty_ytm) < 1e-8 + + def test_cadgb_ytm_indexed_dirty_calc(self) -> None: + # Cad GB has different Accrual function for a YTM and physical settlement. + # If a price is supplied dirty it is expected to be a physical settlement dirty price + bond = IndexFixedRateBond( + effective=dt(2018, 7, 27), + termination=dt(2029, 6, 1), + fixed_rate=2.25, + spec="ca_gbi", + index_base=90.0, + ) + curve = Curve({dt(2019, 1, 1): 1.0, dt(2030, 1, 1): 1.0}, index_base=99.0).shift(100.0) + + physical_indexed_accrued = bond.accrued(dt(2019, 6, 10), indexed=True, index_curve=curve) + ytm_indexed_accrued = bond._accrued( + dt(2019, 6, 10), bond.kwargs.meta["calc_mode"]._ytm_accrual + ) * bond.index_ratio(settlement=dt(2019, 6, 18), index_curve=curve) + assert abs(physical_indexed_accrued - ytm_indexed_accrued) > 1e-4 + + clean_price = 111.00 + clean_ytm = bond.ytm( + clean_price, dt(2019, 6, 10), indexed_price=True, indexed_ytm=False, index_curve=curve + ) + dirty_ytm = bond.ytm( + clean_price + physical_indexed_accrued, + dt(2019, 6, 10), + dirty=True, + indexed_price=True, + indexed_ytm=False, + index_curve=curve, + ) + assert abs(clean_ytm - dirty_ytm) < 1e-8 + ## German gov bonds comparison with official bundesbank publications. @pytest.mark.parametrize( @@ -698,6 +752,30 @@ def test_long_stub(self): bond = FixedRateBond(dt(2025, 7, 4), dt(2035, 8, 15), spec="de_gb", fixed_rate=2.60) assert bond.leg1.schedule.aschedule[0:2] == [dt(2025, 7, 4), dt(2026, 8, 15)] + def test_de_long_front_split_accrued_no_leap(self): + # this bond was not issued around a leap year so there is no difference between + # linear_days_long_front_split and linear_days + bond = FixedRateBond(dt(2025, 3, 12), dt(2056, 8, 15), spec="de_gb", fixed_rate=2.90) + result1 = bond.accrued(settlement=dt(2026, 1, 16)) + result2 = bond.accrued(settlement=dt(2026, 7, 14)) + expected1 = (dt(2026, 1, 16) - dt(2025, 3, 12)).days / 365 * 2.9 + expected2 = (dt(2026, 7, 14) - dt(2025, 3, 12)).days / 365 * 2.9 + assert abs(result1 - expected1) < 1e-6 + assert abs(result2 - expected2) < 1e-6 + + def test_de_long_front_split_accrued_leap(self): + # this bond was issued in 2024 so there is a difference between linear_days and + # linear_days_long_front_split: ISIN DE000BU2D004 + bond = FixedRateBond(dt(2024, 2, 6), dt(2054, 8, 15), spec="de_gb", fixed_rate=2.50) + result1 = bond.accrued(settlement=dt(2024, 7, 15)) + result2 = bond.accrued(settlement=dt(2025, 7, 15)) + expected1 = (dt(2024, 7, 15) - dt(2024, 2, 6)).days / 366 * 2.5 + expected2 = (dt(2024, 8, 15) - dt(2024, 2, 6)).days / 366 * 2.5 + ( + dt(2025, 7, 15) - dt(2024, 8, 15) + ).days / 365 * 2.5 + assert abs(result1 - expected1) < 1e-8 + assert abs(result2 - expected2) < 1e-8 + ## French OAT @pytest.mark.parametrize( @@ -2877,6 +2955,22 @@ def test_sgbb(self) -> None: ytm = bill.ytm(price=96.520547, settlement=dt(2023, 3, 15)) assert abs(ytm - 3.5546338) < 1e-5 + # norwegian + @pytest.mark.parametrize( + ("e", "t", "price", "y"), + [ + (dt(2025, 3, 19), dt(2026, 3, 18), 99.38775, 4.01095), + (dt(2025, 6, 18), dt(2026, 6, 17), 98.4218, 4.0012), + (dt(2025, 9, 17), dt(2026, 9, 16), 97.4707, 3.99), + (dt(2025, 12, 17), dt(2026, 12, 16), 96.5409, 3.9705), + ], + ) + def test_nogbb(self, e, t, price, y) -> None: + # prices obtained from Norges Bank on Friday 16th Jan 2026, settle 20th Jan + bill = Bill(effective=e, termination=t, spec="no_gbb") + ytm = bill.ytm(price=price, settlement=dt(2026, 1, 20)) + assert abs(ytm - y) < 5e-5 + def test_text_example(self) -> None: bill = Bill(effective=dt(2023, 5, 17), termination=dt(2023, 9, 26), spec="us_gbb") result = bill.ytm(99.75, settlement=dt(2023, 9, 7)) @@ -3103,9 +3197,8 @@ def test_float_rate_bond_accrued(self) -> None: convention="Act365f", ex_div=3, float_spread=100, - fixing_method="rfr_observation_shift", + fixing_method=FloatFixingMethod.RFRObservationShift(5), rate_fixings=name, - method_param=5, spread_compound_method="none_simple", ) result = bond.accrued(dt(2010, 3, 3)) @@ -3132,9 +3225,8 @@ def test_float_rate_bond_rate_metric(self, metric, spd, exp) -> None: convention="Act365f", ex_div=3, float_spread=spd, - fixing_method="rfr_observation_shift", + fixing_method="rfr_observation_shift(5)", rate_fixings=name, - method_param=5, spread_compound_method="none_simple", settle=2, ) @@ -3162,9 +3254,8 @@ def test_initialised_rate_metric(self, metric, spd, exp) -> None: convention="Act365f", ex_div=3, float_spread=spd, - fixing_method="rfr_observation_shift", + fixing_method="rfr_observation_shift(5)", rate_fixings=name, - method_param=5, spread_compound_method="none_simple", settle=2, metric=metric, @@ -3193,9 +3284,8 @@ def test_float_rate_bond_accrued_ibor(self, settlement, expected) -> None: convention="Act365f", ex_div=3, float_spread=100, - fixing_method="ibor", + fixing_method=FloatFixingMethod.IBOR(2), rate_fixings=name, - method_param=2, spread_compound_method="none_simple", ) result = bond.accrued(settlement) @@ -3211,9 +3301,8 @@ def test_float_rate_bond_raise_frequency(self) -> None: convention="Act365f", ex_div=3, float_spread=100, - fixing_method="rfr_observation_shift", + fixing_method="rfr_observation_shift(5)", rate_fixings=NoInput(0), - method_param=5, spread_compound_method="none_simple", ) @@ -3227,9 +3316,8 @@ def test_negative_accrued_needs_forecasting(self) -> None: convention="Act365f", ex_div=6, float_spread=0, - fixing_method="rfr_observation_shift", + fixing_method="rfr_observation_shift(5)", rate_fixings=name, - method_param=5, spread_compound_method="none_simple", calendar=NoInput(0), ) @@ -3259,9 +3347,8 @@ def test_negative_accrued_raises(self, rate_fixings) -> None: convention="Act365f", ex_div=5, float_spread=0, - fixing_method="rfr_observation_shift", + fixing_method="rfr_observation_shift(5)", rate_fixings=rate_fixings, - method_param=5, spread_compound_method="none_simple", calendar=NoInput(0), ) @@ -3281,8 +3368,7 @@ def test_bad_accrued_parameter_combo_raises(self, rate_fixings) -> None: termination=dt(2017, 3, 16), frequency="Q", ex_div=5, - fixing_method="rfr_observation_shift", - method_param=3, + fixing_method="rfr_observation_shift(3)", ) def test_accrued_no_fixings_in_period(self) -> None: @@ -3293,9 +3379,8 @@ def test_accrued_no_fixings_in_period(self) -> None: convention="Act365f", ex_div=0, float_spread=0, - fixing_method="rfr_observation_shift", + fixing_method="rfr_observation_shift(0)", rate_fixings=NoInput(0), - method_param=0, spread_compound_method="none_simple", calendar=NoInput(0), ) @@ -3314,7 +3399,7 @@ def test_float_rate_bond_analytic_delta(self) -> None: float_spread=100, notional=-1000000, settle=0, - fixing_method="ibor", + fixing_method="ibor(2)", rate_fixings=2.0, ) curve = Curve({dt(2010, 11, 25): 1.0, dt(2015, 12, 7): 1.0}) @@ -3352,10 +3437,9 @@ def test_float_rate_bond_forward_prices(self, metric, spd, exp) -> None: convention="Act365f", ex_div=3, float_spread=spd, - fixing_method="rfr_observation_shift", + fixing_method="rfr_observation_shift(5)", calendar="bus", rate_fixings=name, - method_param=5, spread_compound_method="none_simple", settle=2, ) @@ -3382,8 +3466,7 @@ def test_float_rate_bond_forward_accrued(self) -> None: convention="Act365f", ex_div=3, float_spread=0, - fixing_method="rfr_observation_shift", - method_param=5, + fixing_method="rfr_observation_shift(5)", spread_compound_method="none_simple", settle=2, ) @@ -3401,8 +3484,7 @@ def test_rate_raises(self) -> None: convention="Act365f", ex_div=3, float_spread=0.0, - fixing_method="rfr_observation_shift", - method_param=5, + fixing_method="rfr_observation_shift(5)", spread_compound_method="none_simple", settle=2, ) @@ -3416,8 +3498,7 @@ def test_forecast_ibor(self, curve) -> None: effective=dt(2022, 2, 1), termination="3m", frequency="Q", - fixing_method="ibor", - method_param=0, + fixing_method="ibor(0)", ) result = frn.accrued(dt(2022, 2, 5), rate_curve=f_curve) expected = 0.044444444 @@ -3463,8 +3544,7 @@ def test_settle_method_param_combinations(self) -> None: termination="1Y", frequency="Q", settle=3, - method_param=2, - fixing_method="rfr_observation_shift", + fixing_method="rfr_observation_shift(2)", rate_fixings=name, convention="Act365F", ex_div=1, @@ -3511,8 +3591,7 @@ def test_settle_method_param_combinations(self) -> None: termination="1Y", frequency="Q", settle=3, - method_param=2, - fixing_method="rfr_observation_shift", + fixing_method="rfr_observation_shift(2)", convention="Act365F", ex_div=1, ) @@ -3528,8 +3607,7 @@ def test_settle_method_param_combinations(self) -> None: termination="1Y", frequency="Q", settle=3, - method_param=0, - fixing_method="rfr_observation_shift", + fixing_method="rfr_observation_shift(0)", convention="Act365F", ex_div=1, ) @@ -3550,7 +3628,7 @@ def test_ibor_fixings_table_historical_before_curve(self, curve): effective=dt(2001, 11, 7), termination=dt(2002, 8, 7), frequency="q", - fixing_method="ibor", + fixing_method="ibor(2)", rate_fixings=[4.0], curves=[curve], ) @@ -3563,7 +3641,7 @@ def test_ibor_fixings_table_with_fixing(self, curve): effective=dt(2021, 11, 7), termination=dt(2022, 8, 7), frequency="q", - fixing_method="ibor", + fixing_method="ibor(2)", rate_fixings=[4.0], curves=[curve], ) @@ -3581,7 +3659,7 @@ def test_ibor_ytm_rate(self, curve): effective=dt(2021, 11, 7), termination=dt(2022, 8, 7), frequency="q", - fixing_method="ibor", + fixing_method="ibor(2)", convention="actacticma", calendar="nyc", modifier="none", @@ -3614,7 +3692,7 @@ def test_ytm_rate_fixings_provided(self, curve): effective=dt(2021, 11, 7), termination=dt(2022, 8, 7), frequency="q", - fixing_method="ibor", + fixing_method="ibor(2)", convention="actacticma", calendar="nyc", modifier="none", @@ -3650,8 +3728,7 @@ def test_cashflows_known_fixings(self): convention="Act365F", ex_div=3, rate_fixings=name, - fixing_method="rfr_observation_shift_avg", - method_param=5, + fixing_method="rfr_observation_shift_avg(5)", ) result = frn.cashflows() fixings.pop(name + "_1B") diff --git a/python/tests/instruments/test_instruments_legacy.py b/python/tests/instruments/test_instruments_legacy.py index 69e0a674f..28f95b012 100644 --- a/python/tests/instruments/test_instruments_legacy.py +++ b/python/tests/instruments/test_instruments_legacy.py @@ -19,10 +19,10 @@ from rateslib import default_context, defaults, fixings from rateslib.curves import CompositeCurve, Curve, LineCurve, MultiCsaCurve from rateslib.curves._parsers import _map_curve_from_solver -from rateslib.data.fixings import FXIndex +from rateslib.data.fixings import FloatRateSeries, FXIndex, IBORStubFixing from rateslib.default import NoInput from rateslib.dual import Dual, Dual2, Variable, dual_exp, dual_log, gradient -from rateslib.enums.parameters import LegMtm +from rateslib.enums.parameters import FloatFixingMethod, LegMtm from rateslib.fx import FXForwards, FXRates from rateslib.fx_volatility import FXDeltaVolSmile, FXDeltaVolSurface, FXSabrSmile, FXSabrSurface from rateslib.instruments import ( @@ -54,6 +54,7 @@ Spread, STIRFuture, Value, + YoYIS, ) from rateslib.instruments.bonds.conventions import US_GB from rateslib.instruments.protocols.kwargs import ( @@ -68,6 +69,7 @@ # _get_curves_fx_and_base_maybe_from_solver, # ) from rateslib.legs import Amortization +from rateslib.periods import ZeroFloatPeriod from rateslib.scheduling import Adjuster, NamedCal, Schedule, add_tenor, get_imm from rateslib.solver import Solver @@ -1440,7 +1442,7 @@ def test_irs_interpolated_stubs(self, curve) -> None: frequency="Q", convention="act360", curves=[{"3m": curve3, "1m": curve1, "6M": curve6}, curve], - leg2_fixing_method="ibor", + leg2_fixing_method="ibor(2)", ) cashflows = irs.cashflows() assert (cashflows.loc[("leg2", 0), "Rate"] - 1.23729) < 1e-4 @@ -1465,7 +1467,7 @@ def test_irs_interpolated_stubs_solver(self) -> None: frequency="Q", convention="act360", curves=[{"3m": "3m", "6m": "6m"}, "3m"], - leg2_fixing_method="ibor", + leg2_fixing_method="ibor(2)", ) cashflows = irs.cashflows(solver=solver) assert (cashflows.loc[("leg2", 0), "Rate"] - 3.93693) < 1e-4 @@ -1571,6 +1573,104 @@ def test_irs_parse_curves(self, curve): r2 = irs.npv(curves={"rate_curve": curve, "disc_curve": curve}) assert r1 == r2 + def test_cny_zero_periods(self): + irs = IRS( + effective=dt(2026, 2, 4), + termination=dt(2031, 2, 4), + frequency="Q", + calendar="bjs", + modifier="F", + payment_lag=0, + leg2_fixing_method="ibor(1)", + convention="act365F", + leg2_fixing_frequency="7D", + leg2_fixing_series=FloatRateSeries( + lag=1, + convention="act365f", + calendar="bjs", + modifier="f", + tenors=["7D"], + zero_period_stub="shortback", + eom=False, + ), + leg2_zero_periods=True, + ) + + assert isinstance(irs.leg2.periods[0], ZeroFloatPeriod) + fixing_dates = [ + dt(2026, 2, 3), + dt(2026, 2, 10), + dt(2026, 2, 14), + dt(2026, 2, 24), + dt(2026, 3, 3), + dt(2026, 3, 10), + dt(2026, 3, 17), + dt(2026, 3, 24), + dt(2026, 3, 31), + dt(2026, 4, 7), + dt(2026, 4, 14), + dt(2026, 4, 21), + dt(2026, 4, 28), + ] + for i, float_period in enumerate(irs.leg2.periods[0].float_periods): + assert float_period.rate_params.rate_fixing.date == fixing_dates[i] + + # test even stub sub-periods are fixed veruss "7D" + assert isinstance( + irs.leg2.periods[1].float_periods[-1].rate_params.rate_fixing, IBORStubFixing + ) + assert isinstance( + irs.leg2.periods[1].float_periods[-1].rate_params.rate_fixing.fixing2, NoInput + ) + + def test_cny_golden_week_npv(self): + fixings.add( + "CNR7_1W", + Series( + index=[dt(2025, 9, 23), dt(2025, 9, 30), dt(2025, 10, 14)], + data=[1.53, 1.65, 1.48], + ), + ) + irs = IRS( + effective=dt(2025, 9, 24), + termination=dt(2025, 10, 22), + frequency="Q", + payment_lag=0, + leg2_fixing_method="ibor(1)", + leg2_fixing_frequency="7D", + leg2_zero_periods=True, + leg2_rate_fixings="CNR7", + leg2_fixing_series=FloatRateSeries( + lag=1, + calendar="bjs", + convention="act365f", + tenors=["7D"], + zero_period_stub="shortback", + modifier="F", + eom=False, + ), + fixed_rate=3.0, + calendar="bjs", + convention="act365F", + notional=-100e6, + ) + curve = Curve( + {dt(2025, 10, 21): 1.0, dt(2026, 10, 21): 0.99}, calendar="bjs", convention="act365f" + ) + _npv = irs.npv(curves=curve) + cf = irs.cashflows(curves=curve) + + assert abs(cf.loc[("leg1", 0), "Cashflow"] - 230136.99) < 1e-2 + assert abs(cf.loc[("leg2", 0), "Cashflow"] + 118426.165) < 1e-2 + + expected_rate = ( + ((1 + 1.53 * 15 / 36500) * (1 + 1.65 * 6 / 36500) * (1 + 1.48 * 7 / 36500) - 1) + * 36500 + / 28 + ) + assert abs(cf.loc[("leg2", 0), "Rate"] - expected_rate) < 1e-4 + fixings.pop("CNR7_1W") + class TestNDIRS: def test_irs_analytic_dv01(self, eureur, usdeur, usdusd) -> None: @@ -2063,6 +2163,131 @@ def test_fixing_in_the_past(self): assert abs(result - 1.9775254614497422) < 1e-8 +class TestYoYIS: + def test_index_fixings(self, curve) -> None: + name = str(hash(os.urandom(2))) + fixings.add( + name, + Series( + index=[ + dt(2025, 11, 1), + dt(2026, 11, 1), + dt(2027, 11, 1), + dt(2028, 11, 1), + dt(2029, 11, 1), + dt(2030, 11, 1), + ], + data=[324.09771, 332.32169, 340.43872, 348.73351, 357.21860, 366.05583], + ), + ) + yoyis = YoYIS( + effective=dt(2026, 2, 11), + termination="5y", + frequency="A", + fixed_rate=2.473874, + convention="ActActIsda", + leg2_index_lag=3, + leg2_index_method="monthly", + leg2_index_fixings=name, + notional=10e6, + calendar="nyc", + ) + expected_cashflows = [253750.018, 244177.225, 244392.329, 242644.969, 247389.973] + cashflows = yoyis.cashflows(curves=[NoInput(0), curve]) + for i in range(5): + value = cashflows.loc["leg2", "Cashflow"].iloc[i] + assert abs(value - expected_cashflows[i]) < 1e-2 + + expected_cashflows = [ + -247387.40, + -247311.47, + -248141.10, + -246709.63, + -247387.40, + ] + cashflows = yoyis.cashflows(curves=[NoInput(0), curve]) + for i in range(5): + value = cashflows.loc["leg1", "Cashflow"].iloc[i] + assert abs(value - expected_cashflows[i]) < 1e-2 + + npv = yoyis.npv(curves=[NoInput(0), curve]) + assert abs(npv + 3002.4397) < 1e-3 + + rate = yoyis.rate(curves=[NoInput(0), curve]) + analytic_delta = yoyis.analytic_delta(curves=[NoInput(0), curve]) + + assert abs((2.473874 - rate) * analytic_delta * 100.0 - 3002.4397) < 1e-3 + + def test_cashflows_no_index_base(self, curve) -> None: + i_curve = Curve( + {dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.5, dt(2034, 1, 1): 0.4}, + index_lag=3, + index_base=100.0, + interpolation="linear_index", + ) + yoyis = YoYIS( + effective=dt(2022, 2, 1), + termination="3y", + frequency="A", + fixed_rate=2.0, + convention="One", + leg2_index_lag=3, + ) + result = yoyis.cashflows(curves=[i_curve, curve]) + expected = [200.0, 204.193474, 208.386949] + for i in range(3): + assert abs(result.loc["leg2", "Index Base"].iloc[i] - expected[i]) < 1e-6 + + expected_cashflows = [204.193474 / 200.0, 208.386949 / 204.193474] + for i in range(2): + expected = 1e6 * (expected_cashflows[i] - 1) + assert abs(result.loc["leg2", "Cashflow"].iloc[i] - expected) < 1e-2 + + def test_yoyis_npv_mid_mkt_zero(self, curve) -> None: + i_curve = Curve( + {dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.5, dt(2034, 1, 1): 0.4}, + index_lag=3, + index_base=100.0, + interpolation="linear_index", + ) + name = str(hash(os.urandom(8))) + fixings.add(name=name, series=Series(index=[dt(2000, 1, 1)], data=[1.00])) + yoyis = YoYIS( + effective=dt(2022, 2, 1), + termination="3y", + frequency="A", + convention="One", + leg2_index_lag=3, + leg2_index_fixings=name, + leg2_index_method="monthly", + ) + + initial_mid = yoyis.rate(curves=[i_curve, curve]) + result = yoyis.npv(curves=[i_curve, curve]) + assert abs(result) < 1e-8 + + yoyis.fixed_rate = initial_mid + fixings.pop(name) + fixings.add(name=name, series=Series(index=[dt(2021, 11, 1)], data=[500.0])) + result2 = yoyis.npv(curves=[i_curve, curve]) + assert result2 < 500000 + assert yoyis.leg2._regular_periods[0].index_params.index_base.value == 500.0 + + new_mid = yoyis.rate(curves=[i_curve, curve]) + assert new_mid - initial_mid < -20.0 + + def test_fixings_table(self, curve): + i_curve = Curve( + {dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.5, dt(2034, 1, 1): 0.4}, + index_lag=3, + index_base=100.0, + interpolation="linear_index", + ) + yoyis = YoYIS(dt(2022, 1, 15), "6m", "Q", curves=[i_curve, curve]) + result = yoyis.local_analytic_rate_fixings() + assert result.empty + + class TestSBS: def test_sbs_npv(self, curve) -> None: sbs = SBS(dt(2022, 1, 1), "9M", "Q", float_spread=3.0) @@ -2120,10 +2345,8 @@ def test_fixings_table_3s1s(self, curve, curve2): inst = SBS( dt(2022, 1, 15), "6m", - fixing_method="ibor", - method_param=0, - leg2_fixing_method="ibor", - leg2_method_param=1, + fixing_method="ibor(0)", + leg2_fixing_method="ibor(1)", frequency="Q", leg2_frequency="m", curves=[curve, curve, curve2, curve], @@ -2370,8 +2593,7 @@ def test_fixings_table(self, curve): effective=dt(2022, 1, 15), termination="2y", frequency="Q", - leg2_fixing_method="ibor", - leg2_method_param=0, + leg2_fixing_method="ibor(2)", calendar="all", convention="30e360", leg2_convention="30e360", @@ -3897,8 +4119,7 @@ def okane_curve(self): IRS( spot, _, - leg2_fixing_method="ibor", - leg2_method_param=2, + leg2_fixing_method="ibor(2)", calendar="nyc", payment_lag=0, convention="30e360", @@ -4499,8 +4720,8 @@ def test_fixings_table(self, curve, curve2, fixed1, fixed2, mtm): fixed=fixed1, leg2_fixed=fixed2, leg2_mtm=mtm, - fixing_method="ibor", - leg2_fixing_method="ibor", + fixing_method="ibor(2)", + leg2_fixing_method=FloatFixingMethod.IBOR(2), ) result = xcs.local_analytic_rate_fixings(curves=[curve, curve, curve2, curve2], fx=fxf) assert isinstance(result, DataFrame) @@ -4512,8 +4733,7 @@ def test_initialisation_bug(self): spec="eurusd_xcs", leg2_fixed=True, leg2_mtm=False, - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", leg2_fixed_rate=2.4, ) @@ -5813,7 +6033,6 @@ def test_spec_overwrites(self) -> None: termination=dt(2024, 2, 26), calendar="tgt", frequency="Q", - leg2_method_param=0, notional=250.0, spec="test", curves="test", @@ -5827,6 +6046,7 @@ def test_spec_overwrites(self) -> None: leg2_pair=NoInput(1), fx_fixings=NoInput(0), leg2_fx_fixings=NoInput(1), + leg2_zero_periods=NoInput(0), mtm=LegMtm.Payment, leg2_mtm=LegMtm.Payment, schedule=Schedule( @@ -5867,7 +6087,6 @@ def test_spec_overwrites(self) -> None: leg2_amortization=NoInput(0), fixed_rate=NoInput(0), leg2_fixing_method=NoInput(0), - leg2_method_param=0, leg2_spread_compound_method=NoInput(0), leg2_rate_fixings=NoInput(0), leg2_float_spread=NoInput(0), @@ -5921,7 +6140,7 @@ def test_sbs(self) -> None: assert inst.kwargs.leg1["convention"] == "30e360" assert inst.kwargs.leg2["convention"] == "30e360" assert inst.kwargs.leg1["currency"] == "eur" - assert inst.kwargs.leg2["fixing_method"] == "ibor" + assert inst.kwargs.leg2["fixing_method"] == "ibor(2)" assert inst.kwargs.leg1["schedule"].frequency == "A" assert inst.kwargs.leg2["schedule"].frequency == "S" @@ -6029,7 +6248,7 @@ def test_fra(self) -> None: modifier="F", fixed_rate=2.0, ) - assert fra.kwargs.leg2["fixing_method"] == FloatFixingMethod.IBOR + assert fra.kwargs.leg2["fixing_method"] == "ibor(2)" assert fra.kwargs.leg1["convention"] == "act360" assert fra.kwargs.leg1["currency"] == "eur" assert fra.kwargs.leg2["currency"] == "eur" @@ -6044,8 +6263,7 @@ def test_frn(self) -> None: spec="usd_frn5", payment_lag=5, ) - assert frn.kwargs.leg1["fixing_method"] == "rfr_observation_shift" - assert frn.kwargs.leg1["method_param"] == 5 + assert frn.kwargs.leg1["fixing_method"] == "rfr_observation_shift(5)" assert frn.kwargs.leg1["convention"] == "act360" assert frn.kwargs.leg1["currency"] == "usd" assert frn.kwargs.leg1["schedule"].payment_adjuster == Adjuster.BusDaysLagSettle(5) @@ -8656,8 +8874,7 @@ def test_local_fixings_rate_and_fx(self): currency="usd", pair="eurusd", fx_fixings="wmr", - leg2_fixing_method="ibor", - leg2_method_param=0, + leg2_fixing_method="ibor(0)", leg2_rate_fixings="ibor", payment_lag=0, curves=[curve], diff --git a/python/tests/legs/test_leg_fixings.py b/python/tests/legs/test_leg_fixings.py index 41e50c86e..f271ef7fd 100644 --- a/python/tests/legs/test_leg_fixings.py +++ b/python/tests/legs/test_leg_fixings.py @@ -16,6 +16,7 @@ from rateslib import fixings from rateslib.curves import Curve from rateslib.enums.generics import NoInput +from rateslib.enums.parameters import FloatFixingMethod from rateslib.legs import FixedLeg, FloatLeg from rateslib.scheduling import Schedule @@ -164,8 +165,7 @@ def test_populated_resets_ibor(self): index_method="monthly", pair="eurusd", fx_fixings="fx", - fixing_method="ibor", - method_param=0, + fixing_method="ibor(0)", rate_fixings="ibor", ) assert fl.periods[0].rate_params.rate_fixing.value == 1.0483333333333333 @@ -234,8 +234,7 @@ def test_populated_at_init_no_reset(self): index_method="monthly", pair="eurusd", fx_fixings="fx", - fixing_method="ibor", - method_param=0, + fixing_method=FloatFixingMethod.IBOR(0), rate_fixings="ibor", ) assert fl.periods[0].rate_params.rate_fixing.value == 1.0483333333333333 diff --git a/python/tests/legs/test_legs_legacy.py b/python/tests/legs/test_legs_legacy.py index 34054c57d..787a0bb02 100644 --- a/python/tests/legs/test_legs_legacy.py +++ b/python/tests/legs/test_legs_legacy.py @@ -22,6 +22,7 @@ from rateslib.data.fixings import FloatRateSeries, FXIndex from rateslib.default import NoInput from rateslib.dual import Dual +from rateslib.enums import SpreadCompoundMethod from rateslib.enums.generics import _drb from rateslib.enums.parameters import LegMtm from rateslib.fx import FXForwards, FXRates @@ -43,7 +44,9 @@ CreditProtectionPeriod, FixedPeriod, FloatPeriod, + ZeroFloatPeriod, ) +from rateslib.rs import LegIndexBase from rateslib.scheduling import Frequency, Schedule, get_calendar @@ -259,8 +262,7 @@ def test_float_leg_fixings2(self, curve) -> None: payment_lag=0, ), rate_fixings=name, - fixing_method="IBOR", - method_param=0, + fixing_method="IBOR(0)", ) assert float_leg.periods[0].rate_params.rate_fixing.value == 10 assert float_leg.periods[1].rate_params.rate_fixing.value == 20 @@ -285,14 +287,14 @@ def test_float_leg_fixings_scalar(self, curve) -> None: assert float_leg.periods[2].rate_params.rate_fixing.value is NoInput(0) @pytest.mark.parametrize( - ("method", "param"), + ("method"), [ - ("rfr_payment_delay", NoInput(0)), - ("rfr_lockout", 1), - ("rfr_observation_shift", 0), + "rfr_payment_delay", + "rfr_lockout(1)", + "rfr_observation_shift(0)", ], ) - def test_float_leg_rfr_fixings_table(self, method, param, curve) -> None: + def test_float_leg_rfr_fixings_table(self, method, curve) -> None: name = str(hash(os.urandom(8))) fixings.add( f"{name}_1B", @@ -313,7 +315,6 @@ def test_float_leg_rfr_fixings_table(self, method, param, curve) -> None: rate_fixings=name, currency="SEK", fixing_method=method, - method_param=param, ) result = float_leg.local_analytic_rate_fixings(rate_curve=curve) result = result[dt(2022, 12, 28) : dt(2023, 1, 1)] @@ -426,7 +427,7 @@ def test_float_leg_set_float_spread(self, curve) -> None: @pytest.mark.parametrize( ("method", "spread_method", "expected"), [ - ("ibor", NoInput(0), True), + ("ibor(2)", NoInput(0), True), ("rfr_payment_delay", "none_simple", True), ("rfr_payment_delay", "isda_compounding", False), ("rfr_payment_delay", "isda_flat_compounding", False), @@ -650,8 +651,7 @@ def test_leg_fixings_as_2_tuple(self) -> None: ), rate_fixings=(1.5, name), currency="SEK", - fixing_method="ibor", - method_param=0, + fixing_method="ibor(0)", ) assert float_leg.periods[0].rate_params.rate_fixing.value == 1.5 assert float_leg.periods[1].rate_params.rate_fixing.value == 2.0 @@ -886,6 +886,281 @@ def test_non_mtm_xcs_nd_type(self, fx_fixings, expected): assert fl.periods[3].non_deliverable_params.fx_fixing.value == expected[3] fixings.pop("AXDE_EURUSD") + def test_sub_zero(self): + # test that a Leg with a zero flag can be composed of multiple ZeroFloatPeriods + # e.g. quarterly payments on 7d + # this tests specifically a 1Y CNY IRS with Quarterly payments to CNRR007 7d rate. + fl = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 21), + termination=dt(2027, 1, 21), + frequency="Q", + calendar="all", + ), + fixing_frequency="7d", + fixing_method="ibor(1)", + zero_periods=True, + ) + curve = Curve({dt(2026, 1, 20): 1.0, dt(2027, 10, 1): 0.95}) + + # ensure all periods have rates + for zero_period in fl._regular_periods: + for float_period in zero_period.float_periods: + _ = float_period.rate(rate_curve=curve) + + result = fl.local_analytic_rate_fixings(rate_curve=curve) + # first 4 fixings are regular: back stubs. + assert [ + dt(2026, 1, 20), + dt(2026, 1, 27), + dt(2026, 2, 3), + dt(2026, 2, 10), + ] == result.index.to_list()[:4] + # around the July Payment date + assert dt(2026, 7, 13) in result.index + assert dt(2026, 7, 20) in result.index + assert dt(2026, 7, 27) in result.index + + # around the October Payment date with stubs + assert dt(2026, 10, 12) in result.index + assert dt(2026, 10, 19) in result.index + assert dt(2026, 10, 20) in result.index + assert dt(2026, 10, 27) in result.index + + # final fixings + assert dt(2027, 1, 12) in result.index + assert dt(2027, 1, 19) in result.index + assert isinstance(fl._regular_periods[0], ZeroFloatPeriod) + + def test_sub_zero_bjs_calendar(self): + # test that a Leg with a zero flag can be composed of multiple ZeroFloatPeriods + # e.g. quarterly payments on 7d + # this tests specifically a 1Y CNY IRS with Quarterly payments to CNRR007 7d rate. + fl = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 21), + termination=dt(2027, 1, 21), + frequency="Q", + calendar="bjs", + ), + fixing_frequency="7d", + fixing_method="ibor(1)", + fixing_series=FloatRateSeries( + lag=1, + convention="Act365F", + calendar="bjs", + tenors=["7D"], + zero_period_stub="shortback", + modifier="F", + eom=False, + ), + zero_periods=True, + ) + curve = Curve( + nodes={dt(2026, 1, 20): 1.0, dt(2027, 10, 1): 0.95}, + convention="act365f", + ) + + # ensure all periods have rates + for zero_period in fl._regular_periods: + for float_period in zero_period.float_periods: + _ = float_period.rate(rate_curve=curve) + + result = fl.local_analytic_rate_fixings(rate_curve=curve) + # first 4 fixings are regular: back stubs. + assert [ + dt(2026, 1, 20), + dt(2026, 1, 27), + dt(2026, 2, 3), + dt(2026, 2, 10), + ] == result.index.to_list()[:4] + # around the July Payment date + assert dt(2026, 7, 13) in result.index + assert dt(2026, 7, 20) in result.index + assert dt(2026, 7, 27) in result.index + + # around the October Payment date with stubs + assert dt(2026, 10, 12) in result.index + assert dt(2026, 10, 19) in result.index + assert dt(2026, 10, 20) in result.index + assert dt(2026, 10, 27) in result.index + + # final fixings + assert dt(2027, 1, 12) in result.index + assert dt(2027, 1, 19) in result.index + assert isinstance(fl._regular_periods[0], ZeroFloatPeriod) + + def test_sub_zero_equivalence_with_rfr_type_rate(self): + # test the two representations of an object yield the same data. + curve = Curve( + nodes={dt(2026, 1, 20): 1.0, dt(2026, 3, 20): 0.99, dt(2026, 5, 20): 0.984}, + calendar="nyc", + convention="act360", + ) + regular = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 20), + termination=dt(2026, 2, 3), + frequency="7d", + calendar="nyc", + modifier="F", + ), + fixing_series="usd_rfr", + fixing_frequency="1b", + fixing_method="rfr_payment_delay", + ) + zero_type = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 20), + termination=dt(2026, 2, 3), + frequency="7d", + calendar="nyc", + modifier="F", + ), + fixing_series="usd_rfr", + fixing_frequency="1b", + fixing_method="rfr_payment_delay", + zero_periods=True, + ) + + rates = [ + curve.rate(dt(2026, 1, 20), dt(2026, 1, 21)), + curve.rate(dt(2026, 1, 21), dt(2026, 1, 22)), + curve.rate(dt(2026, 1, 22), dt(2026, 1, 23)), + curve.rate(dt(2026, 1, 23), dt(2026, 1, 26)), + curve.rate(dt(2026, 1, 26), dt(2026, 1, 27)), + ] + from math import prod + + rate = prod( + [ + 1 + r / 100 * d + for (r, d) in zip(rates, [1 / 360, 1 / 360, 1 / 360, 3 / 360, 1 / 360]) + ] + ) + rate = (rate - 1) * 36000 / 7 + + rate1 = regular.periods[0].rate(rate_curve=curve) + rate2 = zero_type.periods[0].rate(rate_curve=curve) + assert abs(rate1 - rate) < 1e-8 + assert abs(rate2 - rate) < 1e-8 + + rates2 = [_.rate(rate_curve=curve) for _ in zero_type.periods[0].float_periods] + assert all(abs(x - y) < 1e-10 for (x, y) in zip(rates, rates2)) + + def test_sub_zero_equivalence_with_rfr_type_rate_with_fixings(self): + # test the two representations of an object yield the same data. + name = str(hash(os.urandom(3))) + fixings.add( + name + "_1B", Series(index=[dt(2026, 1, 20), dt(2026, 1, 21)], data=[10.0, 12.0]) + ) + curve = Curve( + nodes={dt(2026, 1, 20): 1.0, dt(2026, 3, 20): 0.99, dt(2026, 5, 20): 0.984}, + calendar="nyc", + convention="act360", + ) + regular = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 20), + termination=dt(2026, 2, 3), + frequency="7d", + calendar="nyc", + modifier="F", + ), + fixing_series="usd_rfr", + fixing_frequency="1b", + fixing_method="rfr_payment_delay", + rate_fixings=name, + ) + zero_type = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 20), + termination=dt(2026, 2, 3), + frequency="7d", + calendar="nyc", + modifier="F", + ), + fixing_series="usd_rfr", + fixing_frequency="1b", + fixing_method="rfr_payment_delay", + zero_periods=True, + rate_fixings=name, + ) + + rates = [ + # curve.rate(dt(2026, 1, 20), dt(2026, 1, 21)), + # curve.rate(dt(2026, 1, 21), dt(2026, 1, 22)), + 10.0, + 12.0, + curve.rate(dt(2026, 1, 22), dt(2026, 1, 23)), + curve.rate(dt(2026, 1, 23), dt(2026, 1, 26)), + curve.rate(dt(2026, 1, 26), dt(2026, 1, 27)), + ] + from math import prod + + rate = prod( + [ + 1 + r / 100 * d + for (r, d) in zip(rates, [1 / 360, 1 / 360, 1 / 360, 3 / 360, 1 / 360]) + ] + ) + rate = (rate - 1) * 36000 / 7 + + rate1 = regular.periods[0].rate(rate_curve=curve) + rate2 = zero_type.periods[0].rate(rate_curve=curve) + assert abs(rate1 - rate) < 1e-8 + assert abs(rate2 - rate) < 1e-8 + + rates2 = [_.rate(rate_curve=curve) for _ in zero_type.periods[0].float_periods] + assert all(abs(x - y) < 1e-10 for (x, y) in zip(rates, rates2)) + fixings.pop(name + "_1B") + + def test_sub_zero_index_dates(self): + fl = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 20), + termination=dt(2026, 2, 3), + frequency="7d", + calendar="nyc", + modifier="F", + ), + fixing_series="usd_rfr", + fixing_frequency="1b", + fixing_method="rfr_payment_delay", + zero_periods=True, + index_base=300.0, + ) + assert len(fl.periods) == 2 + assert fl.periods[0].index_params.index_fixing.date == dt(2026, 1, 27) + assert fl.periods[1].index_params.index_fixing.date == dt(2026, 2, 3) + assert fl.periods[0].index_params.index_base.date == dt(2026, 1, 20) + assert fl.periods[1].index_params.index_base.date == dt(2026, 1, 20) + + def test_sub_zero_spread_compounding(self): + # test that a spread under `zero_periods` is added to eahc rate individually prior to + # compounding. The spread compound method only operates at the Period level which + # is specific for a ZeroFloatPeriod. + fl = FloatLeg( + schedule=Schedule( + effective=dt(2026, 1, 20), + termination=dt(2027, 1, 20), + frequency="A", + calendar="all", + modifier="F", + ), + fixing_frequency="S", + fixing_method="ibor(0)", + rate_fixings=[[5.0, 5.5]], + float_spread=50.0, + zero_periods=True, + spread_compound_method=SpreadCompoundMethod.NoneSimple, + ) + result = fl.periods[0].rate() + expected = ( + ((1 + 181 / 36000 * (5.0 + 0.5)) * (1 + 184 / 36000 * (5.5 + 0.5)) - 1) * 36000 / 365 + ) + assert abs(result - expected) < 1e-10 + class TestZeroFloatLeg: def test_zero_float_leg_set_float_spread(self, curve) -> None: @@ -930,8 +1205,7 @@ def test_with_fixings(self): frequency="Q", calendar="all", ), - method_param=0, - fixing_method="ibor", + fixing_method="ibor(0)", rate_fixings=name, ) expected = [5.0, 2.0, 3.0] @@ -1091,8 +1365,7 @@ def test_ibor_fixings_table(self, curve) -> None: ), notional=-1e9, convention="Act360", - fixing_method="ibor", - method_param=0, + fixing_method="ibor(0)", ) result = zfl.local_analytic_rate_fixings(rate_curve=curve) assert abs(result.iloc[0, 0] - 24750) < 1e-3 @@ -1112,8 +1385,7 @@ def test_ibor_stub_fixings_table(self, curve) -> None: ), notional=-1e9, convention="Act360", - fixing_method="ibor", - method_param=0, + fixing_method="ibor(0)", ) result = zfl.local_analytic_rate_fixings( rate_curve={"1m": curve, "3m": curve2}, disc_curve=curve @@ -1140,8 +1412,7 @@ def test_ibor_fixings_table_after_known_fixings(self, curve, fixings) -> None: ), notional=-1e9, convention="Act360", - fixing_method="ibor", - method_param=0, + fixing_method="ibor(0)", rate_fixings=fixings, ) result = zfl.local_analytic_rate_fixings( @@ -1209,7 +1480,7 @@ def test_zero_float_spread_calc(self, settlement, forward, exp, curve) -> None: ), notional=-1e8, convention="Act360", - fixing_method="ibor", + fixing_method="ibor(2)", ) tgt_npv = 25000000 * curve[dt(2027, 1, 1)] result = zfl.spread( @@ -1363,6 +1634,30 @@ def test_zero_fixed_spread(self, settlement, forward, exp, curve) -> None: ) assert abs(result / 100 - exp) < 1e-3 + @pytest.mark.parametrize("final_exchange", [False, True]) + def test_zero_fixed_spread_exchanges(self, curve, final_exchange) -> None: + zfl = ZeroFixedLeg( + schedule=Schedule( + effective=dt(2022, 1, 5), + termination="8m", + payment_lag=0, + frequency="M", + ), + notional=-1e8, + convention="ActAct", + final_exchange=final_exchange, + fixed_rate=NoInput(0), + ) + result = zfl.spread( + target_npv=50000.0 + 1e8 * curve[dt(2022, 9, 5)] * final_exchange, rate_curve=curve + ) + expected = 7.718420018560934 # bps + assert abs(result - expected) < 1e-8 + + zfl.fixed_rate = expected / 100.0 + result = zfl.npv(rate_curve=curve) + assert abs(result - (50000.0 + 1e8 * curve[dt(2022, 9, 5)] * final_exchange)) < 1e-7 + def test_zero_fixed_spread_raises_settlement(self, curve) -> None: zfl = ZeroFixedLeg( schedule=Schedule( @@ -1384,7 +1679,8 @@ def test_zero_fixed_spread_raises_settlement(self, curve) -> None: forward=NoInput(0), ) - def test_zero_fixed_spread_indexed(self, curve) -> None: + @pytest.mark.parametrize("final_exchange", [False, True]) + def test_zero_fixed_spread_indexed(self, curve, final_exchange) -> None: zfl = ZeroFixedLeg( schedule=Schedule( effective=dt(2022, 1, 1), @@ -1395,17 +1691,24 @@ def test_zero_fixed_spread_indexed(self, curve) -> None: notional=-1e8, convention="ActAct", fixed_rate=NoInput(0), + final_exchange=final_exchange, index_base=100.0, index_fixings=110.0, ) + target_npv = (13140821.29 + 1e8 * 1.1 * final_exchange) * curve[dt(2027, 1, 1)] result = zfl.spread( - target_npv=13140821.29 * curve[dt(2027, 1, 1)], + target_npv=target_npv, rate_curve=NoInput(0), disc_curve=curve, ) assert abs(result / 100 - 2.2826266057484057) < 1e-3 - def test_zero_fixed_spread_non_deliverable(self, curve) -> None: + zfl.fixed_rate = result / 100.0 + result = zfl.npv(rate_curve=curve) + assert abs(result - target_npv) < 1e-7 + + @pytest.mark.parametrize("final_exchange", [False, True]) + def test_zero_fixed_spread_non_deliverable(self, curve, final_exchange) -> None: zfl = ZeroFixedLeg( schedule=Schedule( effective=dt(2022, 1, 1), @@ -1417,16 +1720,22 @@ def test_zero_fixed_spread_non_deliverable(self, curve) -> None: convention="ActAct", fixed_rate=NoInput(0), currency="usd", + final_exchange=final_exchange, pair="eurusd", fx_fixings=2.0, ) + target_npv = (13140821.29 + 1e8 * 2.0 * final_exchange) * curve[dt(2027, 1, 1)] result = zfl.spread( - target_npv=13140821.29 * curve[dt(2027, 1, 1)], + target_npv=target_npv, rate_curve=NoInput(0), disc_curve=curve, ) assert abs(result / 100 - 1.2808477472765924) < 1e-3 + zfl.fixed_rate = result / 100.0 + result = zfl.npv(rate_curve=curve) + assert abs(result - target_npv) < 1e-7 + def test_amortization_raises(self) -> None: with pytest.raises(TypeError, match="unexpected keyword argument 'amortization'"): ZeroFixedLeg( @@ -2472,6 +2781,21 @@ def test_non_mtm_xcs_nd_type(self, fx_fixings, expected): assert fl.periods[3].non_deliverable_params.fx_fixing.value == expected[3] fixings.pop("AXDE_EURUSD") + def test_leg_index_base(self): + fl = FixedLeg( + schedule=Schedule( + effective=dt(2000, 1, 7), + termination=dt(2000, 3, 7), + frequency="M", + calendar="all", + ), + index_fixings="some", + index_lag=0, + index_base_type=LegIndexBase.PeriodOnPeriod, + ) + assert fl.periods[0].index_params.index_base.date == dt(2000, 1, 7) + assert fl.periods[1].index_params.index_base.date == dt(2000, 2, 7) + class TestCreditPremiumLeg: @pytest.mark.parametrize( @@ -2681,7 +3005,7 @@ def test_leg_cashflows(self, hazard_curve, curve) -> None: frequency="Q", ), notional=-1e9, - convention="Act360", + # convention="Act360", ) result = leg.cashflows(rate_curve=hazard_curve, disc_curve=curve) # test a couple of return elements @@ -2697,7 +3021,7 @@ def test_leg_zero_sched(self): frequency="Z", ), notional=-1e9, - convention="Act360", + # convention="Act360", ) assert len(leg.periods) == 1 assert leg.periods[0].period_params.end == dt(2024, 6, 1) @@ -3235,8 +3559,7 @@ def test_float_leg_exchange_fixings_table(self) -> None: currency="usd", pair="eurusd", notional=10e6, - fixing_method="ibor", - method_param=0, + fixing_method="ibor(0)", mtm="xcs", initial_exchange=True, ) @@ -3435,7 +3758,7 @@ class TestCustomLeg: end=dt(2022, 4, 1), payment=dt(2022, 4, 3), notional=1e9, - convention="Act360", + # convention="Act360", termination=dt(2022, 4, 1), frequency=Frequency.Months(3, None), currency="usd", diff --git a/python/tests/periods/test_fixings_exposure.py b/python/tests/periods/test_fixings_exposure.py index 32824c434..996b5dba4 100644 --- a/python/tests/periods/test_fixings_exposure.py +++ b/python/tests/periods/test_fixings_exposure.py @@ -40,16 +40,16 @@ def curve(): class TestFloatPeriod: @pytest.mark.parametrize( - ("method", "param"), + ("method"), [ - (FloatFixingMethod.RFRPaymentDelay, 0), - (FloatFixingMethod.RFRObservationShift, 3), - (FloatFixingMethod.RFRLockout, 2), - (FloatFixingMethod.RFRLookback, 3), - (FloatFixingMethod.RFRLockoutAverage, 2), - (FloatFixingMethod.RFRPaymentDelayAverage, 0), - (FloatFixingMethod.RFRObservationShiftAverage, 3), - (FloatFixingMethod.RFRLookbackAverage, 3), + FloatFixingMethod.RFRPaymentDelay(), + FloatFixingMethod.RFRObservationShift(3), + FloatFixingMethod.RFRLockout(2), + FloatFixingMethod.RFRLookback(3), + FloatFixingMethod.RFRLockoutAverage(2), + FloatFixingMethod.RFRPaymentDelayAverage(), + FloatFixingMethod.RFRObservationShiftAverage(3), + FloatFixingMethod.RFRLookbackAverage(3), ], ) @pytest.mark.parametrize( @@ -63,11 +63,11 @@ class TestFloatPeriod: (SpreadCompoundMethod.ISDAFlatCompounding, 500.0), ], ) - def test_baseline_versus_solver_fixings_sensitivity(self, method, param, scm, spread, curve): + def test_baseline_versus_solver_fixings_sensitivity(self, method, scm, spread, curve): # the Solver can make fixings exposure calculations independently from analytical # calculations and approximations. This tests validates the analytical calculations # against the Solver - if method in [ + if type(method) in [ FloatFixingMethod.RFRLockoutAverage, FloatFixingMethod.RFRPaymentDelayAverage, FloatFixingMethod.RFRObservationShiftAverage, @@ -137,7 +137,6 @@ def test_baseline_versus_solver_fixings_sensitivity(self, method, param, scm, sp notional=-10e6, fixing_series="usd_rfr", fixing_method=method, - method_param=param, frequency="A", start=dt(2022, 2, 3), end=dt(2022, 2, 10), @@ -165,7 +164,7 @@ def test_baseline_versus_solver_fixings_sensitivity(self, method, param, scm, sp ) risk_compare = fixings_[("curve", "usd", "usd", "1B")].astype(float).fillna(0.0).to_numpy() - risk_array = risk.to_numpy()[:, 0] + risk_array = risk.to_numpy()[:, 0].copy() _diff = np.max(np.abs(risk_compare - risk_array)) if scm == SpreadCompoundMethod.ISDAFlatCompounding and spread > 100.0: @@ -187,7 +186,6 @@ def test_baseline_versus_solver_fixings_sensitivity(self, method, param, scm, sp notional=-10e6, fixing_series="usd_rfr", fixing_method=method, - method_param=param, frequency="A", start=dt(2022, 2, 3), end=dt(2022, 2, 10), @@ -224,8 +222,7 @@ def test_ibor_curve_example_book(self, curve): p = FloatPeriod( notional=-10e6, fixing_series="eur_ibor", - fixing_method="ibor", - method_param=1, + fixing_method="ibor(2)", frequency="Q", start=dt(2025, 10, 8), end=dt(2026, 1, 8), @@ -241,8 +238,7 @@ def test_ibor_curve_example_book(self, curve): def test_ibor_stub_curve_example_book(self, curve): p = FloatPeriod( notional=-10e6, - fixing_method="ibor", - method_param=2, + fixing_method=FloatFixingMethod.IBOR(2), frequency="Q", start=dt(2025, 10, 8), end=dt(2025, 12, 16), @@ -264,8 +260,7 @@ def test_ibor_fixing_set(self, curve): p = FloatPeriod( notional=-10e6, fixing_series="eur_ibor", - fixing_method="ibor", - method_param=1, + fixing_method="ibor(2)", rate_fixings=2.0, frequency="Q", start=dt(2025, 10, 8), @@ -282,8 +277,7 @@ def test_ibor_fixing_set(self, curve): def test_ibor_stub_curve_fixings_set(self, curve): p = FloatPeriod( notional=-10e6, - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", frequency="Q", start=dt(2025, 10, 8), end=dt(2025, 12, 16), @@ -302,20 +296,19 @@ def test_ibor_stub_curve_fixings_set(self, curve): assert result.index[0] == dt(2025, 10, 6) @pytest.mark.parametrize( - ("method", "param", "expected"), + ("method", "expected"), [ - (FloatFixingMethod.RFRPaymentDelay, 0, [0, 0, 0, 0, 277, 830, 277, 277, 277, 0]), - (FloatFixingMethod.RFRLockout, 2, [0, 0, 0, 0, 277, 830, 830, 0, 0, 0]), - (FloatFixingMethod.RFRLookback, 3, [0, 277, 830, 277, 277, 277, 0, 0, 0, 0]), - (FloatFixingMethod.RFRObservationShift, 3, [0, 277, 277, 277, 277, 830, 0, 0, 0, 0]), + (FloatFixingMethod.RFRPaymentDelay(), [0, 0, 0, 0, 277, 830, 277, 277, 277, 0]), + (FloatFixingMethod.RFRLockout(2), [0, 0, 0, 0, 277, 830, 830, 0, 0, 0]), + (FloatFixingMethod.RFRLookback(3), [0, 277, 830, 277, 277, 277, 0, 0, 0, 0]), + (FloatFixingMethod.RFRObservationShift(3), [0, 277, 277, 277, 277, 830, 0, 0, 0, 0]), ], ) - def test_rfr_curve_book(self, method, param, expected, curve): + def test_rfr_curve_book(self, method, expected, curve): p = FloatPeriod( notional=-1e6, fixing_series="usd_rfr", fixing_method=method, - method_param=param, frequency="Q", start=dt(2022, 2, 3), end=dt(2022, 2, 10), @@ -350,7 +343,6 @@ def test_doc_reset(self): payment=dt(2026, 1, 16), frequency="M", fixing_method="rfr_payment_delay", - method_param=0, rate_fixings="sofr", ) fixings.add( @@ -460,10 +452,9 @@ def test_multiple_sub_periods(self): fixings.add("MY_RATE_INDEX_6M", pd.Series(index=[dt(1999, 1, 1)], data=[1.15])) period = ZeroFloatPeriod( schedule=Schedule(dt(2000, 1, 1), "2Y", "S"), - fixing_method="IBOR", + fixing_method=FloatFixingMethod.IBOR(0), rate_fixings="MY_RATE_INDEX", convention="Act360", - method_param=0, notional=1e6, ) rc = Curve({dt(2000, 1, 1): 1.0, dt(2003, 1, 1): 0.95}) diff --git a/python/tests/periods/test_fixings_load.py b/python/tests/periods/test_fixings_load.py index 4dc01e98d..5976a58e7 100644 --- a/python/tests/periods/test_fixings_load.py +++ b/python/tests/periods/test_fixings_load.py @@ -277,8 +277,7 @@ def test_rate_fixings_input_as_str_out_of_range( notional=2.0, frequency="M", fixing_series="usd_ibor", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", rate_fixings="IBOR123dfgs", ) assert c.rate_params.rate_fixing.value == NoInput(0) @@ -296,9 +295,8 @@ def test_rate_fixings_no_input( payment=dt(2000, 2, 1), notional=2.0, frequency="M", - fixing_method="IBOR", + fixing_method=FloatFixingMethod.IBOR(2), fixing_series="usd_ibor", - method_param=2, rate_fixings=NoInput(0), ) assert c.rate_params.rate_fixing.value == NoInput(0) @@ -314,9 +312,8 @@ def test_rate_fixings_scalar( payment=dt(2000, 2, 1), notional=2.0, frequency="M", - fixing_method="IBOR", + fixing_method="IBOR(2)", fixing_series="usd_ibor", - method_param=2, rate_fixings=2.5, ) assert c.rate_params.rate_fixing.value == 2.5 @@ -372,8 +369,7 @@ def test_rfr_fixings_load(self): accrual_start=dt(2023, 2, 8), accrual_end=dt(2023, 2, 13), rate_index=rate_index, - fixing_method=FloatFixingMethod.RFRPaymentDelay, - method_param=0, + fixing_method=FloatFixingMethod.RFRPaymentDelay(), spread_compound_method=SpreadCompoundMethod.NoneSimple, identifier=f"{name}_1B", float_spread=0.0, @@ -386,8 +382,7 @@ def test_rfr_fixings_load(self): accrual_start=dt(2023, 2, 8), accrual_end=dt(2023, 2, 17), rate_index=rate_index, - fixing_method=FloatFixingMethod.RFRPaymentDelay, - method_param=0, + fixing_method=FloatFixingMethod.RFRPaymentDelay(), spread_compound_method=SpreadCompoundMethod.NoneSimple, identifier=f"{name}_1B", float_spread=0.0, @@ -395,21 +390,23 @@ def test_rfr_fixings_load(self): result = f.value assert result == NoInput(0) - def test_stub_ibor_warns_no_series(self): - with pytest.warns(UserWarning, match=err.UW_NO_TENORS[:15]): - fix = IBORStubFixing( - accrual_start=dt(2022, 1, 5), - accrual_end=dt(2022, 5, 21), - rate_series=FloatRateSeries( - lag=0, - calendar="tgt", - convention="act360", - modifier="mf", - eom=False, - ), - identifier="NOT_AVAILABLE", - ) - assert isinstance(fix.value, NoInput) + # # test is removed because a `fixing_series` with no tenors now + # # defaults to [1w, 1M, 3M, 6M, 12M] + # def test_stub_ibor_warns_no_series(self): + # with pytest.warns(UserWarning, match=err.UW_NO_TENORS[:15]): + # fix = IBORStubFixing( + # accrual_start=dt(2022, 1, 5), + # accrual_end=dt(2022, 5, 21), + # rate_series=FloatRateSeries( + # lag=0, + # calendar="tgt", + # convention="act360", + # modifier="mf", + # eom=False, + # ), + # identifier="NOT_AVAILABLE", + # ) + # assert isinstance(fix.value, NoInput) def test_rfr_fixing_identifier(self): p = FloatPeriod( @@ -417,7 +414,7 @@ def test_rfr_fixing_identifier(self): end=dt(2000, 4, 1), frequency=Frequency.Months(3, None), payment=dt(2000, 1, 4), - fixing_method=FloatFixingMethod.RFRPaymentDelay, + fixing_method=FloatFixingMethod.RFRPaymentDelay(), rate_fixings="TEST", ) assert p.rate_params.fixing_identifier == "TEST" @@ -429,7 +426,7 @@ def test_ibor_fixing_identifier(self): end=dt(2000, 4, 1), frequency=Frequency.Months(3, None), payment=dt(2000, 1, 4), - fixing_method=FloatFixingMethod.IBOR, + fixing_method=FloatFixingMethod.IBOR(2), rate_fixings="TEST", ) assert p.rate_params.fixing_identifier == "TEST" @@ -441,22 +438,22 @@ def test_ibor12M_fixing_identifier(self): end=dt(2001, 1, 1), frequency=Frequency.Months(12, None), payment=dt(2000, 1, 4), - fixing_method=FloatFixingMethod.IBOR, + fixing_method=FloatFixingMethod.IBOR(2), rate_fixings="TEST", ) assert p.rate_params.fixing_identifier == "TEST" assert p.rate_params.rate_fixing.identifier == "TEST_12M" def test_ibor_stub_fixing_identifier(self): - with pytest.warns(UserWarning, match=err.UW_NO_TENORS[:15]): - p = FloatPeriod( - start=dt(2000, 1, 1), - end=dt(2000, 3, 1), - frequency=Frequency.Months(3, None), - payment=dt(2000, 1, 4), - fixing_method=FloatFixingMethod.IBOR, - stub=True, - rate_fixings="TEST", - ) - assert p.rate_params.fixing_identifier == "TEST" - assert p.rate_params.rate_fixing.identifier == "TEST" + # these tenors are derived from the default tenors [1W, 1M, 3M, 6M, 12M] + p = FloatPeriod( + start=dt(2000, 1, 1), + end=dt(2000, 3, 1), + frequency=Frequency.Months(3, None), + payment=dt(2000, 1, 4), + fixing_method=FloatFixingMethod.IBOR(2), + stub=True, + rate_fixings="TEST", + ) + assert p.rate_params.rate_fixing.fixing1.identifier == "TEST_1M" + assert p.rate_params.rate_fixing.fixing2.identifier == "TEST_3M" diff --git a/python/tests/periods/test_float_rate.py b/python/tests/periods/test_float_rate.py index c132437c2..c1bbf8dd8 100644 --- a/python/tests/periods/test_float_rate.py +++ b/python/tests/periods/test_float_rate.py @@ -118,8 +118,7 @@ def test_tenor_rate_from_curve(self, curve, line_curve): end=dt(2000, 4, 3), stub=False, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) assert abs(result - 2.18) < 1e-12 @@ -135,8 +134,7 @@ def test_tenor_rate_from_curve_fail_from_history(self, curve, line_curve): end=dt(1980, 4, 3), stub=False, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) @@ -150,8 +148,7 @@ def test_tenor_rate_from_dict_curve(self, curve, curve2, line_curve, line_curve2 end=dt(2000, 4, 3), stub=False, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) assert abs(result - 2.18) < 1e-12 @@ -171,8 +168,7 @@ def test_tenor_rate_from_scalar_fixing(self, curve, curve2, line_curve, line_cur end=dt(2000, 4, 3), stub=False, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) assert abs(result - 1.68) < 1e-12 @@ -193,8 +189,7 @@ def test_tenor_rate_from_fixing_str(self, curve, line_curve, curve2, line_curve2 end=dt(2000, 4, 3), stub=False, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) assert abs(result - 1.38) < 1e-12 @@ -218,8 +213,7 @@ def test_tenor_rate_from_fixing_str_fallback(self, curve, line_curve, curve2, li end=dt(2000, 4, 3), stub=False, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) assert abs(result - 2.18) < 1e-12 @@ -242,8 +236,7 @@ def test_stub_rate_from_fixing_dict(self, curve, line_curve, curve2, line_curve2 end=dt(2000, 5, 18), stub=True, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) expected = 1.2 + 1.0 * 45 / 91 + 0.18 @@ -268,8 +261,7 @@ def test_stub_rate_from_fixing_dict_missing_data(self, curve, line_curve, curve2 end=dt(2000, 5, 18), stub=True, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) # expected = 1.2 + 1.0 * 45 / 91 + 0.18 @@ -293,8 +285,7 @@ def test_stub_rate_from_fixing_dict_1tenor(self, curve, line_curve, curve2, line end=dt(2000, 5, 18), stub=True, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) expected = 4.1 + 0.18 @@ -316,8 +307,7 @@ def test_stub_rate_from_scalar_fixing(self, curve, line_curve, curve2, line_curv end=dt(2000, 5, 18), stub=True, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) expected = 9.9 + 0.18 @@ -333,8 +323,7 @@ def test_stub_rate_from_dict_curve(self, curve, curve2, line_curve, line_curve2) end=dt(2000, 5, 18), stub=True, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) expected = 2.0 * 46 / 91 + 3.0 * 45 / 91 + 0.18 @@ -351,8 +340,7 @@ def test_stub_rate_from_dict_curve_long_curves(self, curve, curve2, line_curve, end=dt(2000, 5, 18), stub=True, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) expected = 3.0 + 0.18 # just the 6m curve @@ -369,8 +357,7 @@ def test_stub_rate_from_dict_curve_short_curves(self, curve, curve2, line_curve, end=dt(2000, 5, 18), stub=True, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) expected = 2.0 + 0.18 # just the 3m curve @@ -386,8 +373,7 @@ def test_stub_rate_from_single_curve(self, curve, curve2, line_curve, line_curve end=dt(2000, 5, 18), stub=True, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) expected = 2.0 + 0.18 @@ -403,8 +389,7 @@ def test_stub_rate_from_dict_curve_on_fixing_fail(self, curve, curve2, line_curv end=dt(2000, 5, 18), stub=True, frequency="3M", - fixing_method="IBOR", - method_param=2, + fixing_method="IBOR(2)", float_spread=18.0, ) expected = 2.0 * 46 / 91 + 3.0 * 45 / 91 + 0.18 @@ -429,7 +414,7 @@ def test_populate_rates_from_rate_fixings(self): Series(index=[dt(1999, 1, 1), dt(2000, 1, 1), dt(2000, 1, 2)], data=[1.0, 2.0, 3.0]), ) result, _, _ = _RFRRate._push_rate_fixings_as_series_to_fixing_rates( - fixing_rates, "USD_SOFR_1B", FloatFixingMethod.RFRPaymentDelay, 0 + fixing_rates, "USD_SOFR_1B", FloatFixingMethod.RFRPaymentDelay() ) assert_series_equal( result, @@ -456,7 +441,7 @@ def test_populate_rates_from_rate_fixings_all_filled(self): ), ) result, _, _ = _RFRRate._push_rate_fixings_as_series_to_fixing_rates( - fixing_rates, "USD_SOFR_1B", FloatFixingMethod.RFRPaymentDelay, 0 + fixing_rates, "USD_SOFR_1B", FloatFixingMethod.RFRPaymentDelay() ) assert_series_equal( result, @@ -475,7 +460,7 @@ def test_populate_rates_from_rate_fixings_none_filled(self): Series(index=[dt(1999, 1, 1)], data=[1.0]), ) result, _, _ = _RFRRate._push_rate_fixings_as_series_to_fixing_rates( - fixing_rates, "USD_SOFR_1B", FloatFixingMethod.RFRPaymentDelay, 0 + fixing_rates, "USD_SOFR_1B", FloatFixingMethod.RFRPaymentDelay() ) assert_series_equal( result, @@ -490,7 +475,7 @@ def test_populate_rates_from_rate_fixings_missing_fixing(self): fixings.add("USD_SOFR_1B", Series(index=[dt(1999, 1, 1), dt(2000, 1, 2)], data=[1.0, 3.0])) with pytest.raises(ValueError, match="The fixings series 'USD_SOFR_1B' for the RFR 1B rat"): _RFRRate._push_rate_fixings_as_series_to_fixing_rates( - fixing_rates, "USD_SOFR_1B", FloatFixingMethod.RFRPaymentDelay, 0 + fixing_rates, "USD_SOFR_1B", FloatFixingMethod.RFRPaymentDelay() ) fixings.pop("USD_SOFR_1B") @@ -525,13 +510,13 @@ def test_populate_rates_from_rate_fixings_extra_fixing2(self): ) with pytest.warns(UserWarning, match="The fixings series 'USD_SOFR_1B' for the RFR 1B rat"): _RFRRate._push_rate_fixings_as_series_to_fixing_rates( - fixing_rates, "USD_SOFR_1B", FloatFixingMethod.RFRPaymentDelay, 0 + fixing_rates, "USD_SOFR_1B", FloatFixingMethod.RFRPaymentDelay() ) fixings.pop("USD_SOFR_1B") @pytest.mark.parametrize( ("fixing_method"), - [FloatFixingMethod.RFRPaymentDelay, FloatFixingMethod.RFRObservationShift], + [FloatFixingMethod.RFRPaymentDelay(), FloatFixingMethod.RFRObservationShift(1)], ) @pytest.mark.parametrize( ("spread_compound_method", "float_spread"), @@ -554,10 +539,9 @@ def test_efficient_calc(self, curve, fixing_method, spread_compound_method, floa rate_curve=curve, spread_compound_method=spread_compound_method, float_spread=float_spread, - method_param=1, ) - if fixing_method == FloatFixingMethod.RFRObservationShift: + if isinstance(fixing_method, FloatFixingMethod.RFRObservationShift): expected = ( (1 + r0 / 36000) * (1 + r1 / 36000) * (1 + r2 / 36000) - 1 ) * 36000 / 3.0 + float_spread / 100.0 @@ -579,7 +563,6 @@ def test_semi_inefficient_calc_with_populated_fixings(self, curve): rate_curve=curve, spread_compound_method=SpreadCompoundMethod.NoneSimple, float_spread=10.0, - method_param=0, rate_fixings="USD_SOFR_1B", ) expected = ( @@ -599,7 +582,6 @@ def test_inefficient_calc_with_populated_fixings_no_curve_raises(self, curve): rate_curve=NoInput(0), spread_compound_method=SpreadCompoundMethod.ISDACompounding, float_spread=10.0, - method_param=0, rate_fixings="USD_SOFR_1B", rate_series="usd_rfr", ) @@ -614,8 +596,7 @@ def test_inefficient_calc_with_lockout_too_long_raises(self, curve): rate_curve=curve, spread_compound_method=SpreadCompoundMethod.ISDACompounding, float_spread=10.0, - method_param=9, - fixing_method=FloatFixingMethod.RFRLockout, + fixing_method=FloatFixingMethod.RFRLockout(9), ) @pytest.mark.parametrize("curve_type", ["values", "dfs"]) @@ -631,8 +612,7 @@ def test_inefficient_calc_with_populated_fixings(self, curve_type, curve, line_c rate_curve=rate_curve, spread_compound_method=SpreadCompoundMethod.NoneSimple, float_spread=10.0, - method_param=0, - fixing_method=FloatFixingMethod.RFRLookback, + fixing_method=FloatFixingMethod.RFRLookback(0), rate_fixings="USD_SOFR_1B", ) expected = ( @@ -650,7 +630,6 @@ def test_inefficient_calc_with_non_overlapping_fixings(self, curve): rate_curve=curve, spread_compound_method=SpreadCompoundMethod.NoneSimple, float_spread=0.0, - method_param=0, rate_fixings="USD_SOFR_1B", ) fixings.pop("USD_SOFR_1B") @@ -659,43 +638,43 @@ def test_inefficient_calc_with_non_overlapping_fixings(self, curve): ("fixing_method", "expected"), [ ( - FloatFixingMethod.RFRPaymentDelay, + FloatFixingMethod.RFRPaymentDelay(), ((1 + 0.04 * D) * (1 + 0.05 * D) * (1 + 0.06 * D) * (1 + 0.07 * D) - 1) * 100 / (4 * D), ), ( - FloatFixingMethod.RFRObservationShift, + FloatFixingMethod.RFRObservationShift(2), ((1 + 0.02 * D) * (1 + 0.03 * D) * (1 + 0.04 * D) * (1 + 0.05 * D) - 1) * 100 / (4 * D), ), ( - FloatFixingMethod.RFRLockout, + FloatFixingMethod.RFRLockout(2), ((1 + 0.04 * D) * (1 + 0.05 * D) * (1 + 0.05 * D) * (1 + 0.05 * D) - 1) * 100 / (4 * D), ), ( - FloatFixingMethod.RFRLookback, + FloatFixingMethod.RFRLookback(2), ((1 + 0.02 * D) * (1 + 0.03 * D) * (1 + 0.04 * D) * (1 + 0.05 * D) - 1) * 100 / (4 * D), ), ( - FloatFixingMethod.RFRPaymentDelayAverage, + FloatFixingMethod.RFRPaymentDelayAverage(), (4 + 5 + 6 + 7) / 4, ), ( - FloatFixingMethod.RFRObservationShiftAverage, + FloatFixingMethod.RFRObservationShiftAverage(2), (2 + 3 + 4 + 5) / 4, ), ( - FloatFixingMethod.RFRLockoutAverage, + FloatFixingMethod.RFRLockoutAverage(2), (4 + 5 + 5 + 5) / 4, ), ( - FloatFixingMethod.RFRLookbackAverage, + FloatFixingMethod.RFRLookbackAverage(2), (2 + 3 + 4 + 5) / 4, ), ], @@ -720,13 +699,12 @@ def test_fixing_methods(self, fixing_method, expected): rate_curve=rate_curve, spread_compound_method=SpreadCompoundMethod.NoneSimple, float_spread=0.0, - method_param=2, fixing_method=fixing_method, ) assert abs(result - expected) < 1e-10 @pytest.mark.parametrize( - "fixing_method", [FloatFixingMethod.RFRPaymentDelay, FloatFixingMethod.RFRLockout] + "fixing_method", [FloatFixingMethod.RFRPaymentDelay(), FloatFixingMethod.RFRLockout(0)] ) def test_bus252_convention(self, fixing_method): rate_curve = Curve( @@ -743,7 +721,6 @@ def test_bus252_convention(self, fixing_method): rate_curve=rate_curve, spread_compound_method=SpreadCompoundMethod.NoneSimple, float_spread=0.0, - method_param=0, fixing_method=fixing_method, ) diff --git a/python/tests/periods/test_periods_legacy.py b/python/tests/periods/test_periods_legacy.py index 84379ae43..8a8ebff5b 100644 --- a/python/tests/periods/test_periods_legacy.py +++ b/python/tests/periods/test_periods_legacy.py @@ -28,7 +28,7 @@ from rateslib.default import NoInput, _drb from rateslib.dual import Dual, gradient from rateslib.enums import FloatFixingMethod -from rateslib.enums.parameters import FXDeltaMethod, IndexMethod +from rateslib.enums.parameters import FXDeltaMethod, IndexMethod, SpreadCompoundMethod from rateslib.fx import FXForwards, FXRates from rateslib.fx_volatility import FXDeltaVolSmile, FXSabrSmile, FXSabrSurface from rateslib.fx_volatility.utils import _d_plus_min_u @@ -315,14 +315,41 @@ def test_spread_compound_calc_raises(self) -> None: float_spread=1, ) + @pytest.mark.parametrize( + "scm", + [ + SpreadCompoundMethod.ISDACompounding, + SpreadCompoundMethod.ISDAFlatCompounding, + SpreadCompoundMethod.NoneSimple, + ], + ) + @pytest.mark.parametrize( + ("meth"), + [ + FloatFixingMethod.RFRObservationShift(2), + FloatFixingMethod.RFRPaymentDelay(), + FloatFixingMethod.RFRLockout(2), + FloatFixingMethod.RFRLookback(2), + ], + ) + def test_spread_compound_with_fixing_method_allowed(self, scm, meth): + FloatPeriod( + start=dt(2022, 1, 1), + end=dt(2022, 4, 1), + payment=dt(2022, 4, 1), + frequency="Q", + float_spread=1.0, + spread_compound_method=scm, + fixing_method=meth, + ) + def test_rfr_lockout_too_few_dates(self, curve) -> None: period = FloatPeriod( start=dt(2022, 1, 10), end=dt(2022, 1, 15), payment=dt(2022, 1, 15), frequency=Frequency.Months(1, None), - fixing_method="rfr_lockout", - method_param=6, + fixing_method="rfr_lockout(6)", ) with pytest.raises(ValueError, match="The `method_param` for an RFR Lockout type `fixing_"): period.rate(curve) @@ -350,18 +377,30 @@ def test_float_period_npv(self, curve) -> None: result = float_period.npv(rate_curve=curve) assert abs(result + 9997768.95848275) < 1e-7 - def test_rfr_avg_method_raises(self, curve) -> None: - period = FloatPeriod( - start=dt(2022, 1, 1), - end=dt(2022, 1, 4), - payment=dt(2022, 1, 4), - frequency=Frequency.Months(3, None), - fixing_method="rfr_payment_delay_avg", - spread_compound_method="isda_compounding", - ) - msg = "The `spread_compound_method` must be the 'NoneSimple' variant when using a `fixin" + @pytest.mark.parametrize( + "scm", [SpreadCompoundMethod.ISDACompounding, SpreadCompoundMethod.ISDAFlatCompounding] + ) + @pytest.mark.parametrize( + "fm", + [ + FloatFixingMethod.RFRObservationShiftAverage(2), + FloatFixingMethod.RFRPaymentDelayAverage(), + FloatFixingMethod.RFRLockoutAverage(2), + FloatFixingMethod.RFRLookbackAverage(2), + FloatFixingMethod.IBOR(2), + ], + ) + def test_rfr_avg_method_raises(self, scm, fm, curve) -> None: + msg = "is not compatible" with pytest.raises(ValueError, match=msg): - period.rate(curve) + FloatPeriod( + start=dt(2022, 1, 1), + end=dt(2022, 1, 4), + payment=dt(2022, 1, 4), + frequency=Frequency.Months(3, None), + fixing_method=fm, + spread_compound_method=scm, + ) @pytest.mark.parametrize("curve_type", ["curve", "line_curve"]) def test_rfr_payment_delay_method(self, curve_type, rfr_curve, line_curve) -> None: @@ -468,8 +507,7 @@ def test_rfr_lockout_avg_method(self, curve_type, rfr_curve, line_curve) -> None end=dt(2022, 1, 4), payment=dt(2022, 1, 4), frequency=Frequency.Months(3, None), - fixing_method="rfr_lockout_avg", - method_param=2, + fixing_method="rfr_lockout_avg(2)", fixing_series=FloatRateSeries( calendar="all", lag=0, @@ -488,8 +526,7 @@ def test_rfr_lockout_avg_method(self, curve_type, rfr_curve, line_curve) -> None end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_lockout_avg", - method_param=1, + fixing_method="rfr_lockout_avg(1)", fixing_series=FloatRateSeries( calendar="all", lag=0, @@ -504,16 +541,16 @@ def test_rfr_lockout_avg_method(self, curve_type, rfr_curve, line_curve) -> None @pytest.mark.parametrize("curve_type", ["curve", "line_curve"]) def test_rfr_lockout_avg_method_with_fixings(self, curve_type, rfr_curve, line_curve) -> None: + name = str(hash(os.urandom(2))) curve = rfr_curve if curve_type == "curve" else line_curve - fixings.add("887762_1B", Series(index=[dt(2022, 1, 1), dt(2022, 1, 2)], data=[10.0, 8.0])) + fixings.add(f"{name}_1B", Series(index=[dt(2022, 1, 1), dt(2022, 1, 2)], data=[10.0, 8.0])) period = FloatPeriod( start=dt(2022, 1, 1), end=dt(2022, 1, 4), payment=dt(2022, 1, 4), frequency=Frequency.Months(3, None), - fixing_method="rfr_lockout_avg", - method_param=2, - rate_fixings="887762", + fixing_method="rfr_lockout_avg(2)", + rate_fixings=name, fixing_series=FloatRateSeries( calendar="all", lag=0, @@ -531,9 +568,8 @@ def test_rfr_lockout_avg_method_with_fixings(self, curve_type, rfr_curve, line_c end=dt(2022, 1, 4), payment=dt(2022, 1, 1), frequency=Frequency.Months(3, None), - fixing_method="rfr_lockout_avg", - method_param=1, - rate_fixings="887762", + fixing_method="rfr_lockout_avg(1)", + rate_fixings=name, fixing_series=FloatRateSeries( calendar="all", lag=0, @@ -545,7 +581,7 @@ def test_rfr_lockout_avg_method_with_fixings(self, curve_type, rfr_curve, line_c result = period.rate(rfr_curve) expected = (10.0 + 8.0 + 8.0) / 3 assert abs(result - expected) < 1e-12 - fixings.pop("887762_1B") + fixings.pop(f"{name}_1B") @pytest.mark.parametrize("curve_type", ["curve", "line_curve"]) def test_rfr_lockout_method(self, curve_type, rfr_curve, line_curve) -> None: @@ -555,8 +591,7 @@ def test_rfr_lockout_method(self, curve_type, rfr_curve, line_curve) -> None: end=dt(2022, 1, 4), payment=dt(2022, 1, 4), frequency=Frequency.Months(3, None), - fixing_method="rfr_lockout", - method_param=2, + fixing_method="rfr_lockout(2)", fixing_series=FloatRateSeries( calendar="all", lag=0, @@ -575,8 +610,7 @@ def test_rfr_lockout_method(self, curve_type, rfr_curve, line_curve) -> None: end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_lockout", - method_param=1, + fixing_method="rfr_lockout(1)", fixing_series=FloatRateSeries( calendar="all", lag=0, @@ -598,8 +632,7 @@ def test_rfr_lockout_method_with_fixings(self, curve_type, rfr_curve, line_curve end=dt(2022, 1, 4), payment=dt(2022, 1, 4), frequency=Frequency.Months(3, None), - fixing_method="rfr_lockout", - method_param=2, + fixing_method="rfr_lockout(2)", rate_fixings="887762", fixing_series=FloatRateSeries( calendar="all", @@ -618,8 +651,7 @@ def test_rfr_lockout_method_with_fixings(self, curve_type, rfr_curve, line_curve end=dt(2022, 1, 4), payment=dt(2022, 1, 4), frequency=Frequency.Months(3, None), - fixing_method="rfr_lockout", - method_param=1, + fixing_method="rfr_lockout(1)", rate_fixings="887762", fixing_series=FloatRateSeries( calendar="all", @@ -642,8 +674,7 @@ def test_rfr_observation_shift_method(self, curve_type, rfr_curve, line_curve) - end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_observation_shift", - method_param=1, + fixing_method="rfr_observation_shift(1)", fixing_series=FloatRateSeries( calendar="all", lag=0, @@ -661,8 +692,7 @@ def test_rfr_observation_shift_method(self, curve_type, rfr_curve, line_curve) - end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_observation_shift", - method_param=2, + fixing_method="rfr_observation_shift(2)", fixing_series=FloatRateSeries( calendar="all", lag=0, @@ -690,8 +720,7 @@ def test_rfr_observation_shift_method_with_fixings( end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_observation_shift", - method_param=1, + fixing_method="rfr_observation_shift(1)", rate_fixings=name, fixing_series=FloatRateSeries( calendar="all", @@ -710,8 +739,7 @@ def test_rfr_observation_shift_method_with_fixings( end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_observation_shift", - method_param=2, + fixing_method="rfr_observation_shift(2)", rate_fixings=name, fixing_series=FloatRateSeries( calendar="all", @@ -741,8 +769,7 @@ def test_rfr_observation_shift_method_with_fixings_and_float_spread( end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_observation_shift", - method_param=2, + fixing_method="rfr_observation_shift(2)", rate_fixings=name, float_spread=1000.0, fixing_series=FloatRateSeries( @@ -767,8 +794,7 @@ def test_rfr_observation_shift_avg_method(self, curve_type, rfr_curve, line_curv end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_observation_shift_avg", - method_param=1, + fixing_method="rfr_observation_shift_avg(1)", fixing_series=FloatRateSeries( calendar="all", lag=0, @@ -786,8 +812,7 @@ def test_rfr_observation_shift_avg_method(self, curve_type, rfr_curve, line_curv end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_observation_shift_avg", - method_param=2, + fixing_method="rfr_observation_shift_avg(2)", fixing_series=FloatRateSeries( calendar="all", lag=0, @@ -814,8 +839,7 @@ def test_rfr_observation_shift_avg_method_with_fixings( end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_observation_shift_avg", - method_param=1, + fixing_method="rfr_observation_shift_avg(1)", rate_fixings="123454", fixing_series=FloatRateSeries( calendar="all", @@ -834,8 +858,7 @@ def test_rfr_observation_shift_avg_method_with_fixings( end=dt(2022, 1, 5), payment=dt(2022, 1, 5), frequency=Frequency.Months(3, None), - fixing_method="rfr_observation_shift_avg", - method_param=2, + fixing_method="rfr_observation_shift_avg(2)", rate_fixings="123454", fixing_series=FloatRateSeries( calendar="all", @@ -857,8 +880,7 @@ def test_dcf_obs_period_raises(self) -> None: end=dt(2022, 12, 31), payment=dt(2022, 12, 31), frequency=Frequency.Months(12, None), - fixing_method="rfr_lookback", - method_param=5, + fixing_method="rfr_lookback(5)", fixing_series=FloatRateSeries( calendar="ldn", lag=0, @@ -882,9 +904,9 @@ def test_dcf_obs_period_raises(self) -> None: ("method", "expected", "expected_date"), [ ("rfr_payment_delay", [1000000, 1000082, 1000191, 1000561], dt(2022, 1, 6)), - ("rfr_observation_shift", [1499240, 1499281, 1499363, 1499486], dt(2022, 1, 4)), - ("rfr_lockout", [999931, 4999411, 0, 0], dt(2022, 1, 6)), - ("rfr_lookback", [999657, 999685, 2998726, 999821], dt(2022, 1, 4)), + ("rfr_observation_shift(2)", [1499240, 1499281, 1499363, 1499486], dt(2022, 1, 4)), + ("rfr_lockout(2)", [999931, 4999411, 0, 0], dt(2022, 1, 6)), + ("rfr_lookback(2)", [999657, 999685, 2998726, 999821], dt(2022, 1, 4)), ], ) def test_rfr_fixings_array(self, curve_type, method, expected, expected_date) -> None: @@ -964,9 +986,9 @@ def test_rfr_fixings_array(self, curve_type, method, expected, expected_date) -> ("method", "expected", "expected_date"), [ ("rfr_payment_delay", [0.27393, 0.27392, 0.82155, 0.27391], dt(2022, 1, 6)), - ("rfr_observation_shift", [0.41074, 0.41073, 0.41072, 0.41071], dt(2022, 1, 4)), - ("rfr_lockout", [0.27391, 1.36933, 0, 0], dt(2022, 1, 6)), - ("rfr_lookback", [0.27387, 0.27386, 0.82143, 0.27385], dt(2022, 1, 4)), + ("rfr_observation_shift(2)", [0.41074, 0.41073, 0.41072, 0.41071], dt(2022, 1, 4)), + ("rfr_lockout(2)", [0.27391, 1.36933, 0, 0], dt(2022, 1, 6)), + ("rfr_lookback(2)", [0.27387, 0.27386, 0.82143, 0.27385], dt(2022, 1, 4)), ], ) def test_rfr_fixings_array_substitute( @@ -1036,11 +1058,8 @@ def test_rfr_fixings_array_substitute( table = period.local_analytic_rate_fixings(rate_curve=rfr_curve, disc_curve=curve) assert table.index.tolist()[1] == expected_date - assert np.all( - np.isclose( - np.array(expected), table[(rfr_curve.id, "usd", "usd", "1B")].to_numpy(), atol=1e-4 - ) - ) + result = table[(rfr_curve.id, "usd", "usd", "1B")].to_numpy() + assert np.all(np.isclose(np.array(expected), result, atol=1e-4)) def test_rfr_fixings_array_raises2(self, line_curve, curve) -> None: period = FloatPeriod( @@ -1069,14 +1088,14 @@ def test_rfr_fixings_array_raises2(self, line_curve, curve) -> None: @pytest.mark.skip(reason="NOTIONAL mapping not implemented") @pytest.mark.parametrize( - ("method", "param", "expected"), + ("method", "expected"), [ - ("rfr_payment_delay", 0, 1000000), - ("rfr_observation_shift", 1, 333319), - ("rfr_lookback", 1, 333319), + ("rfr_payment_delay", 1000000), + ("rfr_observation_shift(1)", 333319), + ("rfr_lookback(1)", 333319), ], ) - def test_rfr_fixings_array_single_period(self, method, param, expected) -> None: + def test_rfr_fixings_array_single_period(self, method, expected) -> None: rfr_curve = Curve( nodes={dt(2022, 1, 3): 1.0, dt(2022, 1, 15): 0.9995}, interpolation="log_linear", @@ -1089,7 +1108,6 @@ def test_rfr_fixings_array_single_period(self, method, param, expected) -> None: payment=dt(2022, 1, 11), frequency=Frequency.Months(3, None), fixing_method=method, - method_param=param, notional=-1000000, convention="act365f", fixing_series=FloatRateSeries( @@ -1104,14 +1122,14 @@ def test_rfr_fixings_array_single_period(self, method, param, expected) -> None: assert abs(result[(rfr_curve.id, "notional")].iloc[0] - expected) < 1 @pytest.mark.parametrize( - ("method", "param", "expected"), + ("method", "expected"), [ - ("rfr_payment_delay", 0, 0.27388), - ("rfr_observation_shift", 1, 0.27388), - ("rfr_lookback", 1, 0.27388), + ("rfr_payment_delay", 0.27388), + ("rfr_observation_shift(1)", 0.27388), + ("rfr_lookback(1)", 0.27388), ], ) - def test_rfr_fixings_array_single_period_substitute(self, method, param, expected) -> None: + def test_rfr_fixings_array_single_period_substitute(self, method, expected) -> None: rfr_curve = Curve( nodes={dt(2022, 1, 3): 1.0, dt(2022, 1, 15): 0.9995}, interpolation="log_linear", @@ -1124,7 +1142,6 @@ def test_rfr_fixings_array_single_period_substitute(self, method, param, expecte payment=dt(2022, 1, 11), frequency=Frequency.Months(3, None), fixing_method=method, - method_param=param, notional=-1000000, convention="act365f", fixing_series=FloatRateSeries( @@ -1139,43 +1156,41 @@ def test_rfr_fixings_array_single_period_substitute(self, method, param, expecte assert abs(result[(rfr_curve.id, "usd", "usd", "1B")].iloc[0] - expected) < 1 @pytest.mark.parametrize( - ("method", "param", "expected", "index"), + ("method", "expected", "index"), [ ( "rfr_payment_delay", - 0, 3.20040557, [dt(2022, 1, 28), dt(2022, 1, 31), dt(2022, 2, 1)], ), - ("rfr_lockout", 1, 3.80063892, [dt(2022, 1, 28), dt(2022, 1, 31), dt(2022, 2, 1)]), - ("rfr_lookback", 1, 3.20040557, [dt(2022, 1, 27), dt(2022, 1, 28), dt(2022, 1, 31)]), + ("rfr_lockout(1)", 3.80063892, [dt(2022, 1, 28), dt(2022, 1, 31), dt(2022, 2, 1)]), + ("rfr_lookback(1)", 3.20040557, [dt(2022, 1, 27), dt(2022, 1, 28), dt(2022, 1, 31)]), ( - "rfr_observation_shift", - 1, + "rfr_observation_shift(1)", 4.00045001, [dt(2022, 1, 27), dt(2022, 1, 28), dt(2022, 1, 31)], ), ], ) - def test_rfr_period_all_types_with_defined_fixings(self, method, param, expected, index): + def test_rfr_period_all_types_with_defined_fixings(self, method, expected, index): # This is probably a redundant test but it came later after some refactoring and # was double checked with manual calculation in Excel. Easy to do. curve = Curve({dt(2022, 1, 1): 1.0, dt(2022, 3, 1): 1.0}, calendar="nyc") - fixings.add("887654_1B", Series(data=[3.0, 5.0, 2.0], index=index)) + name = str(hash(os.urandom(2))) + fixings.add(f"{name}_1B", Series(data=[3.0, 5.0, 2.0], index=index)) period = FloatPeriod( start=dt(2022, 1, 28), end=dt(2022, 2, 2), frequency=Frequency.Months(12, None), payment=dt(2022, 1, 1), fixing_method=method, - method_param=param, convention="act360", calendar="nyc", - rate_fixings="887654", + rate_fixings=name, ) result = period.rate(curve) assert abs(result - expected) < 1e-8 - fixings.pop("887654_1B") + fixings.pop(f"{name}_1B") @pytest.mark.parametrize( ("method", "expected"), @@ -1211,8 +1226,7 @@ def test_ibor_rate_line_curve(self, line_curve) -> None: end=dt(2022, 4, 5), payment=dt(2022, 4, 5), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", fixing_series=FloatRateSeries( lag=2, calendar="all", @@ -1231,8 +1245,7 @@ def test_ibor_fixing_table(self, line_curve, curve) -> None: end=dt(2022, 4, 4), payment=dt(2022, 4, 4), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", convention="act365f", fixing_series=FloatRateSeries( calendar="all", @@ -1270,8 +1283,7 @@ def test_ibor_fixing_table_substitute(self, line_curve, curve) -> None: end=dt(2022, 4, 4), payment=dt(2022, 4, 4), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", convention="act365f", fixing_series=FloatRateSeries( calendar="all", @@ -1291,8 +1303,7 @@ def test_ibor_fixing_table_right(self, line_curve, curve) -> None: end=dt(2022, 4, 4), payment=dt(2022, 4, 4), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", convention="act365f", fixing_series=FloatRateSeries( calendar="all", @@ -1370,8 +1381,7 @@ def test_ibor_fixings(self) -> None: end=dt(2023, 6, 6), payment=dt(2023, 6, 6), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", rate_fixings="TEST_VALUES", fixing_series=FloatRateSeries( calendar="bus", @@ -1395,8 +1405,7 @@ def test_ibor_fixings_table_historical_before_curve(self) -> None: end=dt(2000, 5, 2), payment=dt(2000, 5, 2), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=0, + fixing_method="ibor(0)", fixing_series=FloatRateSeries( calendar="bus", convention="act360", @@ -1429,8 +1438,7 @@ def test_ibor_fixings_table_historical_before_curve_substitute(self) -> None: end=dt(2000, 5, 2), payment=dt(2000, 5, 2), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=0, + fixing_method="ibor(0)", fixing_series=FloatRateSeries( calendar="bus", convention="act360", @@ -1461,7 +1469,6 @@ def test_rfr_fixings_table_historical_before_curve(self) -> None: payment=dt(2022, 1, 4), frequency=Frequency.Months(3, None), fixing_method="rfr_payment_delay", - method_param=0, fixing_series=FloatRateSeries( calendar="bus", convention="act360", @@ -1482,7 +1489,6 @@ def test_rfr_fixings_table_historical_before_curve(self) -> None: payment=dt(2022, 1, 4), frequency=Frequency.Months(3, None), fixing_method="rfr_payment_delay", - method_param=0, fixing_series=FloatRateSeries( calendar="bus", convention="act360", @@ -1507,7 +1513,6 @@ def test_rfr_fixings_table_historical_before_curve_substitute(self) -> None: payment=dt(2022, 1, 4), frequency=Frequency.Months(3, None), fixing_method="rfr_payment_delay", - method_param=0, fixing_series=FloatRateSeries( calendar="bus", convention="act360", @@ -1528,7 +1533,6 @@ def test_rfr_fixings_table_historical_before_curve_substitute(self) -> None: payment=dt(2022, 1, 4), frequency=Frequency.Months(3, None), fixing_method="rfr_payment_delay", - method_param=0, fixing_series=FloatRateSeries( calendar="bus", convention="act360", @@ -1554,8 +1558,7 @@ def test_ibor_fixing_unavailable(self) -> None: end=dt(2023, 6, 20), payment=dt(2023, 6, 20), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", calendar="bus", rate_fixings=name, ) @@ -1572,8 +1575,7 @@ def test_ibor_fixings_exposure_with_fixing(self) -> None: end=dt(2023, 6, 20), payment=dt(2023, 6, 20), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", calendar="bus", rate_fixings=2.0, ) @@ -1587,12 +1589,12 @@ def test_ibor_rate_df_curve(self, float_spread, curve) -> None: end=dt(2022, 7, 1), payment=dt(2022, 7, 1), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", float_spread=float_spread, ) expected = (0.99 / 0.98 - 1) * 36000 / 91 + float_spread / 100 - assert period.rate(curve) == expected + result = period.rate(curve) + assert result == expected @pytest.mark.parametrize("float_spread", [0, 100]) def test_ibor_rate_stub_df_curve(self, float_spread, curve) -> None: @@ -1601,8 +1603,7 @@ def test_ibor_rate_stub_df_curve(self, float_spread, curve) -> None: end=dt(2022, 5, 1), payment=dt(2022, 5, 1), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", stub=True, float_spread=float_spread, ) @@ -1615,8 +1616,7 @@ def test_single_fixing_override(self, curve) -> None: end=dt(2022, 5, 1), payment=dt(2022, 5, 1), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", stub=True, float_spread=100, rate_fixings=7.5, @@ -2151,21 +2151,20 @@ def test_method_param_raises(self) -> None: end=dt(2022, 4, 4), payment=dt(2022, 4, 4), frequency=Frequency.Months(3, None), - fixing_method="rfr_lockout", - method_param=0, + fixing_method="rfr_lockout(0)", rate_fixings=[1.00], ) - with pytest.raises(ValueError, match="`method_param` should not be used"): - FloatPeriod( - start=dt(2022, 1, 4), - end=dt(2022, 4, 4), - payment=dt(2022, 4, 4), - frequency=Frequency.Months(3, None), - fixing_method="rfr_payment_delay", - method_param=2, - rate_fixings=[1.00], - ) + # test obsolete with FloatFixingMethod enum + # with pytest.raises(ValueError, match="`method_param` should not be used"): + # FloatPeriod( + # start=dt(2022, 1, 4), + # end=dt(2022, 4, 4), + # payment=dt(2022, 4, 4), + # frequency=Frequency.Months(3, None), + # fixing_method="rfr_payment_delay", + # rate_fixings=[1.00], + # ) def test_analytic_delta_no_curve_raises(self) -> None: name = str(hash(os.urandom(9))) @@ -2231,15 +2230,15 @@ def test_series_fixings_not_applicable_to_period(self) -> None: assert abs(result - expected) < 1e-5 @pytest.mark.parametrize( - ("meth", "param", "exp"), + ("meth", "exp"), [ - ("rfr_payment_delay", NoInput(0), 3.1183733605), - ("rfr_observation_shift", 2, 3.085000395), - ("rfr_lookback", 2, 3.05163645), - ("rfr_lockout", 7, 3.00157855), + ("rfr_payment_delay", 3.1183733605), + ("rfr_observation_shift(2)", 3.085000395), + ("rfr_lookback(2)", 3.05163645), + ("rfr_lockout(7)", 3.00157855), ], ) - def test_norges_bank_nowa_calc_same(self, meth, param, exp) -> None: + def test_norges_bank_nowa_calc_same(self, meth, exp) -> None: # https://app.norges-bank.no/nowa/#/en/ curve = Curve({dt(2023, 8, 4): 1.0}, calendar="osl", convention="act365f") fixings.add("nowa_1B", fixings["nowa"][1]) @@ -2249,7 +2248,6 @@ def test_norges_bank_nowa_calc_same(self, meth, param, exp) -> None: payment=dt(2023, 5, 16), frequency=Frequency.Months(12, None), fixing_method=meth, - method_param=param, float_spread=0.0, rate_fixings="nowa", fixing_series=FloatRateSeries( @@ -2270,8 +2268,7 @@ def test_interpolated_ibor_warns(self) -> None: end=dt(2023, 6, 12), payment=dt(2023, 6, 16), frequency=Frequency.Months(12, None), - fixing_method="ibor", - method_param=1, + fixing_method="ibor(1)", float_spread=0.0, stub=True, ) @@ -2287,8 +2284,7 @@ def test_interpolated_ibor_rate_line(self) -> None: end=dt(2023, 4, 1), payment=dt(2023, 4, 1), frequency=Frequency.Months(12, None), - fixing_method="ibor", - method_param=1, + fixing_method="ibor(1)", float_spread=0.0, stub=True, ) @@ -2306,8 +2302,7 @@ def test_interpolated_ibor_rate_df(self) -> None: end=dt(2023, 4, 1), payment=dt(2023, 4, 1), frequency=Frequency.Months(12, None), - fixing_method="ibor", - method_param=1, + fixing_method="ibor(1)", float_spread=0.0, stub=True, ) @@ -2401,8 +2396,7 @@ def test_ibor_stub_book2_substitute(self): frequency="Q", calendar="tgt", convention="act360", - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", notional=-1e6, stub=True, ) @@ -2419,8 +2413,7 @@ def test_ibor_stub_fixings_table(self) -> None: end=dt(2023, 4, 1), payment=dt(2023, 4, 1), frequency=Frequency.Months(12, None), - fixing_method="ibor", - method_param=1, + fixing_method="ibor(1)", float_spread=0.0, stub=True, fixing_series=FloatRateSeries( @@ -2445,8 +2438,7 @@ def test_ibor_stub_fixings_table_substitute(self) -> None: end=dt(2023, 4, 1), payment=dt(2023, 4, 1), frequency=Frequency.Months(12, None), - fixing_method="ibor", - method_param=1, + fixing_method="ibor(1)", float_spread=0.0, stub=True, fixing_series=FloatRateSeries( @@ -2496,8 +2488,7 @@ def test_ibor_stub_fixings_rfr_in_dict_ignored_substitute(self) -> None: end=dt(2023, 4, 1), payment=dt(2023, 4, 1), frequency=Frequency.Months(12, None), - fixing_method="ibor", - method_param=1, + fixing_method="ibor(1)", float_spread=0.0, stub=True, fixing_series=FloatRateSeries( @@ -2540,8 +2531,7 @@ def test_ibor_non_stub_fixings_table(self) -> None: end=dt(2023, 5, 1), payment=dt(2023, 5, 1), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=1, + fixing_method="ibor(1)", float_spread=0.0, ) curve3 = LineCurve({dt(2022, 1, 1): 3.0, dt(2023, 2, 1): 3.0}) @@ -2568,8 +2558,7 @@ def test_ibor_fixings_no_bad_curves_raises(self): end=dt(2023, 6, 6), payment=dt(2023, 6, 6), frequency=Frequency.Months(3, None), - fixing_method="ibor", - method_param=2, + fixing_method="ibor(2)", fixing_series=FloatRateSeries( calendar="bus", convention="act360", @@ -2597,7 +2586,7 @@ def test_local_historical_pay_date_issue(self, curve) -> None: @pytest.mark.parametrize( "curve", [NoInput(0), LineCurve({dt(2000, 1, 1): 2.0, dt(2001, 1, 1): 2.0})] ) - @pytest.mark.parametrize("fixing_method", ["ibor", "rfr_payment_delay_avg"]) + @pytest.mark.parametrize("fixing_method", ["ibor(2)", "rfr_payment_delay_avg"]) @pytest.mark.parametrize("fixings", [3.0, NoInput(0)]) def test_rate_optional_curve(self, fixings, fixing_method, curve) -> None: # GH530. Allow forecasting rates without necessarily providing curve if unnecessary @@ -2609,13 +2598,19 @@ def test_rate_optional_curve(self, fixings, fixing_method, curve) -> None: rate_fixings=fixings, payment=dt(2000, 4, 12), ) - if isinstance(curve, NoInput) and isinstance(fixings, NoInput) and fixing_method != "ibor": + if ( + isinstance(curve, NoInput) + and isinstance(fixings, NoInput) + and fixing_method != "ibor(2)" + ): # then no data to price msg = "A `rate_curve` is required to forecast missing RFR" with pytest.raises(FixingMissingForecasterError, match=msg): period.rate(curve) elif ( - isinstance(curve, NoInput) and isinstance(fixings, NoInput) and fixing_method == "ibor" + isinstance(curve, NoInput) + and isinstance(fixings, NoInput) + and fixing_method == "ibor(2)" ): msg = "A `rate_curve` is required to forecast missing IBOR" with pytest.raises(ValueError, match=msg): @@ -2697,8 +2692,7 @@ def test_rfr_lockout_calculation_is_accurate(self): end=dt(2024, 6, 20), payment=dt(2024, 6, 21), frequency="A", - fixing_method=FloatFixingMethod.RFRLockout, - method_param=4, + fixing_method=FloatFixingMethod.RFRLockout(4), fixing_series=FloatRateSeries( calendar="bus", convention="act360", lag=0, eom=False, modifier="F" ), @@ -2731,8 +2725,7 @@ def test_analytic_delta_raises(self, curve): end=dt(2024, 6, 20), payment=dt(2024, 6, 21), frequency="A", - fixing_method=FloatFixingMethod.RFRLockout, - method_param=4, + fixing_method=FloatFixingMethod.RFRLockout(4), fixing_series=FloatRateSeries( calendar="bus", convention="act360", lag=0, eom=False, modifier="F" ), @@ -2743,6 +2736,19 @@ def test_analytic_delta_raises(self, curve): rate_curve=NoInput(0), disc_curve=curve ).is_err + def test_ibor_param_mismatch(self): + with pytest.raises( + ValueError, match="A `fixing_series` has been provided with a publication `lag` that" + ): + FloatPeriod( + start=dt(2000, 1, 1), + end=dt(2000, 4, 1), + payment=dt(2000, 4, 1), + fixing_method="ibor(1)", + fixing_series="eur_ibor", + frequency="Q", + ) + class TestFixedPeriod: def test_frequency_as_str(self): @@ -3211,7 +3217,7 @@ def test_period_npv(self, hazard_curve, curve, fxr) -> None: end=dt(2022, 4, 1), payment=dt(2022, 4, 3), notional=1e9, - convention="Act360", + # convention="Act360", termination=dt(2022, 4, 1), frequency=Frequency.Months(3, None), currency="usd", @@ -3237,7 +3243,7 @@ def test_period_npv_raises(self, curve, hazard_curve) -> None: end=dt(2022, 4, 1), payment=dt(2022, 4, 3), notional=1e9, - convention="Act360", + # convention="Act360", termination=dt(2022, 4, 1), frequency=Frequency.Months(3, None), currency="usd", @@ -3259,7 +3265,7 @@ def test_period_analytic_delta(self, hazard_curve, curve, fxr) -> None: end=dt(2022, 4, 1), payment=dt(2022, 4, 3), notional=1e9, - convention="Act360", + # convention="Act360", termination=dt(2022, 4, 1), frequency=Frequency.Months(3, None), currency="usd", @@ -3278,7 +3284,7 @@ def test_period_analytic_delta_fxr_base(self, hazard_curve, curve, fxr) -> None: end=dt(2022, 4, 1), payment=dt(2022, 4, 3), notional=1e9, - convention="Act360", + # convention="Act360", termination=dt(2022, 4, 1), frequency=Frequency.Months(3, None), currency="usd", @@ -3294,7 +3300,7 @@ def test_period_cashflows(self, hazard_curve, curve, fxr) -> None: end=dt(2022, 4, 1), payment=dt(2022, 4, 3), notional=1e9, - convention="Act360", + # convention="Act360", termination=dt(2022, 4, 1), frequency=Frequency.Months(3, None), currency="usd", @@ -3309,7 +3315,7 @@ def test_period_cashflows(self, hazard_curve, curve, fxr) -> None: defaults.headers["payment"]: dt(2022, 4, 3), defaults.headers["notional"]: 1e9, defaults.headers["currency"]: "USD", - defaults.headers["convention"]: "Act360", + defaults.headers["convention"]: "One", defaults.headers["dcf"]: period.period_params.dcf, defaults.headers["df"]: 0.9897791268897856, defaults.headers["recovery"]: 0.4, @@ -3333,7 +3339,7 @@ def test_period_cashflows_no_curves(self, fxr) -> None: end=dt(2022, 4, 1), payment=dt(2022, 4, 3), notional=1e9, - convention="Act360", + # convention="Act360", termination=dt(2022, 4, 1), frequency=Frequency.Months(3, None), currency="usd", @@ -3348,7 +3354,7 @@ def test_period_cashflows_no_curves(self, fxr) -> None: defaults.headers["payment"]: dt(2022, 4, 3), defaults.headers["notional"]: 1e9, defaults.headers["currency"]: "USD", - defaults.headers["convention"]: "Act360", + defaults.headers["convention"]: "One", defaults.headers["dcf"]: period.period_params.dcf, defaults.headers["df"]: None, defaults.headers["recovery"]: None, diff --git a/python/tests/scheduling/test_calendars.py b/python/tests/scheduling/test_calendars.py index fbd65dc68..6e2729ee1 100644 --- a/python/tests/scheduling/test_calendars.py +++ b/python/tests/scheduling/test_calendars.py @@ -12,7 +12,7 @@ from datetime import datetime as dt import pytest -from rateslib import defaults, fixings +from rateslib import calendars, defaults, fixings from rateslib.curves import Curve from rateslib.default import NoInput from rateslib.instruments import IRS @@ -29,7 +29,11 @@ get_imm, next_imm, ) -from rateslib.scheduling.calendars import _adjust_date, _get_years_and_months, _is_day_type_tenor +from rateslib.scheduling.calendars import ( + _adjust_date, + _get_years_and_months, + _is_day_type_tenor, +) from rateslib.scheduling.frequency import _get_frequency, _get_fx_expiry_and_delivery_and_payment @@ -566,15 +570,66 @@ def test_pipe_vectors() -> None: def test_pipe_raises() -> None: - with pytest.raises(ValueError, match="Cannot use more than one pipe"): + with pytest.raises( + ValueError, match="The calendar cannot be parsed. Is there more than one pipe character?" + ): get_calendar("tgt|nyc|stk") def test_add_and_get_custom_calendar() -> None: cal = Cal([dt(2023, 1, 2)], [5, 6]) - defaults.calendars["custom"] = cal + calendars.add("custom", cal) result = get_calendar("custom") assert result == cal + calendars.pop("custom") + + +def test_add_and_get_custom_calendar_combination() -> None: + cal = Cal([dt(2023, 1, 2)], [5, 6]) + cal2 = Cal([dt(2023, 1, 3)], [1, 2, 5, 6]) + calendars.add("custom", cal) + calendars.add("custom2", cal2) + result = get_calendar("custom,custom2") + assert result == UnionCal([cal, cal2], []) + calendars.pop("custom") + calendars.pop("custom2") + + +def test_calendar_pop_all_combinations() -> None: + cal = Cal([dt(2023, 1, 2)], [5, 6]) + cal2 = Cal([dt(2023, 1, 3)], [1, 2, 5, 6]) + cal3 = Cal([dt(2023, 1, 3)], [1, 2, 4, 6]) + calendars.add("custom1", cal) + calendars.add("custom2", cal2) + calendars.add("custom3", cal3) + _ = get_calendar("custom1,custom2") + _ = get_calendar("custom1,custom3") + _ = get_calendar("custom2,custom3") + calendars.pop("custom1") + + assert "custom1,custom2" not in calendars + assert "custom1,custom3" not in calendars + assert "custom2,custom3" in calendars + calendars.pop("custom2") + calendars.pop("custom3") + + +def test_doc_union_cal() -> None: + calendars.add("mondays-off", Cal([], [0, 5, 6])) + calendars.add("fridays-off", Cal([], [4, 5, 6])) + result = get_calendar("mondays-off, fridays-off").print(2026, 1) + expected = """ January 2026 +Su Mo Tu We Th Fr Sa + 1 * . + . * 6 7 8 * . + . * 13 14 15 * . + . * 20 21 22 * . + . * 27 28 29 * . + +""" # noqa: W293 + assert result == expected + calendars.pop("mondays-off") + calendars.pop("fridays-off") @pytest.mark.parametrize( @@ -633,12 +688,6 @@ def test_is_not_day_type_tenor(tenor): assert not _is_day_type_tenor(tenor) -def test_get_calendar_from_defaults() -> None: - defaults.calendars["custom"] = "my_object" - assert get_calendar("custom") == "my_object" - defaults.calendars.pop("custom") - - @pytest.mark.parametrize( ("start", "method", "expected"), [ @@ -720,7 +769,103 @@ def test_mex_loads(): assert cal.is_bus_day(dt(2026, 3, 17)) +def test_bjs_loads(): + cal = get_calendar("bjs") + assert not cal.is_bus_day(dt(2026, 9, 19)) + assert cal.is_bus_day(dt(2026, 9, 20)) + + def test_replace_whitespace(): cal1 = get_calendar("nyc, tgt") cal2 = get_calendar("nyc,tgt") assert cal1 == cal2 + + +def test_print_month(): + cal = get_calendar("nyc,tgt") + output = cal.print(2026, 1) + assert ( + output + == r""" January 2026 +Su Mo Tu We Th Fr Sa + * 2 . + . 5 6 7 8 9 . + . 12 13 14 15 16 . + . * 20 21 22 23 . + . 26 27 28 29 30 . + +""" # noqa: W291, W293 + ) + + +def test_print_calendar(): + cal = get_calendar("bjs") + output = cal.print(2026) + expected = """ + January 2026 April 2026 July 2026 October 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + * * . 1 2 3 . 1 2 3 . * * . + 4 5 6 7 8 9 . . * 7 8 9 10 . . 6 7 8 9 10 . . * * * 8 9 10 + . 12 13 14 15 16 . . 13 14 15 16 17 . . 13 14 15 16 17 . . 12 13 14 15 16 . + . 19 20 21 22 23 . . 20 21 22 23 24 . . 20 21 22 23 24 . . 19 20 21 22 23 . + . 26 27 28 29 30 . . 27 28 29 30 . 27 28 29 30 31 . 26 27 28 29 30 . + + February 2026 May 2026 August 2026 November 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + . 2 3 4 5 6 . * . . . 2 3 4 5 6 . + . 9 10 11 12 13 14 . * * 6 7 8 9 . 3 4 5 6 7 . . 9 10 11 12 13 . + . * * * * * . . 11 12 13 14 15 . . 10 11 12 13 14 . . 16 17 18 19 20 . + . * 24 25 26 27 28 . 18 19 20 21 22 . . 17 18 19 20 21 . . 23 24 25 26 27 . + . 25 26 27 28 29 . . 24 25 26 27 28 . . 30 + . . 31 + March 2026 June 2026 September 2026 December 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + . 2 3 4 5 6 . 1 2 3 4 5 . 1 2 3 4 . 1 2 3 4 . + . 9 10 11 12 13 . . 8 9 10 11 12 . . 7 8 9 10 11 . . 7 8 9 10 11 . + . 16 17 18 19 20 . . 15 16 17 18 * . . 14 15 16 17 18 . . 14 15 16 17 18 . + . 23 24 25 26 27 . . 22 23 24 25 26 . 20 21 22 23 24 * . . 21 22 23 24 25 . + . 30 31 . 29 30 . 28 29 30 . 28 29 30 31 + +Legend: +'1-31': Settleable business day 'X': Non-settleable business day + '.': Non-business weekend '*': Non-business day +""" # noqa: W291, W293 + assert output == expected + + +def test_print_compare_calendar(): + cal = get_calendar("nyc") + cal2 = get_calendar("fed") + output = cal.print_compare(cal2, 2026) + expected = """ + January 2026 April 2026 July 2026 October 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + _ _ _ _ _ [] _ _ _ [] _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + + February 2026 May 2026 August 2026 November 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ + March 2026 June 2026 September 2026 December 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +""" # noqa: W291, W293 + assert output == expected + + +def test_union_cal_try_from_name(): + uc = UnionCal.from_name("ldn,tgt|fed") + assert isinstance(uc, UnionCal) diff --git a/python/tests/scheduling/test_calendarsrs.py b/python/tests/scheduling/test_calendarsrs.py index b95013a76..0e6611a37 100644 --- a/python/tests/scheduling/test_calendarsrs.py +++ b/python/tests/scheduling/test_calendarsrs.py @@ -14,7 +14,7 @@ import pytest from pandas import Index from rateslib import fixings -from rateslib.rs import Adjuster, Cal, Modifier, NamedCal, RollDay, UnionCal +from rateslib.rs import Adjuster, Cal, CalendarManager, Modifier, NamedCal, RollDay, UnionCal from rateslib.scheduling import get_calendar from rateslib.serialization import from_json @@ -222,13 +222,13 @@ def test_equality(self, left, right, expected) -> None: def test_attributes(self) -> None: ncal = get_calendar("tgt,LDN|Fed") - assert ncal.name == "tgt,ldn|fed" - assert isinstance(ncal.union_cal, UnionCal) - assert len(ncal.union_cal.calendars) == 2 - assert len(ncal.union_cal.settlement_calendars) == 1 + assert ncal.name == "ldn,tgt|fed" + assert isinstance(ncal.inner, UnionCal) + assert len(ncal.inner.calendars) == 2 + assert len(ncal.inner.settlement_calendars) == 1 ncal = get_calendar("tgt") - assert ncal.union_cal.settlement_calendars is None + assert isinstance(ncal.inner, Cal) def test_adjusts(self, simple_cal): dates = [dt(2015, 9, 4), dt(2015, 9, 5), dt(2015, 9, 6), dt(2015, 9, 7)] @@ -259,12 +259,12 @@ def test_roll(self, simple_union): class TestNamedCal: def test_equality_named_cal(self) -> None: - cal = get_calendar("fed", named=False) + cal = Cal.from_name("fed") ncal = NamedCal("fed") assert cal == ncal assert ncal == cal - ucal = get_calendar("ldn,tgt|fed", named=False) + ucal = UnionCal.from_name("ldn,tgt|fed") ncal = NamedCal("ldn,tgt|fed") assert ucal == ncal assert ncal == ucal @@ -324,3 +324,37 @@ def test_adjusts(self, simple_cal): result = Adjuster.Following().adjusts(dates, simple_cal) expected = [dt(2015, 9, 4), dt(2015, 9, 8), dt(2015, 9, 8), dt(2015, 9, 8)] assert result == expected + + +class TestCalendarManager: + def test_add_and_pop(self): + c = CalendarManager() + c.add("mycalendar", Cal([], [2])) + nc = c.get("mycalendar") + assert isinstance(nc, NamedCal) + assert nc == Cal([], [2]) + pop = c.pop("mycalendar") + assert pop == Cal([], [2]) + assert isinstance(pop, Cal) + with pytest.raises(KeyError): + c.get("mycalendar") + + def test_add_union_cal_raises(self): + c = CalendarManager() + with pytest.raises(TypeError, match="argument 'calendar': 'UnionCal' object is not"): + c.add("mycalendar", UnionCal([Cal([], [])], None)) + + def test_add_and_get_composition(self): + c = CalendarManager() + x = c.get("ldn,tgt") + y = c.get("tgt,ldn") + assert x == y + assert x.inner_ptr_eq(y) + + def test_get_raises(self): + c = CalendarManager() + with pytest.raises(KeyError, match="`name` does not exist in calendars."): + c.get("bad_calendar") + + with pytest.raises(KeyError, match="`name` does not exist in calendars."): + c.get("ldn,bad_calendar") diff --git a/python/tests/scheduling/test_imm.py b/python/tests/scheduling/test_imm.py index c8bf871ce..170a2a87a 100644 --- a/python/tests/scheduling/test_imm.py +++ b/python/tests/scheduling/test_imm.py @@ -13,6 +13,7 @@ import pytest from rateslib.rs import Imm +from rateslib.scheduling import get_imm @pytest.mark.parametrize( @@ -65,3 +66,8 @@ def test_get_imm_namespace(): def test_get_eom(month, year, expected) -> None: result = Imm.Eom.get(year, month) assert result == expected + + +def test_get_som() -> None: + assert Imm.Som.get(2000, 3) == dt(2000, 3, 1) + assert get_imm(code="H25", definition="som") == dt(2025, 3, 1) diff --git a/python/tests/scheduling/test_schedule.py b/python/tests/scheduling/test_schedule.py index 20a573817..cbf9673e4 100644 --- a/python/tests/scheduling/test_schedule.py +++ b/python/tests/scheduling/test_schedule.py @@ -297,18 +297,90 @@ def test_schedule_raises(cal_) -> None: @pytest.mark.parametrize( ("eff", "term", "f", "roll"), [ - (dt(2022, 3, 16), dt(2024, 9, 10), "Q", "imm"), # non-imm term - (dt(2022, 3, 31), dt(2023, 3, 30), "A", "eom"), # non-eom term - (dt(2022, 3, 1), dt(2023, 3, 2), "A", "som"), # non-som term - (dt(2022, 2, 20), dt(2025, 8, 21), "S", 20), # roll - (dt(2022, 2, 28), dt(2024, 2, 28), "S", 30), # is leap + ( + dt(2022, 3, 16), + dt(2024, 9, 10), + "Q", + "imm", + ), # cannot build because termination does not align with IMM and no back stub specified. + ( + dt(2022, 3, 1), + dt(2023, 3, 2), + "A", + "som", + ), # fails because roll is explicit and a short stub to 1st march 2022 this does not align. + ( + dt(2022, 2, 20), + dt(2025, 8, 21), + "S", + 20, + ), # fails because a short stub cannot be generated aligned with specified roll. + ( + dt(2022, 2, 28), + dt(2024, 2, 28), + "S", + 30, + ), # is leap year 2024 and front stub is specified so 28th Feb '24 does not align with roll ], ) def test_unadjusted_regular_swap_dead_stubs(eff, term, f, roll) -> None: + # this test isn't really about dead stubs more about misalignment with rolls. with pytest.raises(ValueError, match="A Schedule could not be generated from the parameter c"): + # the default `stub` is SHORTFRONT Schedule(eff, term, f, eom=False, roll=roll) +@pytest.mark.parametrize( + ("eff", "term", "f", "roll", "stub"), + [ + ( + dt(2022, 3, 31), + dt(2023, 3, 30), + "A", + "eom", + "shortfront", + ), # this builds because it is a single period short stub. + ( + dt(2022, 3, 1), + dt(2023, 3, 2), + "A", + "som", + "shortback", + ), # corrects the above test issue by specifying a back stub. + ( + dt(2022, 2, 20), + dt(2025, 8, 21), + "S", + 20, + "longback", + ), # corrects to provide a single period stub + ( + dt(2022, 2, 20), + dt(2025, 8, 21), + "S", + 20, + "shortback", + ), # corrects to provide a shoprt back stub with regular rolling on 20th + ( + dt(2022, 2, 28), + dt(2024, 2, 28), + "S", + 30, + "shortback", + ), # corrects the above to specify a back stub + ( + dt(2022, 2, 28), + dt(2024, 2, 28), + "S", + 30, + "longback", + ), # or alternatively with a long back stub + ], +) +def test_unadjusted_regular_swap_dead_stubs_corrections(eff, term, f, roll, stub) -> None: + Schedule(eff, term, f, eom=False, roll=roll, stub=stub) + + @pytest.mark.parametrize( ("eff", "term", "f", "roll", "exp"), [ @@ -334,31 +406,45 @@ def test_unadjusted_regular_swap(eff, term, f, roll, exp) -> None: # 12th and 13th of Feb and March are Saturday and Sunday @pytest.mark.parametrize( - ("eff", "term", "roll", "e_bool", "e_ueff", "e_uterm", "e_roll"), + ("eff", "term", "roll", "e_ueff", "e_uterm", "e_roll"), [ - (dt(2022, 2, 11), dt(2022, 3, 11), 11, True, dt(2022, 2, 11), dt(2022, 3, 11), 11), - (dt(2022, 2, 14), dt(2022, 3, 14), 14, True, dt(2022, 2, 14), dt(2022, 3, 14), 14), - (dt(2022, 2, 14), dt(2022, 3, 14), NoInput(0), True, dt(2022, 2, 14), dt(2022, 3, 14), 14), - (dt(2022, 2, 13), dt(2022, 3, 14), NoInput(0), True, dt(2022, 2, 13), dt(2022, 3, 13), 13), - (dt(2022, 2, 12), dt(2022, 3, 14), NoInput(0), True, dt(2022, 2, 12), dt(2022, 3, 12), 12), - (dt(2022, 2, 12), dt(2022, 3, 13), NoInput(0), False, None, None, None), - (dt(2022, 2, 14), dt(2022, 3, 12), NoInput(0), True, dt(2022, 2, 12), dt(2022, 3, 12), 12), - (dt(2022, 2, 14), dt(2022, 3, 14), 12, True, dt(2022, 2, 12), dt(2022, 3, 12), 12), - (dt(2022, 2, 14), dt(2022, 3, 14), 11, False, None, None, None), - (dt(2022, 2, 28), dt(2022, 3, 31), NoInput(0), True, dt(2022, 2, 28), dt(2022, 3, 31), 31), - (dt(2022, 2, 28), dt(2022, 3, 31), 28, False, None, None, None), - (dt(2022, 2, 28), dt(2022, 3, 31), "eom", True, dt(2022, 2, 28), dt(2022, 3, 31), 31), + (dt(2022, 2, 11), dt(2022, 3, 11), 11, dt(2022, 2, 11), dt(2022, 3, 11), 11), + (dt(2022, 2, 14), dt(2022, 3, 14), 14, dt(2022, 2, 14), dt(2022, 3, 14), 14), + (dt(2022, 2, 14), dt(2022, 3, 14), NoInput(0), dt(2022, 2, 14), dt(2022, 3, 14), 14), + (dt(2022, 2, 13), dt(2022, 3, 14), NoInput(0), dt(2022, 2, 13), dt(2022, 3, 13), 13), + (dt(2022, 2, 12), dt(2022, 3, 14), NoInput(0), dt(2022, 2, 12), dt(2022, 3, 12), 12), + (dt(2022, 2, 14), dt(2022, 3, 12), NoInput(0), dt(2022, 2, 12), dt(2022, 3, 12), 12), + (dt(2022, 2, 14), dt(2022, 3, 14), 12, dt(2022, 2, 12), dt(2022, 3, 12), 12), + (dt(2022, 2, 28), dt(2022, 3, 31), NoInput(0), dt(2022, 2, 28), dt(2022, 3, 31), 31), + (dt(2022, 2, 28), dt(2022, 3, 31), "eom", dt(2022, 2, 28), dt(2022, 3, 31), 31), + ( + dt(2022, 2, 12), + dt(2022, 3, 13), + NoInput(0), + dt(2022, 2, 12), + dt(2022, 3, 13), + 13, + ), # dead stub converts to long stub ], ) -def test_check_regular_swap_mf(eff, term, roll, e_bool, e_ueff, e_uterm, e_roll, cal_) -> None: - try: - result = Schedule(eff, term, "M", modifier="MF", eom=False, roll=roll, calendar=cal_) - except ValueError: - assert not e_bool - else: - assert result.ueffective == e_ueff - assert result.utermination == e_uterm - assert result.roll == e_roll +def test_check_regular_swap_mf(eff, term, roll, e_ueff, e_uterm, e_roll, cal_) -> None: + result = Schedule(eff, term, "M", modifier="MF", eom=False, roll=roll, calendar=cal_) + assert result.ueffective == e_ueff + assert result.utermination == e_uterm + assert result.roll == e_roll + + +# 12th and 13th of Feb and March are Saturday and Sunday +@pytest.mark.parametrize( + ("eff", "term", "roll"), + [ + (dt(2022, 2, 14), dt(2022, 3, 14), 11), # fails due to roll misalignment + (dt(2022, 2, 28), dt(2022, 3, 31), 28), # fails due to wrong stub side + ], +) +def test_check_regular_swap_mf_failures(eff, term, roll, cal_) -> None: + with pytest.raises(ValueError): + Schedule(eff, term, "M", modifier="MF", eom=False, roll=roll, calendar=cal_) @pytest.mark.parametrize( @@ -970,3 +1056,19 @@ def test_single_period_from_str_matching_frequency(tenor): # When the frequency matches the tenor it should generate only a single period. s = Schedule(effective=dt(2025, 1, 15), termination=tenor, frequency=tenor) assert s.n_periods == 1 + + +@pytest.mark.parametrize("stub", ["shortfront", "shortback"]) +def test_dead_stub_failures(stub) -> None: + # this test attempts to build a schedule from unadjusted saturday to unadjusted sunday + # using a 7d frequency. This converts the dead short stub to a long stub and thereby + # defines only one period. + s = Schedule( + effective=dt(2026, 1, 3), # saturday + termination=dt(2026, 1, 11), # sunday + frequency="7d", + calendar="bus", + modifier="f", + stub=stub, + ) + assert s.uschedule == [dt(2026, 1, 3), dt(2026, 1, 11)] diff --git a/python/tests/scheduling/test_schedulers.py b/python/tests/scheduling/test_schedulers.py index b2f92b37d..f27f7a5c8 100644 --- a/python/tests/scheduling/test_schedulers.py +++ b/python/tests/scheduling/test_schedulers.py @@ -19,7 +19,12 @@ @pytest.mark.parametrize( ("ueff", "uterm", "si", "exp"), [ - (dt(2000, 1, 1), dt(2000, 7, 1), None, [dt(2000, 1, 1), dt(2000, 4, 1), dt(2000, 7, 1)]), + ( + dt(2000, 1, 1), + dt(2000, 7, 1), + StubInference.NeitherSide, + [dt(2000, 1, 1), dt(2000, 4, 1), dt(2000, 7, 1)], + ), ( dt(2000, 1, 1), dt(2000, 8, 1), @@ -76,7 +81,7 @@ def test_imm_schedule(): eom=True, front_stub=None, back_stub=None, - stub_inference=None, + stub_inference=StubInference.NeitherSide, ) assert s.frequency == Frequency.Months(3, RollDay.IMM()) @@ -93,7 +98,7 @@ def test_single_period_schedule(): eom=True, front_stub=None, back_stub=None, - stub_inference=None, + stub_inference=StubInference.NeitherSide, ) assert s.uschedule == [dt(2025, 3, 19), dt(2025, 9, 19)] diff --git a/python/tests/serialization/test_json.py b/python/tests/serialization/test_json.py index b83e0b9a8..7268b0c68 100644 --- a/python/tests/serialization/test_json.py +++ b/python/tests/serialization/test_json.py @@ -11,6 +11,7 @@ import pytest from rateslib import Curve, Dual, Dual2, FXForwards, FXRates, dt, from_json +from rateslib.enums import FloatFixingMethod, LegIndexBase from rateslib.rs import Schedule as ScheduleRs from rateslib.scheduling import ( Adjuster, @@ -55,7 +56,7 @@ front_stub=None, back_stub=None, eom=False, - stub_inference=None, + stub_inference=StubInference.NeitherSide, ), Schedule( effective=dt(2000, 1, 1), @@ -72,6 +73,17 @@ [0, 0, 0, 1, 1, 1], [Dual2(0.1, [], [], []), Dual2(0.2, [], [], []), Dual2(0.3, [], [], [])], ), + FloatFixingMethod.RFRPaymentDelay(), + FloatFixingMethod.RFRPaymentDelayAverage(), + FloatFixingMethod.RFRObservationShift(2), + FloatFixingMethod.RFRObservationShiftAverage(2), + FloatFixingMethod.RFRLookback(3), + FloatFixingMethod.RFRLookbackAverage(3), + FloatFixingMethod.RFRLockout(4), + FloatFixingMethod.RFRLockoutAverage(4), + FloatFixingMethod.IBOR(2), + LegIndexBase.Initial, + LegIndexBase.PeriodOnPeriod, ], ) def test_json_round_trip(obj) -> None: diff --git a/python/tests/serialization/test_pickle.py b/python/tests/serialization/test_pickle.py index 9f42ce96f..7bc7f2e13 100644 --- a/python/tests/serialization/test_pickle.py +++ b/python/tests/serialization/test_pickle.py @@ -31,6 +31,7 @@ MultiCsaCurve, ProxyCurve, ) +from rateslib.enums import FloatFixingMethod, LegIndexBase from rateslib.rs import Schedule as ScheduleRs from rateslib.scheduling import ( Adjuster, @@ -120,6 +121,15 @@ payment_lag=Adjuster.BusDaysLagSettle(2), stub=StubInference.ShortBack, ), + Schedule( + effective=dt(2000, 1, 1), + termination=dt(2001, 1, 1), + frequency=Frequency.Months(6, RollDay.Day(1)), + calendar=NamedCal("tgt"), + modifier=Adjuster.ModifiedFollowing(), + payment_lag=Adjuster.BusDaysLagSettle(2), + stub=StubInference.NeitherSide, + ), PPSplineF64(3, [0, 0, 0, 1, 1, 1], [0.1, 0.2, 0.3]), PPSplineDual( 3, [0, 0, 0, 1, 1, 1], [Dual(0.1, [], []), Dual(0.2, [], []), Dual(0.3, [], [])] @@ -157,6 +167,9 @@ def test_pickle_round_trip_obj_via_equality(obj): Frequency.Months(4, None), ), (Convention.ActActICMA, Convention.ActActICMA, Convention.ActActISDA), + (FloatFixingMethod.IBOR(2), FloatFixingMethod.IBOR(2), FloatFixingMethod.RFRLookback(2)), + (FloatFixingMethod.IBOR(2), FloatFixingMethod.IBOR(2), FloatFixingMethod.IBOR(5)), + (LegIndexBase.Initial, LegIndexBase.Initial, LegIndexBase.PeriodOnPeriod), ], ) def test_enum_equality(a1, a2, b1): @@ -164,6 +177,22 @@ def test_enum_equality(a1, a2, b1): assert a2 != b1 +@pytest.mark.parametrize( + ("enum", "klass"), + [ + (FloatFixingMethod.IBOR(2), FloatFixingMethod.IBOR), + ], +) +def test_complex_enum_isinstance(enum, klass): + assert isinstance(enum, klass) + type_enum = type(enum) + assert type_enum is klass + assert type_enum in [klass] + assert not isinstance(enum, FloatFixingMethod.RFRLookback) + assert type(enum) is not FloatFixingMethod.RFRLookback + assert enum != FloatFixingMethod.RFRLookback(2) + + @pytest.mark.parametrize( ("enum", "method_filter"), [ @@ -171,6 +200,7 @@ def test_enum_equality(a1, a2, b1): (StubInference, ["to_json"]), (ADOrder, []), (Convention, ["dcf", "to_json"]), + (LegIndexBase, ["to_json"]), ], ) def test_simple_enum_pickle(enum, method_filter): @@ -206,6 +236,15 @@ def test_simple_enum_pickle(enum, method_filter): Frequency.BusDays(2, NamedCal("tgt")), Frequency.Zero(), Frequency.CalDays(3), + FloatFixingMethod.RFRPaymentDelay(), + FloatFixingMethod.RFRPaymentDelayAverage(), + FloatFixingMethod.RFRObservationShift(2), + FloatFixingMethod.RFRObservationShiftAverage(2), + FloatFixingMethod.RFRLookback(3), + FloatFixingMethod.RFRLookbackAverage(3), + FloatFixingMethod.RFRLockout(4), + FloatFixingMethod.RFRLockoutAverage(4), + FloatFixingMethod.IBOR(2), ], ) def test_complex_enum_pickle(enum): diff --git a/python/tests/serialization/test_repr.py b/python/tests/serialization/test_repr.py index ee21ad98a..763daa451 100644 --- a/python/tests/serialization/test_repr.py +++ b/python/tests/serialization/test_repr.py @@ -12,6 +12,7 @@ import pytest from rateslib import dt from rateslib.dual import Dual, Dual2 +from rateslib.enums import FloatFixingMethod, LegIndexBase from rateslib.scheduling import ( Adjuster, Cal, @@ -59,6 +60,9 @@ (Cal([], []), "Cal"), (UnionCal([Cal([], []), Cal([], [])], []), "UnionCal"), (NamedCal("tgt,ldn|fed"), "NamedCal:'tgt,ldn|fed'"), + (FloatFixingMethod.IBOR(2), "FloatFixingMethod.IBOR(2)"), + (FloatFixingMethod.RFRPaymentDelay(), "FloatFixingMethod.RFRPaymentDelay"), + (LegIndexBase.Initial, "LegIndexBase.Initial"), ], ) def test_repr_strings(obj, expected) -> None: diff --git a/python/tests/test_default.py b/python/tests/test_default.py index 177246b21..fcc26aa27 100644 --- a/python/tests/test_default.py +++ b/python/tests/test_default.py @@ -9,12 +9,24 @@ # and/or contact info (at) rateslib (dot) com #################################################################################################### +import os + import pytest -from rateslib import NamedCal, __version__, default_context, defaults, dt, fixings +from rateslib import ( + Licence, + NamedCal, + __version__, + default_context, + defaults, + dt, + fixings, + licence, +) +from rateslib.verify import LicenceNotice, _LicenceStatus def test_version() -> None: - assert __version__ == "2.5.1" + assert __version__ == "2.6.0" def test_context_raises() -> None: @@ -27,13 +39,10 @@ def test_reset_defaults() -> None: defaults.base_currency = "gbp" assert defaults.modifier == "MP" assert defaults.base_currency == "gbp" - defaults.calendars["TEST"] = 10.0 - assert defaults.calendars["TEST"] == 10.0 defaults.reset_defaults() assert defaults.modifier == "MF" assert defaults.base_currency == "usd" - assert "TEST" not in defaults.calendars def test_defaults_singleton() -> None: @@ -80,3 +89,101 @@ def test_float_series_change(): defaults.reset_defaults() assert "monkey" not in defaults.float_series + + +def collect_and_remove_licence() -> tuple[str | None, str | None]: + env_licence = os.getenv("RATESLIB_LICENCE") + if env_licence is not None: + del os.environ["RATESLIB_LICENCE"] + try: + file_licence = licence.print_licence() + licence.remove_licence() + except ValueError: + file_licence = None + return env_licence, file_licence + + +def replace_collected_licence(env_licence, file_licence) -> None: + if env_licence is not None: + os.environ["RATESLIB_LICENCE"] = env_licence + if file_licence is not None: + licence.add_licence(file_licence) + + +class TestLicence: + def test_valid_licence(self): + # test that this system has a valid licence + assert licence.status == _LicenceStatus.VALID + + @pytest.mark.skipif( + os.getenv("RATESLIB_LICENCE") is not None, reason="env licence already tested." + ) + def test_env_licence(self): + # this test relies on `test_valid_licence` + assert licence.status == _LicenceStatus.VALID # licence is loaded from file. + os.environ["RATESLIB_LICENCE"] = licence.print_licence() + licence.remove_licence() # remove the file licence + x = Licence() + assert x.status == _LicenceStatus.VALID + licence.add_licence(os.environ["RATESLIB_LICENCE"]) + del os.environ["RATESLIB_LICENCE"] + + def test_licence_no_licence_warning(self): + # test just the + env_licence, file_licence = collect_and_remove_licence() + with pytest.warns(LicenceNotice, match="No commercial licence is registered"): + Licence() + replace_collected_licence(env_licence, file_licence) + + def test_licence_warning_for_expired_as_file(self): + env_licence, file_licence = collect_and_remove_licence() + licence.add_licence( + '{"expiry": "1900-01-01", "id": "Rateslib Tests", "xkey": "0x2cec1be74d8b2d2bdfa41aec384a4a8ede06c8c7873d6130035c19fcf244b5b92e29c7087a5e51c453a1fe7da345a689ef3d0953b8841ab1b3895a69a209aa529ff3e4d6b8217ce16b37c5572d737ece0a7f381696a3f3901bced9f843b48504930b25d204d910955f52c76eccd208a975a3a0e4433d70dd090ef5adb8de83cb", "name": "System"}' # noqa: E501 + ) + with pytest.warns(LicenceNotice, match="expired on 1900-01-01"): + Licence() + licence.remove_licence() + replace_collected_licence(env_licence, file_licence) + + def test_licence_warning_for_expired_as_env_var(self): + env_licence, file_licence = collect_and_remove_licence() + os.environ["RATESLIB_LICENCE"] = ( + '{"expiry": "1900-01-01", "id": "Rateslib Tests", "xkey": "0x2cec1be74d8b2d2bdfa41aec384a4a8ede06c8c7873d6130035c19fcf244b5b92e29c7087a5e51c453a1fe7da345a689ef3d0953b8841ab1b3895a69a209aa529ff3e4d6b8217ce16b37c5572d737ece0a7f381696a3f3901bced9f843b48504930b25d204d910955f52c76eccd208a975a3a0e4433d70dd090ef5adb8de83cb", "name": "System"}' # noqa: E501 + ) + with pytest.warns(LicenceNotice, match="expired on 1900-01-01"): + Licence() + del os.environ["RATESLIB_LICENCE"] + replace_collected_licence(env_licence, file_licence) + + def test_invalid_signature(self): + env_licence, file_licence = collect_and_remove_licence() + os.environ["RATESLIB_LICENCE"] = ( + '{"expiry": "2100-01-01", "id": "Rateslib Tests", "xkey": "0x2cec1be74d8b2d2bdfa41aec384a4a8ede06c8c7873d6130035c19fcf244b5b92e29c7087a5e51c453a1fe7da345a689ef3d0953b8841ab1b3895a69a209aa529ff3e4d6b8217ce16b37c5572d737ece0a7f381696a3f3901bced9f843b48504930b25d204d910955f52c76eccd208a975a3a0e4433d70dd090ef5adb8de83cb", "name": "System"}' # noqa: E501 + ) + with pytest.warns(LicenceNotice, match="An invalid licence file is detected"): + Licence() + del os.environ["RATESLIB_LICENCE"] + replace_collected_licence(env_licence, file_licence) + + @pytest.mark.parametrize( + "licence_text", + [ + "garbage", + '{"expiry": "1900-01-01", "id": "Rateslib Tests", "xkey": "0x2cec1", "name": "System"}', + ], + ) + def test_add_invalid_licence(self, licence_text): + with pytest.raises(ValueError): + licence.add_licence(licence_text) + + @pytest.mark.parametrize( + "licence_text", + [ + '{"name": "RL Expiry Test", "xkey": "0x68178a21511a36f8270bb4f73451bf3a6575e23e11bc9d0ebead841fa77bfef16cbae1341ad2e6d80f0b717923a48fbd3580eb6cc216a31c0d23618a32e8b2773cc52998e6bcb0315a8f46d003ce04f7ddeb8c19e66a16c73d2e925218dff044ba5f43f7d05503626e89fadbf85751807737f73c55b2048f96fd331b202abe45"}', # noqa: E501 + '{"name": "RL xkey missing"}', + ], + ) + def test_licence_missing_keys(self, licence_text): + from rateslib.verify import _verify_licence + + assert _verify_licence(licence_text) is None diff --git a/python/tests/test_enums.py b/python/tests/test_enums.py new file mode 100644 index 000000000..2e4896d21 --- /dev/null +++ b/python/tests/test_enums.py @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + +from rateslib.enums import FloatFixingMethod + + +def test_method_param(): + a1 = FloatFixingMethod.RFRPaymentDelay() + a2 = FloatFixingMethod.RFRPaymentDelayAverage() + + for obj in [a1, a2]: + assert obj.method_param() == 0 + + b1 = FloatFixingMethod.IBOR(6) + b2 = FloatFixingMethod.RFRLookback(6) + + for obj in [b1, b2]: + assert obj.method_param() == 6 diff --git a/python/tests/test_fixings.py b/python/tests/test_fixings.py index e9e7cc0a6..125869058 100644 --- a/python/tests/test_fixings.py +++ b/python/tests/test_fixings.py @@ -25,6 +25,7 @@ _UnitFixing, ) from rateslib.enums.generics import NoInput +from rateslib.enums.parameters import FloatFixingMethod from rateslib.instruments import IRS from rateslib.scheduling import Adjuster, get_calendar @@ -214,8 +215,7 @@ def test_rfr_lockout(self) -> None: accrual_end=dt(2025, 9, 19), identifier=name, spread_compound_method="NoneSimple", - fixing_method="RFRLockout", - method_param=2, + fixing_method=FloatFixingMethod.RFRLockout(2), float_spread=100.0, rate_index=FloatRateIndex(frequency="1B", series="eur_rfr"), ) diff --git a/python/tests/test_solver.py b/python/tests/test_solver.py index 16936b598..89353205b 100644 --- a/python/tests/test_solver.py +++ b/python/tests/test_solver.py @@ -16,13 +16,13 @@ import numpy as np import pytest from numpy.testing import assert_allclose -from pandas import DataFrame, MultiIndex +from pandas import DataFrame, MultiIndex, Series from pandas.errors import PerformanceWarning from pandas.testing import assert_frame_equal, assert_series_equal from rateslib import default_context from rateslib.curves import CompositeCurve, Curve, LineCurve, MultiCsaCurve, index_left from rateslib.default import NoInput -from rateslib.dual import Dual, Dual2, gradient, ift_1dim, newton_1dim, newton_ndim +from rateslib.dual import Dual, Dual2, Variable, gradient, ift_1dim, newton_1dim, newton_ndim from rateslib.fx import FXForwards, FXRates from rateslib.fx_volatility import FXDeltaVolSmile, FXDeltaVolSurface, FXSabrSmile, FXSabrSurface from rateslib.instruments import ( @@ -2839,3 +2839,133 @@ def test_curves_without_their_own_params(label): s=[2.0], ) assert sv.result["status"] == "SUCCESS" + + +class TestContainerSolver: + # these tests involve a Solver that has no instruments of its own and is just a + # wrapper of 1 or multiple `pre_solvers` + + def test_combine_separate_solvers_for_delta(self): + curve = Curve({dt(2000, 1, 1): 1.0, dt(2001, 1, 1): 1.0}, id="x") + curve2 = Curve({dt(2000, 1, 1): 1.0, dt(2001, 1, 1): 1.0}, id="y") + solver = Solver( + curves=[curve], + instruments=[Value(dt(2000, 9, 12), curves="x", metric="o/n_rate")], + s=[2.0], + instrument_labels=["X"], + id="A1", + ) + solver2 = Solver( + curves=[curve2], + instruments=[Value(dt(2000, 9, 12), curves="y", metric="o/n_rate")], + s=[3.0], + instrument_labels=["Y"], + id="A2", + ) + solver3 = Solver(pre_solvers=[solver, solver2]) + + v = IRS(dt(2000, 9, 12), "1d", "M", curves="x") + w = IRS(dt(2000, 9, 12), "1d", "M", curves="y") + result = Portfolio([v, w]).delta(solver=solver3) + + m_idx = MultiIndex.from_tuples( + [("instruments", "A1", "X"), ("instruments", "A2", "Y")], + names=["type", "solver", "label"], + ) + c_idx = MultiIndex.from_tuples([("usd", "usd")], names=["local_ccy", "display_ccy"]) + expected = DataFrame([0.273825, 0.271870], index=m_idx, columns=c_idx) + assert_frame_equal(result, expected) + + def test_combine_separate_solvers_for_exo_delta(self): + curve = Curve({dt(2000, 1, 1): 1.0, dt(2001, 1, 1): 1.0}, id="x") + curve2 = Curve({dt(2000, 1, 1): 1.0, dt(2001, 1, 1): 1.0}, id="y") + solver = Solver( + curves=[curve], + instruments=[Value(dt(2000, 9, 12), curves="x", metric="o/n_rate")], + s=[2.0], + instrument_labels=["X"], + id="A1", + ) + solver2 = Solver( + curves=[curve2], + instruments=[Value(dt(2000, 9, 12), curves="y", metric="o/n_rate")], + s=[3.0], + instrument_labels=["Y"], + id="A2", + ) + solver3 = Solver(pre_solvers=[solver, solver2]) + + v = IRS( + dt(2000, 9, 12), "1d", "M", curves="x", notional=Variable(1e8, ["exo"]), fixed_rate=5 + ) + w = IRS( + dt(2000, 9, 12), "1d", "M", curves="y", notional=Variable(1e8, ["exo"]), fixed_rate=4 + ) + result = ( + Portfolio([v, w]).exo_delta(solver=solver3, vars=["exo"], vars_scalar=[1e8]).to_numpy() + ) + pv = Portfolio([v, w]).npv(solver=solver3) + assert abs(result[0, 0] - pv) < 1e-7 + + def test_combine_separate_solvers_for_gamma(self): + curve = Curve({dt(2000, 1, 1): 1.0, dt(2001, 1, 1): 1.0}, id="x") + curve2 = Curve({dt(2000, 1, 1): 1.0, dt(2001, 1, 1): 1.0}, id="y") + solver = Solver( + curves=[curve], + instruments=[Value(dt(2000, 9, 12), curves="x", metric="o/n_rate")], + s=[2.0], + instrument_labels=["X"], + id="A1", + ) + solver2 = Solver( + curves=[curve2], + instruments=[Value(dt(2000, 9, 12), curves="y", metric="o/n_rate")], + s=[3.0], + instrument_labels=["Y"], + id="A2", + ) + solver3 = Solver(pre_solvers=[solver, solver2]) + + v = IRS(dt(2000, 9, 12), "1d", "M", curves="x") + w = IRS(dt(2000, 9, 12), "1d", "M", curves="y") + result = Portfolio([v, w]).gamma(solver=solver3).to_numpy() + + partial_result1 = v.gamma(solver=solver).to_numpy() + partial_result2 = w.gamma(solver=solver2).to_numpy() + + assert np.all( + result + == np.block( + [ + [partial_result1, np.zeros(shape=(1, 1))], + [np.zeros(shape=(1, 1)), partial_result2], + ] + ) + ) + + def test_combine_separate_solvers_error(self): + curve = Curve({dt(2000, 1, 1): 1.0, dt(2001, 1, 1): 1.0}, id="x") + curve2 = Curve({dt(2000, 1, 1): 1.0, dt(2001, 1, 1): 1.0}, id="y") + solver = Solver( + curves=[curve], + instruments=[Value(dt(2000, 9, 12), curves="x", metric="o/n_rate")], + s=[2.0], + instrument_labels=["X"], + id="A1", + ) + solver2 = Solver( + curves=[curve2], + instruments=[Value(dt(2000, 9, 12), curves="y", metric="o/n_rate")], + s=[3.0], + instrument_labels=["Y"], + id="A2", + ) + solver3 = Solver(pre_solvers=[solver, solver2]) + result = solver3.error + assert isinstance(result, Series) + + def test_error_empty(self): + s1 = Solver() + s2 = Solver() + s3 = Solver(pre_solvers=[s1, s2]) + assert s3.error.empty diff --git a/python/tests/test_splines.py b/python/tests/test_splines.py index 1da535a5d..c2d5582e0 100644 --- a/python/tests/test_splines.py +++ b/python/tests/test_splines.py @@ -287,7 +287,7 @@ def test_dual_float_raises() -> None: _0 = Dual(0.0, [], []) y0, y1 = Dual(0.0, ["y0"], []), Dual(0.0, ["y1"], []) y2, y3 = Dual(2.0, ["y2"], []), Dual(2.0, ["y3"], []) - with pytest.raises(TypeError, match="argument 'y': 'float' object cannot be"): + with pytest.raises(TypeError, match="argument 'y': 'float' object is not an instance of 'Dua"): sp.csolve([0, 0, 1, 3, 4, 4], [0.0, y0, y1, y2, y3, _0], 2, 2, False) diff --git a/requirements-minimum.txt b/requirements-minimum.txt index a63664c02..1ef9b8ac4 100644 --- a/requirements-minimum.txt +++ b/requirements-minimum.txt @@ -6,4 +6,4 @@ matplotlib==3.5.1 # run tests in github actions maturin>=1.6.0,<2.0 -pytest>=8.2.2,<9.0 \ No newline at end of file +pytest>=9.0,<10.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 466435cdc..0bfb3403d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,16 @@ # project numpy>=1.21.5,<3.0 -pandas>=1.4.1,<3.0 +pandas>=1.4.1,<4.0 matplotlib>=3.5.1,<4.0 # development +# pandas >=3.0,<4.0 maturin>=1.8.0,<2.0 -pytest>=8.3.5,<9.0 +pytest>=9.0,<10.0 coverage>=7.6.1,<8.0 # for test and code monitoring # doc building -sphinx>=8.1,<8.2 +sphinx>=8.1,<9.0 sphinx-automodapi>=0.19.0,<1.0 sphinxcontrib-googleanalytics>=0.4,<1.0 sphinx-tabs>=3.4,<4.0 @@ -19,7 +20,7 @@ pickleshare>=0.7.5,<1.0 ruff>=0.11.0,<1.0 # for code linting mypy>=1.16.0,<1.20 # for type checking -pandas-stubs>=2.0,<3.0 +pandas-stubs>=2.0,<4.0 jupyterlab>=4.0,<5.0 diff --git a/robots.txt b/robots.txt new file mode 100644 index 000000000..0837c620e --- /dev/null +++ b/robots.txt @@ -0,0 +1,8 @@ +User-agent: GPTBot +Disallow: / + +User-agent: CCBot +Disallow: / + +User-agent: ClaudeBot +Disallow: / \ No newline at end of file diff --git a/rust/curves/curve.rs b/rust/curves/curve.rs index 78a796726..a060f5bb3 100644 --- a/rust/curves/curve.rs +++ b/rust/curves/curve.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::curves::interpolation::utils::index_left; use crate::curves::nodes::{Nodes, NodesTimestamp}; use crate::dual::{get_variable_tags, ADOrder, Dual, Dual2, Number}; @@ -22,7 +34,7 @@ pub struct CurveDF { } /// A rule to adjust a non-business day to a business day. -#[pyclass(module = "rateslib.rs", eq, eq_int)] +#[pyclass(module = "rateslib.rs", eq, eq_int, from_py_object)] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Modifier { /// Actual: date is unchanged, even if it is a non-business day. diff --git a/rust/curves/curve_py.rs b/rust/curves/curve_py.rs index 2cc129f3c..6a0d1164e 100644 --- a/rust/curves/curve_py.rs +++ b/rust/curves/curve_py.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Wrapper module to export Rust curve data types to Python using pyo3 bindings. use crate::curves::nodes::{Nodes, NodesTimestamp}; @@ -63,7 +75,7 @@ impl CurveInterpolation for CurveInterpolator { } } -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Deserialize, Serialize)] pub(crate) struct Curve { inner: CurveDF, diff --git a/rust/curves/interpolation/interpolation_py.rs b/rust/curves/interpolation/interpolation_py.rs index 4bf1d42a3..58893afb6 100644 --- a/rust/curves/interpolation/interpolation_py.rs +++ b/rust/curves/interpolation/interpolation_py.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::curves::interpolation::utils::index_left; use pyo3::pyfunction; diff --git a/rust/curves/interpolation/intp_flat_backward.rs b/rust/curves/interpolation/intp_flat_backward.rs index 09222df4a..cc29c0f66 100644 --- a/rust/curves/interpolation/intp_flat_backward.rs +++ b/rust/curves/interpolation/intp_flat_backward.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::curves::nodes::NodesTimestamp; use crate::curves::CurveInterpolation; use crate::dual::Number; @@ -11,7 +23,7 @@ use serde::{Deserialize, Serialize}; use std::cmp::PartialEq; /// Define flat backward interpolation of nodes. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct FlatBackwardInterpolator {} diff --git a/rust/curves/interpolation/intp_flat_forward.rs b/rust/curves/interpolation/intp_flat_forward.rs index c47a52558..c06c32683 100644 --- a/rust/curves/interpolation/intp_flat_forward.rs +++ b/rust/curves/interpolation/intp_flat_forward.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::curves::nodes::NodesTimestamp; use crate::curves::CurveInterpolation; use crate::dual::Number; @@ -11,7 +23,7 @@ use serde::{Deserialize, Serialize}; use std::cmp::PartialEq; /// Define flat forward interpolation of nodes. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct FlatForwardInterpolator {} diff --git a/rust/curves/interpolation/intp_linear.rs b/rust/curves/interpolation/intp_linear.rs index a4e3fb687..0a51221fa 100644 --- a/rust/curves/interpolation/intp_linear.rs +++ b/rust/curves/interpolation/intp_linear.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::curves::interpolation::utils::linear_interp; use crate::curves::nodes::NodesTimestamp; use crate::curves::CurveInterpolation; @@ -12,7 +24,7 @@ use serde::{Deserialize, Serialize}; use std::cmp::PartialEq; /// Define linear interpolation of nodes. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct LinearInterpolator {} diff --git a/rust/curves/interpolation/intp_linear_zero_rate.rs b/rust/curves/interpolation/intp_linear_zero_rate.rs index 94f2af190..26b7b89b4 100644 --- a/rust/curves/interpolation/intp_linear_zero_rate.rs +++ b/rust/curves/interpolation/intp_linear_zero_rate.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::curves::interpolation::utils::linear_zero_interp; use crate::curves::nodes::NodesTimestamp; use crate::curves::CurveInterpolation; @@ -14,7 +26,7 @@ use std::cmp::PartialEq; /// Define linear zero rate interpolation of nodes. /// /// This interpolation can only be used with discount factors node values. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct LinearZeroRateInterpolator {} diff --git a/rust/curves/interpolation/intp_log_cubic.rs b/rust/curves/interpolation/intp_log_cubic.rs index 3dc296409..fff5094f4 100644 --- a/rust/curves/interpolation/intp_log_cubic.rs +++ b/rust/curves/interpolation/intp_log_cubic.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::curves::interpolation::utils::log_linear_interp; use crate::curves::nodes::NodesTimestamp; use crate::curves::CurveInterpolation; @@ -12,7 +24,7 @@ use serde::{Deserialize, Serialize}; use std::cmp::PartialEq; /// Define log-linear interpolation of nodes. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct LogCubicInterpolator { spline: T diff --git a/rust/curves/interpolation/intp_log_linear.rs b/rust/curves/interpolation/intp_log_linear.rs index 4621fd1c4..6b9a76daa 100644 --- a/rust/curves/interpolation/intp_log_linear.rs +++ b/rust/curves/interpolation/intp_log_linear.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::curves::interpolation::utils::log_linear_interp; use crate::curves::nodes::NodesTimestamp; use crate::curves::CurveInterpolation; @@ -12,7 +24,7 @@ use serde::{Deserialize, Serialize}; use std::cmp::PartialEq; /// Define log-linear interpolation of nodes. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct LogLinearInterpolator {} diff --git a/rust/curves/interpolation/intp_null.rs b/rust/curves/interpolation/intp_null.rs index afa203194..1388960c0 100644 --- a/rust/curves/interpolation/intp_null.rs +++ b/rust/curves/interpolation/intp_null.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::curves::nodes::NodesTimestamp; use crate::curves::CurveInterpolation; use crate::dual::Number; @@ -13,7 +25,7 @@ use std::cmp::PartialEq; /// Define a null interpolation object. /// /// This is used by PyO3 binding to indicate interpolation occurs in Python. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct NullInterpolator {} diff --git a/rust/curves/interpolation/mod.rs b/rust/curves/interpolation/mod.rs index e986f62c2..b3e847da5 100644 --- a/rust/curves/interpolation/mod.rs +++ b/rust/curves/interpolation/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + pub(crate) mod interpolation_py; pub(crate) mod intp_flat_backward; diff --git a/rust/curves/interpolation/utils.rs b/rust/curves/interpolation/utils.rs index 54f95883e..f446d81f8 100644 --- a/rust/curves/interpolation/utils.rs +++ b/rust/curves/interpolation/utils.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::{MathFuncs, NumberOps}; use std::{ cmp::{PartialEq, PartialOrd}, diff --git a/rust/curves/mod.rs b/rust/curves/mod.rs index c2f03ae0a..e9fa766b5 100644 --- a/rust/curves/mod.rs +++ b/rust/curves/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Create curves for calculating interest rates and discount factors. pub(crate) mod nodes; diff --git a/rust/curves/nodes.rs b/rust/curves/nodes.rs index edbfc8327..ad074795b 100644 --- a/rust/curves/nodes.rs +++ b/rust/curves/nodes.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::{Dual, Dual2, Number}; use chrono::{DateTime, NaiveDateTime}; use indexmap::IndexMap; diff --git a/rust/curves/serde.rs b/rust/curves/serde.rs index f2bf86e16..0acaa4f77 100644 --- a/rust/curves/serde.rs +++ b/rust/curves/serde.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::curves::curve_py::Curve; use crate::curves::{CurveDF, CurveInterpolation}; use crate::json::JSON; diff --git a/rust/dual/docs.rs b/rust/dual/docs.rs index fbb107c7d..37f7c62a5 100644 --- a/rust/dual/docs.rs +++ b/rust/dual/docs.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Standalone documentation pages. //! //! # Examples diff --git a/rust/dual/dual.rs b/rust/dual/dual.rs index ee51967ab..4971b3d3a 100644 --- a/rust/dual/dual.rs +++ b/rust/dual/dual.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + pub use crate::dual::dual_ops::convert::{set_order, set_order_clone}; pub use crate::dual::dual_ops::math_funcs::MathFuncs; pub use crate::dual::dual_ops::numeric_ops::NumberOps; @@ -10,7 +22,7 @@ use std::cmp::PartialEq; use std::sync::Arc; /// A dual number data type supporting first order derivatives. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Default, Debug, Deserialize, Serialize)] pub struct Dual { pub(crate) real: f64, @@ -19,7 +31,7 @@ pub struct Dual { } /// A dual number data type supporting second order derivatives. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct Dual2 { pub(crate) real: f64, diff --git a/rust/dual/dual_ops/add.rs b/rust/dual/dual_ops/add.rs index 2cc9028ac..0d05eec86 100644 --- a/rust/dual/dual_ops/add.rs +++ b/rust/dual/dual_ops/add.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2, Vars, VarsRelationship}; use crate::dual::enums::Number; use auto_ops::{impl_op_ex, impl_op_ex_commutative}; diff --git a/rust/dual/dual_ops/convert.rs b/rust/dual/dual_ops/convert.rs index 4b2cb3caa..6f78cbd74 100644 --- a/rust/dual/dual_ops/convert.rs +++ b/rust/dual/dual_ops/convert.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::{ADOrder, Number}; use std::convert::From; diff --git a/rust/dual/dual_ops/div.rs b/rust/dual/dual_ops/div.rs index c89a1b8d9..a885b85a9 100644 --- a/rust/dual/dual_ops/div.rs +++ b/rust/dual/dual_ops/div.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use auto_ops::impl_op_ex; diff --git a/rust/dual/dual_ops/eq.rs b/rust/dual/dual_ops/eq.rs index f9cbdc810..1fbec7b95 100644 --- a/rust/dual/dual_ops/eq.rs +++ b/rust/dual/dual_ops/eq.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2, Vars, VarsRelationship}; use crate::dual::enums::Number; diff --git a/rust/dual/dual_ops/from.rs b/rust/dual/dual_ops/from.rs index 1ba18f466..f8c13f56d 100644 --- a/rust/dual/dual_ops/from.rs +++ b/rust/dual/dual_ops/from.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use ndarray::{Array2, Axis}; diff --git a/rust/dual/dual_ops/math_funcs.rs b/rust/dual/dual_ops/math_funcs.rs index 33c26b841..2c507ad51 100644 --- a/rust/dual/dual_ops/math_funcs.rs +++ b/rust/dual/dual_ops/math_funcs.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use crate::dual::linalg::fouter11_; diff --git a/rust/dual/dual_ops/mod.rs b/rust/dual/dual_ops/mod.rs index 2808c5f1b..a8214d381 100644 --- a/rust/dual/dual_ops/mod.rs +++ b/rust/dual/dual_ops/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + mod add; pub mod convert; mod div; diff --git a/rust/dual/dual_ops/mul.rs b/rust/dual/dual_ops/mul.rs index 50303442e..d94937919 100644 --- a/rust/dual/dual_ops/mul.rs +++ b/rust/dual/dual_ops/mul.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2, Vars, VarsRelationship}; use crate::dual::enums::Number; use crate::dual::linalg::fouter11_; diff --git a/rust/dual/dual_ops/neg.rs b/rust/dual/dual_ops/neg.rs index 307394fb5..80f2d1667 100644 --- a/rust/dual/dual_ops/neg.rs +++ b/rust/dual/dual_ops/neg.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use auto_ops::impl_op; diff --git a/rust/dual/dual_ops/num.rs b/rust/dual/dual_ops/num.rs index f0eb53917..9ecd51726 100644 --- a/rust/dual/dual_ops/num.rs +++ b/rust/dual/dual_ops/num.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use num_traits::Num; diff --git a/rust/dual/dual_ops/numeric_ops.rs b/rust/dual/dual_ops/numeric_ops.rs index b446add9a..5d305bbe3 100644 --- a/rust/dual/dual_ops/numeric_ops.rs +++ b/rust/dual/dual_ops/numeric_ops.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use std::ops::{Add, Div, Mul, Sub}; diff --git a/rust/dual/dual_ops/one.rs b/rust/dual/dual_ops/one.rs index 1737c46d6..4b977e1a9 100644 --- a/rust/dual/dual_ops/one.rs +++ b/rust/dual/dual_ops/one.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use num_traits::One; diff --git a/rust/dual/dual_ops/ord.rs b/rust/dual/dual_ops/ord.rs index cc5f8e86c..393a3dea7 100644 --- a/rust/dual/dual_ops/ord.rs +++ b/rust/dual/dual_ops/ord.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use std::cmp::Ordering; diff --git a/rust/dual/dual_ops/pow.rs b/rust/dual/dual_ops/pow.rs index efc6ddc7f..addc5b43e 100644 --- a/rust/dual/dual_ops/pow.rs +++ b/rust/dual/dual_ops/pow.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2, Vars, VarsRelationship}; use crate::dual::enums::Number; use crate::dual::linalg::fouter11_; diff --git a/rust/dual/dual_ops/rem.rs b/rust/dual/dual_ops/rem.rs index a6a09a17d..f545068e7 100644 --- a/rust/dual/dual_ops/rem.rs +++ b/rust/dual/dual_ops/rem.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use auto_ops::impl_op_ex; diff --git a/rust/dual/dual_ops/signed.rs b/rust/dual/dual_ops/signed.rs index cdea17fe6..5be0b6378 100644 --- a/rust/dual/dual_ops/signed.rs +++ b/rust/dual/dual_ops/signed.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use num_traits::Signed; diff --git a/rust/dual/dual_ops/sub.rs b/rust/dual/dual_ops/sub.rs index 4a5760e6b..e63db6a51 100644 --- a/rust/dual/dual_ops/sub.rs +++ b/rust/dual/dual_ops/sub.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2, Vars, VarsRelationship}; use crate::dual::enums::Number; use auto_ops::impl_op_ex; diff --git a/rust/dual/dual_ops/sum.rs b/rust/dual/dual_ops/sum.rs index 2a4e10de5..bedca1fd3 100644 --- a/rust/dual/dual_ops/sum.rs +++ b/rust/dual/dual_ops/sum.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use std::iter::Sum; diff --git a/rust/dual/dual_ops/zero.rs b/rust/dual/dual_ops/zero.rs index f9894216f..719276e3e 100644 --- a/rust/dual/dual_ops/zero.rs +++ b/rust/dual/dual_ops/zero.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::dual::{Dual, Dual2}; use crate::dual::enums::Number; use num_traits::Zero; diff --git a/rust/dual/dual_py.rs b/rust/dual/dual_py.rs index fecb80aa1..3756bae0c 100644 --- a/rust/dual/dual_py.rs +++ b/rust/dual/dual_py.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Wrapper module to export Rust dual data types to Python using pyo3 bindings. use crate::dual::dual::{Dual, Dual2, Gradient1, Gradient2, Vars}; diff --git a/rust/dual/enums.rs b/rust/dual/enums.rs index 3832d84d2..bf06541f2 100644 --- a/rust/dual/enums.rs +++ b/rust/dual/enums.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::{Dual, Dual2}; use crate::splines::{PPSplineDual, PPSplineDual2, PPSplineF64}; use ndarray::{Array1, Array2}; @@ -5,7 +17,7 @@ use pyo3::{pyclass, FromPyObject, IntoPyObject, PyErr}; use serde::{Deserialize, Serialize}; /// Defines the order of gradients available in a calculation with AD. -#[pyclass(module = "rateslib.rs", eq, eq_int)] +#[pyclass(module = "rateslib.rs", eq, eq_int, from_py_object)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum ADOrder { /// Floating point arithmetic only. diff --git a/rust/dual/linalg/linalg_dual.rs b/rust/dual/linalg/linalg_dual.rs index ba8e043ba..fa4f5872f 100644 --- a/rust/dual/linalg/linalg_dual.rs +++ b/rust/dual/linalg/linalg_dual.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Perform linear algebra operations on arrays containing generic data types. use itertools::Itertools; diff --git a/rust/dual/linalg/linalg_f64.rs b/rust/dual/linalg/linalg_f64.rs index dce412f83..0f077bb88 100644 --- a/rust/dual/linalg/linalg_f64.rs +++ b/rust/dual/linalg/linalg_f64.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Perform linear algebraic operations between arrays of generic type and arrays of f64. use crate::dual::linalg::linalg_dual::{argabsmax, dmul22_, el_swap, row_swap}; diff --git a/rust/dual/linalg/mod.rs b/rust/dual/linalg/mod.rs index 86b6cc041..772b30cfd 100644 --- a/rust/dual/linalg/mod.rs +++ b/rust/dual/linalg/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Perform linear algebra operations involving Arrays of [f64], [Dual](crate::dual::Dual) and [Dual2](crate::dual::Dual2). mod linalg_dual; diff --git a/rust/dual/linalg_py.rs b/rust/dual/linalg_py.rs index 69c3eb54d..f2776efb4 100644 --- a/rust/dual/linalg_py.rs +++ b/rust/dual/linalg_py.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Wrapper module to export Rust linalg operations to Python using pyo3 bindings. use crate::dual::dual::{Dual, Dual2}; diff --git a/rust/dual/mod.rs b/rust/dual/mod.rs index 992b6d714..749c2df74 100644 --- a/rust/dual/mod.rs +++ b/rust/dual/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Toolset for forward mode automatic differentiation (AD). //! //! # AD Architecture diff --git a/rust/enums/mod.rs b/rust/enums/mod.rs new file mode 100644 index 000000000..571e4e207 --- /dev/null +++ b/rust/enums/mod.rs @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// pub mod docs; + +mod parameters; +pub use crate::enums::parameters::{FloatFixingMethod, LegIndexBase}; + +pub(crate) mod py; +pub(crate) use crate::enums::py::PyFloatFixingMethod; diff --git a/rust/enums/parameters.rs b/rust/enums/parameters.rs new file mode 100644 index 000000000..e67a7ffd7 --- /dev/null +++ b/rust/enums/parameters.rs @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + +use pyo3::prelude::*; +use serde::{Deserialize, Serialize}; + +/// Specifier for date adjustment rules. +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +pub enum FloatFixingMethod { + /// RFR periods are settled with cashflow dates determined (separately as part of a Schedule) with a lag. + RFRPaymentDelay {}, + /// RFR fixings and associated DCFs use values taken from 'n' business days prior. + RFRObservationShift(i32), + /// The final 'n' RFR fixings' values are taken as the most recent published value. + RFRLockout(i32), + /// RFR fixings use values taken from 'n' business days prior (no DCF shift). + RFRLookback(i32), + /// Uses arithmetic averaging instead compounding on the RFRPaymentDelay method. + RFRPaymentDelayAverage {}, + /// Uses arithmetic averaging instead compounding on the RFRObservationShift method. + RFRObservationShiftAverage(i32), + /// Uses arithmetic averaging instead compounding on the RFRLockout method. + RFRLockoutAverage(i32), + /// Uses arithmetic averaging instead compounding on the RFRLookback method. + RFRLookbackAverage(i32), + /// Uses a tenor IBOR type rate calculation with the fixing lagged by 'n' business days. + IBOR(i32), +} + +impl FloatFixingMethod { + /// Return a fixing lag parameter associated with the variant. + pub fn method_param(&self) -> i32 { + match self { + FloatFixingMethod::RFRPaymentDelay {} + | FloatFixingMethod::RFRPaymentDelayAverage {} => 0_i32, + FloatFixingMethod::RFRObservationShift(param) + | FloatFixingMethod::RFRObservationShiftAverage(param) + | FloatFixingMethod::RFRLookback(param) + | FloatFixingMethod::RFRLookbackAverage(param) + | FloatFixingMethod::RFRLockout(param) + | FloatFixingMethod::RFRLockoutAverage(param) + | FloatFixingMethod::IBOR(param) => *param, + } + } +} + +/// Enumerable type for index base determination on each Period in a Leg. +#[pyclass(module = "rateslib.rs", eq, eq_int, hash, frozen, from_py_object)] +#[derive(Debug, Hash, Copy, Clone, Serialize, Deserialize, PartialEq)] +pub enum LegIndexBase { + /// Set the index base on every period as the initial base date of the Leg. + Initial = 0, + /// Set the index base date of each period successively as the reference value for the + // previous period. + PeriodOnPeriod = 1, +} diff --git a/rust/enums/py/float_fixing_method.rs b/rust/enums/py/float_fixing_method.rs new file mode 100644 index 000000000..0698b9ee6 --- /dev/null +++ b/rust/enums/py/float_fixing_method.rs @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//! Wrapper module to export to Python using pyo3 bindings. + +use crate::enums::FloatFixingMethod; +use crate::json::{DeserializedObj, JSON}; +use pyo3::exceptions::PyValueError; +use pyo3::prelude::*; +use pyo3::types::PyTuple; +use serde::{Deserialize, Serialize}; + +/// Enumerable type to defined floating period rate methods. +/// +/// .. rubric:: Variants +/// +/// .. ipython:: python +/// :suppress: +/// +/// from rateslib.rs import FloatFixingMethod +/// variants = [item for item in FloatFixingMethod.__dict__ if \ +/// "__" != item[:2] and \ +/// item not in ['to_json', 'method_param'] \ +/// ] +/// +/// .. ipython:: python +/// +/// variants +/// +#[pyclass(module = "rateslib.rs", name = "FloatFixingMethod", eq, from_py_object)] +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +pub(crate) enum PyFloatFixingMethod { + #[pyo3(constructor = (_u8=0))] + RFRPaymentDelay { _u8: u8 }, + #[pyo3(constructor = (param, _u8=1))] + RFRObservationShift { param: i32, _u8: u8 }, + #[pyo3(constructor = (param, _u8=2))] + RFRLockout { param: i32, _u8: u8 }, + #[pyo3(constructor = (param, _u8=3))] + RFRLookback { param: i32, _u8: u8 }, + #[pyo3(constructor = (_u8=4))] + RFRPaymentDelayAverage { _u8: u8 }, + #[pyo3(constructor = (param, _u8=5))] + RFRObservationShiftAverage { param: i32, _u8: u8 }, + #[pyo3(constructor = (param, _u8=6))] + RFRLockoutAverage { param: i32, _u8: u8 }, + #[pyo3(constructor = (param, _u8=7))] + RFRLookbackAverage { param: i32, _u8: u8 }, + #[pyo3(constructor = (param, _u8=8))] + IBOR { param: i32, _u8: u8 }, +} + +/// Used for providing pickle support for PyFloatFixingMethod +enum PyFloatFixingMethodNewArgs { + NoArgs(u8), + I32(i32, u8), +} + +impl<'py> IntoPyObject<'py> for PyFloatFixingMethodNewArgs { + type Target = PyTuple; + type Output = Bound<'py, Self::Target>; + type Error = std::convert::Infallible; + + fn into_pyobject(self, py: Python<'py>) -> Result { + match self { + PyFloatFixingMethodNewArgs::NoArgs(x) => Ok((x,).into_pyobject(py).unwrap()), + PyFloatFixingMethodNewArgs::I32(x, y) => Ok((x, y).into_pyobject(py).unwrap()), + } + } +} + +impl<'py> FromPyObject<'py, 'py> for PyFloatFixingMethodNewArgs { + type Error = PyErr; + + fn extract(obj: Borrowed<'_, 'py, PyAny>) -> Result { + let ext: PyResult<(u8,)> = obj.extract(); + if ext.is_ok() { + let (x,) = ext.unwrap(); + return Ok(PyFloatFixingMethodNewArgs::NoArgs(x)); + } + let ext: PyResult<(i32, u8)> = obj.extract(); + if ext.is_ok() { + let (x, y) = ext.unwrap(); + return Ok(PyFloatFixingMethodNewArgs::I32(x, y)); + } + Err(PyValueError::new_err("Undefined behaviour")) + } +} + +impl From for PyFloatFixingMethod { + fn from(value: FloatFixingMethod) -> Self { + match value { + FloatFixingMethod::RFRPaymentDelay {} => { + PyFloatFixingMethod::RFRPaymentDelay { _u8: 0 } + } + FloatFixingMethod::RFRObservationShift(n) => { + PyFloatFixingMethod::RFRObservationShift { param: n, _u8: 1 } + } + FloatFixingMethod::RFRLockout(n) => { + PyFloatFixingMethod::RFRLockout { param: n, _u8: 2 } + } + FloatFixingMethod::RFRLookback(n) => { + PyFloatFixingMethod::RFRLookback { param: n, _u8: 3 } + } + FloatFixingMethod::RFRPaymentDelayAverage {} => { + PyFloatFixingMethod::RFRPaymentDelayAverage { _u8: 4 } + } + FloatFixingMethod::RFRObservationShiftAverage(n) => { + PyFloatFixingMethod::RFRObservationShiftAverage { param: n, _u8: 5 } + } + FloatFixingMethod::RFRLockoutAverage(n) => { + PyFloatFixingMethod::RFRLockoutAverage { param: n, _u8: 6 } + } + FloatFixingMethod::RFRLookbackAverage(n) => { + PyFloatFixingMethod::RFRLookbackAverage { param: n, _u8: 7 } + } + FloatFixingMethod::IBOR(n) => PyFloatFixingMethod::IBOR { param: n, _u8: 8 }, + } + } +} + +impl From for FloatFixingMethod { + fn from(value: PyFloatFixingMethod) -> Self { + match value { + PyFloatFixingMethod::RFRPaymentDelay { _u8: _ } => { + FloatFixingMethod::RFRPaymentDelay {} + } + PyFloatFixingMethod::RFRObservationShift { param: n, _u8: _ } => { + FloatFixingMethod::RFRObservationShift(n) + } + PyFloatFixingMethod::RFRLockout { param: n, _u8: _ } => { + FloatFixingMethod::RFRLockout(n) + } + PyFloatFixingMethod::RFRLookback { param: n, _u8: _ } => { + FloatFixingMethod::RFRLookback(n) + } + PyFloatFixingMethod::RFRPaymentDelayAverage { _u8: _ } => { + FloatFixingMethod::RFRPaymentDelayAverage {} + } + PyFloatFixingMethod::RFRObservationShiftAverage { param: n, _u8: _ } => { + FloatFixingMethod::RFRObservationShiftAverage(n) + } + PyFloatFixingMethod::RFRLockoutAverage { param: n, _u8: _ } => { + FloatFixingMethod::RFRLockoutAverage(n) + } + PyFloatFixingMethod::RFRLookbackAverage { param: n, _u8: _ } => { + FloatFixingMethod::RFRLookbackAverage(n) + } + PyFloatFixingMethod::IBOR { param: n, _u8: _ } => FloatFixingMethod::IBOR(n), + } + } +} + +#[pymethods] +impl PyFloatFixingMethod { + /// Return a parameter associated with the fixing method. + /// + /// Returns + /// ------- + /// int + #[pyo3(name = "method_param")] + fn method_param_py(&self) -> i32 { + let fixing_method: FloatFixingMethod = (*self).into(); + fixing_method.method_param() + } + + fn __str__(&self) -> String { + match self { + PyFloatFixingMethod::RFRPaymentDelay { _u8: _ } => "rfr_payment_delay".to_string(), + PyFloatFixingMethod::RFRObservationShift { param: _, _u8: _ } => { + "rfr_observation_shift".to_string() + } + PyFloatFixingMethod::RFRLockout { param: _, _u8: _ } => "rfr_lockout".to_string(), + PyFloatFixingMethod::RFRLookback { param: _, _u8: _ } => "rfr_lookback".to_string(), + PyFloatFixingMethod::RFRPaymentDelayAverage { _u8: _ } => { + "rfr_payment_delay_avg".to_string() + } + PyFloatFixingMethod::RFRObservationShiftAverage { param: _, _u8: _ } => { + "rfr_observation_shift_avg".to_string() + } + PyFloatFixingMethod::RFRLockoutAverage { param: _, _u8: _ } => { + "rfr_lockout_avg".to_string() + } + PyFloatFixingMethod::RFRLookbackAverage { param: _, _u8: _ } => { + "rfr_lookback_avg".to_string() + } + PyFloatFixingMethod::IBOR { param: _, _u8: _ } => "ibor".to_string(), + } + } + + fn __getnewargs__(&self) -> PyFloatFixingMethodNewArgs { + match self { + PyFloatFixingMethod::RFRPaymentDelay { _u8: u } => { + PyFloatFixingMethodNewArgs::NoArgs(*u) + } + PyFloatFixingMethod::RFRObservationShift { param: n, _u8: u } => { + PyFloatFixingMethodNewArgs::I32(*n, *u) + } + PyFloatFixingMethod::RFRLockout { param: n, _u8: u } => { + PyFloatFixingMethodNewArgs::I32(*n, *u) + } + PyFloatFixingMethod::RFRLookback { param: n, _u8: u } => { + PyFloatFixingMethodNewArgs::I32(*n, *u) + } + PyFloatFixingMethod::RFRPaymentDelayAverage { _u8: u } => { + PyFloatFixingMethodNewArgs::NoArgs(*u) + } + PyFloatFixingMethod::RFRObservationShiftAverage { param: n, _u8: u } => { + PyFloatFixingMethodNewArgs::I32(*n, *u) + } + PyFloatFixingMethod::RFRLockoutAverage { param: n, _u8: u } => { + PyFloatFixingMethodNewArgs::I32(*n, *u) + } + PyFloatFixingMethod::RFRLookbackAverage { param: n, _u8: u } => { + PyFloatFixingMethodNewArgs::I32(*n, *u) + } + PyFloatFixingMethod::IBOR { param: n, _u8: u } => { + PyFloatFixingMethodNewArgs::I32(*n, *u) + } + } + } + + #[new] + fn new_py(args: PyFloatFixingMethodNewArgs) -> PyFloatFixingMethod { + match args { + PyFloatFixingMethodNewArgs::NoArgs(0) => { + PyFloatFixingMethod::RFRPaymentDelay { _u8: 0 } + } + PyFloatFixingMethodNewArgs::I32(n, 1) => { + PyFloatFixingMethod::RFRObservationShift { param: n, _u8: 1 } + } + PyFloatFixingMethodNewArgs::I32(n, 2) => { + PyFloatFixingMethod::RFRLockout { param: n, _u8: 2 } + } + PyFloatFixingMethodNewArgs::I32(n, 3) => { + PyFloatFixingMethod::RFRLookback { param: n, _u8: 3 } + } + PyFloatFixingMethodNewArgs::NoArgs(4) => { + PyFloatFixingMethod::RFRPaymentDelayAverage { _u8: 4 } + } + PyFloatFixingMethodNewArgs::I32(n, 5) => { + PyFloatFixingMethod::RFRObservationShiftAverage { param: n, _u8: 5 } + } + PyFloatFixingMethodNewArgs::I32(n, 6) => { + PyFloatFixingMethod::RFRLockoutAverage { param: n, _u8: 6 } + } + PyFloatFixingMethodNewArgs::I32(n, 7) => { + PyFloatFixingMethod::RFRLookbackAverage { param: n, _u8: 7 } + } + PyFloatFixingMethodNewArgs::I32(n, 8) => PyFloatFixingMethod::IBOR { param: n, _u8: 8 }, + _ => panic!("Undefined behaviour."), + } + } + + fn __repr__(&self) -> String { + let fixing_method: FloatFixingMethod = (*self).into(); + format!("", fixing_method, self) + } + + /// Return a JSON representation of the object. + /// + /// Returns + /// ------- + /// str + #[pyo3(name = "to_json")] + fn to_json_py(&self) -> PyResult { + match DeserializedObj::PyFloatFixingMethod(self.clone()).to_json() { + Ok(v) => Ok(v), + Err(_) => Err(PyValueError::new_err( + "Failed to serialize `FloatFixingMethod` to JSON.", + )), + } + } +} diff --git a/rust/enums/py/leg_index_base.rs b/rust/enums/py/leg_index_base.rs new file mode 100644 index 000000000..0b38cfc2b --- /dev/null +++ b/rust/enums/py/leg_index_base.rs @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + +use crate::enums::parameters::LegIndexBase; +use crate::json::{DeserializedObj, JSON}; + +use pyo3::exceptions::PyValueError; +use pyo3::prelude::*; + +#[pymethods] +impl LegIndexBase { + // JSON + /// Return a JSON representation of the object. + /// + /// Returns + /// ------- + /// str + #[pyo3(name = "to_json")] + fn to_json_py(&self) -> PyResult { + match DeserializedObj::LegIndexBase(self.clone()).to_json() { + Ok(v) => Ok(v), + Err(_) => Err(PyValueError::new_err( + "Failed to serialize `LegIndexBase` to JSON.", + )), + } + } + + // Pickling + #[new] + fn new_py(item: usize) -> PyResult { + match item { + _ if item == LegIndexBase::Initial as usize => Ok(LegIndexBase::Initial), + _ if item == LegIndexBase::PeriodOnPeriod as usize => Ok(LegIndexBase::PeriodOnPeriod), + _ => Err(PyValueError::new_err( + "unreachable code on LegIndexBase pickle. Please report", + )), + } + } + fn __getnewargs__<'py>(&self) -> PyResult<(usize,)> { + Ok((*self as usize,)) + } + + fn __repr__(&self) -> String { + format!("", self, self) + } +} diff --git a/rust/enums/py/mod.rs b/rust/enums/py/mod.rs new file mode 100644 index 000000000..825b89be3 --- /dev/null +++ b/rust/enums/py/mod.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + +pub(crate) mod float_fixing_method; +pub(crate) mod leg_index_base; + +pub(crate) use crate::enums::py::float_fixing_method::PyFloatFixingMethod; diff --git a/rust/fx/mod.rs b/rust/fx/mod.rs index f94c5ac13..5dbf78c9b 100644 --- a/rust/fx/mod.rs +++ b/rust/fx/mod.rs @@ -1,2 +1,14 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + pub mod rates; pub mod rates_py; diff --git a/rust/fx/rates/ccy.rs b/rust/fx/rates/ccy.rs index fd76c5b91..ff237dfe0 100644 --- a/rust/fx/rates/ccy.rs +++ b/rust/fx/rates/ccy.rs @@ -1,10 +1,22 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use internment::Intern; use pyo3::exceptions::PyValueError; use pyo3::{pyclass, PyErr}; use serde::{Deserialize, Serialize}; /// A currency identified by 3-ascii ISO code. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct Ccy { pub(crate) name: Intern, diff --git a/rust/fx/rates/fxpair.rs b/rust/fx/rates/fxpair.rs index 3fa4333a1..3b9f47834 100644 --- a/rust/fx/rates/fxpair.rs +++ b/rust/fx/rates/fxpair.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::fx::rates::ccy::Ccy; use pyo3::exceptions::PyValueError; use pyo3::PyErr; diff --git a/rust/fx/rates/fxrate.rs b/rust/fx/rates/fxrate.rs index f4fef7a2e..157878b0c 100644 --- a/rust/fx/rates/fxrate.rs +++ b/rust/fx/rates/fxrate.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::Number; use crate::fx::rates::fxpair::FXPair; use chrono::NaiveDateTime; @@ -5,7 +17,7 @@ use pyo3::{pyclass, PyErr}; use serde::{Deserialize, Serialize}; /// An FX rate containing `FXPair`, `rate` and `settlement` info. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct FXRate { pub(crate) pair: FXPair, diff --git a/rust/fx/rates/mod.rs b/rust/fx/rates/mod.rs index 2c0ccdd4d..eaa4becc6 100644 --- a/rust/fx/rates/mod.rs +++ b/rust/fx/rates/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Create objects related to the management and valuation of monetary amounts in different //! currencies, measured at different settlement dates in time. @@ -24,7 +36,7 @@ pub(crate) mod fxrate; pub use crate::fx::rates::fxrate::FXRate; /// A multi-currency FX market deriving all crosses from a vector of `FXRate`s. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(from = "FXRatesDataModel")] pub struct FXRates { diff --git a/rust/fx/rates_py.rs b/rust/fx/rates_py.rs index 26b33cac6..e410fcccf 100644 --- a/rust/fx/rates_py.rs +++ b/rust/fx/rates_py.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Wrapper module to export Rust FX rate data types to Python using pyo3 bindings. use crate::dual::{ADOrder, Number, NumberArray2}; diff --git a/rust/fx_volatility/mod.rs b/rust/fx_volatility/mod.rs index 831b7e759..95f742aa2 100644 --- a/rust/fx_volatility/mod.rs +++ b/rust/fx_volatility/mod.rs @@ -1 +1,13 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + pub mod sabr_funcs; diff --git a/rust/fx_volatility/sabr_funcs.rs b/rust/fx_volatility/sabr_funcs.rs index 6ece7afbf..298290f1c 100644 --- a/rust/fx_volatility/sabr_funcs.rs +++ b/rust/fx_volatility/sabr_funcs.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::linalg::fouter11_; use crate::dual::{Dual, Dual2, MathFuncs, Number, Vars}; diff --git a/rust/json/json_py.rs b/rust/json/json_py.rs index 3500ed765..f51662cdd 100644 --- a/rust/json/json_py.rs +++ b/rust/json/json_py.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Wrapper to allow de/serializable objects in Rust to be passed to/from Python using pyo3 //! bindings. //! @@ -7,6 +19,7 @@ use crate::curves::curve_py::Curve; use crate::dual::{Dual, Dual2}; +use crate::enums::{LegIndexBase, PyFloatFixingMethod}; use crate::fx::rates::FXRates; use crate::json::JSON; use crate::scheduling::{ @@ -41,6 +54,8 @@ pub(crate) enum DeserializedObj { PyAdjuster(PyAdjuster), Schedule(Schedule), Convention(Convention), + PyFloatFixingMethod(PyFloatFixingMethod), + LegIndexBase(LegIndexBase), } impl JSON for DeserializedObj {} diff --git a/rust/json/mod.rs b/rust/json/mod.rs index ecab4334b..b817cbda8 100644 --- a/rust/json/mod.rs +++ b/rust/json/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Allows serialization and deserialization to JSON, with the ``serde`` crate. pub(crate) mod json_py; diff --git a/rust/lib.rs b/rust/lib.rs index 968a62414..ec1810a0c 100644 --- a/rust/lib.rs +++ b/rust/lib.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! This is the documentation for rateslib-rs //! //!
This library is in development. Only parts of *rateslib (Python)* have been ported @@ -43,10 +55,13 @@ use fx_volatility::sabr_funcs::{_sabr_x0, _sabr_x1, _sabr_x2}; pub mod scheduling; use scheduling::{ - Cal, Convention, Frequency, Imm, NamedCal, PyAdjuster, RollDay, Schedule, StubInference, - UnionCal, + Cal, CalendarManager, Convention, Frequency, Imm, NamedCal, PyAdjuster, RollDay, Schedule, + StubInference, UnionCal, }; +pub mod enums; +use enums::{LegIndexBase, PyFloatFixingMethod}; + #[pymodule] fn rs(m: &Bound<'_, PyModule>) -> PyResult<()> { // JSON @@ -83,6 +98,7 @@ fn rs(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_function(wrap_pyfunction!(_get_modifier_str, m)?)?; @@ -103,5 +119,9 @@ fn rs(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(_sabr_x1, m)?)?; m.add_function(wrap_pyfunction!(_sabr_x2, m)?)?; + // Rates and Indexes + m.add_class::()?; + m.add_class::()?; + Ok(()) } diff --git a/rust/main.rs b/rust/main.rs index 360347cb4..3d711bc1c 100644 --- a/rust/main.rs +++ b/rust/main.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use pyo3::prelude::*; use pyo3::types::PyTuple; use rateslib::dual::{Dual, Number, NumberOps}; diff --git a/rust/scheduling/calendars/adjuster.rs b/rust/scheduling/calendars/adjuster.rs index d074bb5f8..66c71671b 100644 --- a/rust/scheduling/calendars/adjuster.rs +++ b/rust/scheduling/calendars/adjuster.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::scheduling::DateRoll; use chrono::prelude::*; use chrono::Days; diff --git a/rust/scheduling/calendars/cal.rs b/rust/scheduling/calendars/cal.rs index 9829aaee0..ce7c645c4 100644 --- a/rust/scheduling/calendars/cal.rs +++ b/rust/scheduling/calendars/cal.rs @@ -1,15 +1,27 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use chrono::prelude::*; use chrono::Weekday; use indexmap::set::IndexSet; +use pyo3::exceptions::PyKeyError; use pyo3::{pyclass, PyErr}; use serde::{Deserialize, Serialize}; use std::collections::HashSet; -use crate::scheduling::calendars::named::{get_holidays_by_name, get_weekmask_by_name}; -use crate::scheduling::{ndt, CalendarAdjustment, DateRoll, NamedCal, UnionCal}; +use crate::scheduling::{CalWrapper, CalendarAdjustment, CalendarManager, DateRoll}; /// A basic business day calendar containing holidays. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct Cal { /// A vector of specific dates that are defined as **non-business** days. @@ -19,6 +31,22 @@ pub struct Cal { // pub(crate) meta: Vec, } +impl DateRoll for Cal { + fn is_weekday(&self, date: &NaiveDateTime) -> bool { + !self.week_mask.contains(&date.weekday()) + } + + fn is_holiday(&self, date: &NaiveDateTime) -> bool { + self.holidays.contains(date) + } + + fn is_settlement(&self, _date: &NaiveDateTime) -> bool { + true + } +} + +impl CalendarAdjustment for Cal {} + impl Cal { /// Create a [`Cal`]. /// @@ -55,48 +83,14 @@ impl Cal { /// let ldn_cal = Cal::try_from_name("ldn").unwrap(); /// ``` pub fn try_from_name(name: &str) -> Result { - Ok(Cal::new( - get_holidays_by_name(name)?, - get_weekmask_by_name(name)?, - // get_rules_by_name(name)? - )) - } -} - -impl DateRoll for Cal { - fn is_weekday(&self, date: &NaiveDateTime) -> bool { - !self.week_mask.contains(&date.weekday()) - } - - fn is_holiday(&self, date: &NaiveDateTime) -> bool { - self.holidays.contains(date) - } - - fn is_settlement(&self, _date: &NaiveDateTime) -> bool { - true - } -} - -impl CalendarAdjustment for Cal {} - -impl PartialEq for Cal { - fn eq(&self, other: &UnionCal) -> bool { - let cd1 = self - .cal_date_range(&ndt(1970, 1, 1), &ndt(2200, 12, 31)) - .unwrap(); - let cd2 = other - .cal_date_range(&ndt(1970, 1, 1), &ndt(2200, 12, 31)) - .unwrap(); - cd1.iter().zip(cd2.iter()).all(|(x, y)| { - self.is_bus_day(x) == other.is_bus_day(x) - && self.is_settlement(x) == other.is_settlement(y) - }) - } -} - -impl PartialEq for Cal { - fn eq(&self, other: &NamedCal) -> bool { - other.union_cal.eq(self) + let cm = CalendarManager::new(); + let named_cal = cm.get(name)?; + match (*named_cal.inner).clone() { + CalWrapper::Cal(cal) => Ok(cal), + CalWrapper::UnionCal(_) => Err(PyKeyError::new_err( + "`name` was key for a UnionCal not a Cal.", + )), + } } } @@ -104,7 +98,7 @@ impl PartialEq for Cal { #[cfg(test)] mod tests { use super::*; - use crate::scheduling::Adjuster; + use crate::scheduling::{ndt, Adjuster}; fn fixture_hol_cal() -> Cal { let hols = vec![ndt(2015, 9, 5), ndt(2015, 9, 7)]; // Saturday and Monday diff --git a/rust/scheduling/calendars/calendar.rs b/rust/scheduling/calendars/calendar.rs index caafa18e2..be435ddb1 100644 --- a/rust/scheduling/calendars/calendar.rs +++ b/rust/scheduling/calendars/calendar.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use chrono::prelude::*; use pyo3::{FromPyObject, IntoPyObject}; use serde::{Deserialize, Serialize}; diff --git a/rust/scheduling/calendars/dateroll.rs b/rust/scheduling/calendars/dateroll.rs index 3482daf62..243154919 100644 --- a/rust/scheduling/calendars/dateroll.rs +++ b/rust/scheduling/calendars/dateroll.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use chrono::prelude::*; use chrono::Days; use pyo3::exceptions::PyValueError; @@ -231,6 +243,156 @@ pub trait DateRoll { } Ok(vec) } + + /// Print a representation of the month of the object. + fn print_month(&self, year: i32, month: u8) -> String { + let _map: Vec = vec![ + format!(" January {}\n", year), + format!(" February {}\n", year), + format!(" March {}\n", year), + format!(" April {}\n", year), + format!(" May {}\n", year), + format!(" June {}\n", year), + format!(" July {}\n", year), + format!(" August {}\n", year), + format!(" September {}\n", year), + format!(" October {}\n", year), + format!(" November {}\n", year), + format!(" December {}\n", year), + ]; + let mut output = _map[(month - 1) as usize].clone(); + output += "Su Mo Tu We Th Fr Sa\n"; + + let month_obj = Month::try_from(month).unwrap(); + let days: u8 = month_obj.num_days(year).unwrap(); + let weekday = NaiveDate::from_ymd_opt(year, month.into(), 1) + .unwrap() + .weekday() + .num_days_from_monday(); + let idx_start: u32 = (weekday + 1) % 7; + + let mut arr: [String; 42] = std::array::from_fn(|_| String::from(" ")); + for i in 0..days { + let date = NaiveDate::from_ymd_opt(year, month.into(), (i + 1).into()) + .expect("`year`, `month` `day` are invalid.") + .and_hms_opt(0, 0, 0) + .unwrap(); + let s: String = { + if self.is_bus_day(&date) && self.is_settlement(&date) { + format!("{:>2}", i + 1) + } else if self.is_bus_day(&date) && !self.is_settlement(&date) { + " X".to_string() + } else if !self.is_bus_day(&date) + && matches!(date.weekday(), Weekday::Sat | Weekday::Sun) + { + " .".to_string() + } else { + " *".to_string() + } + }; + let index: u32 = i as u32 + idx_start; + arr[index as usize] = s; + } + + for row in 0..6 { + output += &format!( + "{} {} {} {} {} {} {}\n", + &arr[row * 7], + &arr[row * 7 + 1], + &arr[row * 7 + 2], + &arr[row * 7 + 3], + &arr[row * 7 + 4], + &arr[row * 7 + 5], + &arr[row * 7 + 6] + ); + } + output + } + + /// Print a representation of a year of the object. + fn print_year(&self, year: i32) -> String { + let mut data: Vec> = vec![]; + for i in 1..13 { + data.push( + self.print_month(year, i) + .lines() + .map(|s| s.to_string()) + .collect(), + ); + } + let mut output = "\n".to_string(); + for i in 0..8 { + output += &format!( + "{} {} {} {}\n", + data[0][i], data[3][i], data[6][i], data[9][i] + ); + } + for i in 0..8 { + output += &format!( + "{} {} {} {}\n", + data[1][i], data[4][i], data[7][i], data[10][i] + ); + } + for i in 0..8 { + output += &format!( + "{} {} {} {}\n", + data[2][i], data[5][i], data[8][i], data[11][i] + ); + } + output += "Legend:\n"; + output += "'1-31': Settleable business day 'X': Non-settleable business day\n"; + output += " '.': Non-business weekend '*': Non-business day\n"; + output + } + + /// Compare two calendars and highlight differences. + fn print_compare(&self, comparator: &T, year: i32) -> String { + let str1: Vec = self + .print_year(year) + .lines() + .map(|s| s.to_string()) + .collect(); + let str2: Vec = comparator + .print_year(year) + .lines() + .map(|s| s.to_string()) + .collect(); + + let header_row: Vec = vec![0, 1, 2, 9, 10, 17, 18]; + let mut output = "\n".to_string(); + for i in 1..25 { + if header_row.contains(&i) { + output += &str1[i]; + } else { + let row_data: Vec<(char, char)> = str1[i].chars().zip(str2[i].chars()).collect(); + for m in 0..4 { + let m_ = m * 23; + if m > 0 { + output += " "; + } + for c in 0..7 { + let c_ = c * 3 + m_; + if c_ > 89 { + continue; + } + if row_data[c_].0 == row_data[c_].1 + && row_data[c_ + 1].0 == row_data[c_ + 1].1 + { + if row_data[c_].0 == ' ' && row_data[c_ + 1].0 == ' ' { + output += " "; + } else { + output += " _ "; + } + } else { + output += "[] "; + } + } + } + } + output += &"\n"; + } + return output; + } } #[cfg(test)] @@ -489,4 +651,103 @@ mod tests { uni.lag_bus_days(&ndt(2000, 6, 28), 0, true) ); } + + #[test] + fn test_print_month() { + let cal = Cal::new(vec![ndt(2026, 1, 1), ndt(2026, 1, 19)], vec![5, 6]); + let result = cal.print_month(2026, 1); + let raw_output = r#" January 2026 +Su Mo Tu We Th Fr Sa + * 2 . + . 5 6 7 8 9 . + . 12 13 14 15 16 . + . * 20 21 22 23 . + . 26 27 28 29 30 . +$$$$$$$$$$$$$$$$$$$$ +"#; + let expected = raw_output.replace("$", " "); + assert_eq!(result, expected); + } + + #[test] + fn test_print_year() { + let cal = Cal::new(vec![ndt(2026, 1, 1), ndt(2026, 1, 19)], vec![5, 6]); + let result = cal.print_year(2026); + let raw_output = r#" + January 2026 April 2026 July 2026 October 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + * 2 . 1 2 3 . 1 2 3 . 1 2 . + . 5 6 7 8 9 . . 6 7 8 9 10 . . 6 7 8 9 10 . . 5 6 7 8 9 . + . 12 13 14 15 16 . . 13 14 15 16 17 . . 13 14 15 16 17 . . 12 13 14 15 16 . + . * 20 21 22 23 . . 20 21 22 23 24 . . 20 21 22 23 24 . . 19 20 21 22 23 . + . 26 27 28 29 30 . . 27 28 29 30 . 27 28 29 30 31 . 26 27 28 29 30 . +$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + February 2026 May 2026 August 2026 November 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + . 2 3 4 5 6 . 1 . . . 2 3 4 5 6 . + . 9 10 11 12 13 . . 4 5 6 7 8 . . 3 4 5 6 7 . . 9 10 11 12 13 . + . 16 17 18 19 20 . . 11 12 13 14 15 . . 10 11 12 13 14 . . 16 17 18 19 20 . + . 23 24 25 26 27 . . 18 19 20 21 22 . . 17 18 19 20 21 . . 23 24 25 26 27 . + . 25 26 27 28 29 . . 24 25 26 27 28 . . 30$$$$$$$$$$$$$$$ + . . 31$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + March 2026 June 2026 September 2026 December 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + . 2 3 4 5 6 . 1 2 3 4 5 . 1 2 3 4 . 1 2 3 4 . + . 9 10 11 12 13 . . 8 9 10 11 12 . . 7 8 9 10 11 . . 7 8 9 10 11 . + . 16 17 18 19 20 . . 15 16 17 18 19 . . 14 15 16 17 18 . . 14 15 16 17 18 . + . 23 24 25 26 27 . . 22 23 24 25 26 . . 21 22 23 24 25 . . 21 22 23 24 25 . + . 30 31 . 29 30 . 28 29 30 . 28 29 30 31$$$$$$ +$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +Legend: +'1-31': Settleable business day 'X': Non-settleable business day + '.': Non-business weekend '*': Non-business day +"#; + let expected = raw_output.replace("$", " "); + + let result_lines: Vec<&str> = result.lines().collect(); + let expected_lines: Vec<&str> = expected.lines().collect(); + for i in 0..result_lines.len() { + assert_eq!(expected_lines[i], result_lines[i]); + } + } + + #[test] + fn test_print_compare() { + let cal1 = Cal::new(vec![], vec![0, 5]); + let cal2 = Cal::new(vec![], vec![3, 5]); + let result = cal1.print_compare(&cal2, 2026); + let raw_output = r#" + January 2026 April 2026 July 2026 October 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + [] _ _ _ [] _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ [] _ _ [] _ _ [] _ _ [] _ _$ +$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + February 2026 May 2026 August 2026 November 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + _ [] _ _ [] _ _ _ _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ []$$$$$$$$$$$$$$$$ + _ _ []$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + March 2026 June 2026 September 2026 December 2026 +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + _ [] _ _ [] _ _ [] _ _ [] _ _ _ _ [] _ _ _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _ _ [] _ _ [] _ _$ + _ [] _ _ [] _ _ [] _ _ _ [] _ _ []$$$$$$$ +$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +"#; + let expected = raw_output.replace("$", " "); + + let result_lines: Vec<&str> = result.lines().collect(); + let expected_lines: Vec<&str> = expected.lines().collect(); + for i in 0..result_lines.len() { + assert_eq!(expected_lines[i], result_lines[i]); + } + } } diff --git a/rust/scheduling/calendars/manager.rs b/rust/scheduling/calendars/manager.rs new file mode 100644 index 000000000..92af01db2 --- /dev/null +++ b/rust/scheduling/calendars/manager.rs @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + +use crate::scheduling::calendars::named::{HOLIDAYS, WEEKMASKS}; +use crate::scheduling::calendars::{Cal, CalWrapper, Calendar, NamedCal, UnionCal}; +use pyo3::exceptions::{PyKeyError, PyValueError}; +use pyo3::{pyclass, PyErr}; +use std::collections::HashMap; +use std::sync::{Arc, LazyLock, RwLock}; + +// A single memory allocated space to maintain the UnionCal with an associated name. +static NAMED_CALENDARS: LazyLock>>> = LazyLock::new(|| { + let mut m = HashMap::new(); + for (k, _) in WEEKMASKS.iter() { + m.insert( + (*k).into(), + Arc::new(CalWrapper::Cal(Cal::new( + HOLIDAYS.get(k).unwrap().to_vec(), + WEEKMASKS.get(k).unwrap().to_vec(), + ))), + ); + } + RwLock::new(m) +}); + +/// A manager to add and mutate the core calendars from which [`NamedCal`] are constructed. +#[pyclass] +pub struct CalendarManager; + +impl CalendarManager { + /// Create an instance of the [`CalendarManager`] manager. + /// + /// This object interacts with the memory allocation for stored calendars. It returns + /// objects with thread safe, shared memory access to the same objects for performance. + pub fn new() -> Self { + Self {} + } + + /// Returns *true* if the set contains a specific key. + pub fn contains_key(&self, key: &str) -> bool { + let k: String = sort_calendar_names(key); + let r = NAMED_CALENDARS.read().unwrap(); + r.contains_key(&k) + } + + /// Return a list of keys. + pub fn keys(&self) -> Vec { + let r = NAMED_CALENDARS.read().unwrap(); + r.iter().map(|(k, _)| k.to_string()).collect() + } + + /// Add any [`Calendar`] to the calendar manager. + /// + /// Data will not be overwritten. It will error prior to that or clone existing data to a + /// new key. + pub fn add(&self, name: &str, calendar: Cal) -> Result<(), PyErr> { + let k: String = sort_calendar_names(name); + if k.chars().any(|c| c == ',' || c == '|') { + return Err(PyValueError::new_err( + " + `name` cannot contain the comma (',') or pipe ('|') characters.\nThese are reserved + to define calendar combinations (i.e. UnionCal) and only Cal objects are allowed to be + populated directly to the calendar manager.", + )); + } + + let mut w = NAMED_CALENDARS.write().unwrap(); + if w.contains_key(&k) { + return Err(PyKeyError::new_err( + "`name` already exists in calendars. + Cannot overwrite, first `pop` the existing calendar.", + )); + } + w.insert(k, Arc::new(CalWrapper::Cal(calendar))); + Ok(()) + } + + /// Remove an existing [`Calendar`] from the calendar manager. + pub fn pop(&self, name: &str) -> Result { + let k: String = sort_calendar_names(name); + let popped = remove_any_calendar(&k); + match popped { + Some(arc) => match &*arc { + CalWrapper::Cal(c) => { + remove_all_combinations(&k); + Ok(Calendar::Cal(c.clone())) + } + CalWrapper::UnionCal(c) => Ok(Calendar::UnionCal(c.clone())), + }, + None => Err(PyKeyError::new_err("`name` does not exist in calendars.")), + } + } + + /// Return a [`NamedCal`] matching the name that is stored in the calendar manager. + /// + /// If the name as a key does not exist then an error will result. + pub fn get(&self, name: &str) -> Result { + let k: String = sort_calendar_names(name); + let r = NAMED_CALENDARS.read().unwrap(); + let v = r.get(&k); + match v { + Some(arc_ref) => Ok(NamedCal { + name: k, + inner: arc_ref.clone(), + }), + None => Err(PyKeyError::new_err("`name` does not exist in calendars.")), + } + } + + /// Return a [`NamedCal`] matching the name that is stored in the calendar manager. + /// + /// If the name as a key does not exist but a [`UnionCal`] as a combination of [`Cal`] can + /// be created, the HashMap will be updated with a new entry and the relevant [`NamedCal`] + /// returned. + pub fn get_with_insert(&self, name: &str) -> Result { + let k: String = sort_calendar_names(name); + if !k.chars().any(|c| c == ',' || c == '|') { + // then lookup is for a single calendar, no composition necessary + self.get(&k) + } else { + let item = self.get(&k); + match item { + Ok(value) => Ok(value), // key is found pre-populated in HashMap + Err(_) => { + // then the calendars might need to be composited and inserted + let data = extract_individual_calendars(&k)?; + let _ = insert_union_cal( + &k, + UnionCal { + calendars: data.0, + settlement_calendars: data.1, + }, + ); + self.get(&k) + } + } + } + } +} + +// Take an input string (potentially with comma and pipe) and convert to lower case and +// order the specific calendar names. See test_sort_calendar_names. +fn sort_calendar_names(name: &str) -> String { + let stripped: String = name.chars().filter(|c| !c.is_whitespace()).collect(); + let parts: Vec = stripped + .to_lowercase() + .split("|") + .map(String::from) + .collect(); + let mut reordered_parts: Vec = Vec::new(); + for part in parts { + let mut cals: Vec = part.split(",").map(String::from).collect(); + cals.sort(); + reordered_parts.push(cals.join(",")) + } + reordered_parts.join("|") +} + +// Take an input string (potentially with comma and pipe) and extract the ordered list +// of individual, expected [`Cal`] objects. `k` is expected to be cleaned (sorted, lowercase etc.) +fn extract_individual_calendars(k: &str) -> Result<(Vec, Option>), PyErr> { + let nc = CalendarManager::new(); + let parts: Vec = k.split("|").map(String::from).collect(); + let mut container: Vec> = Vec::new(); + for part in &parts { + let cal_names: Vec = part.split(",").map(String::from).collect(); + + let named_cals: Vec = cal_names + .iter() + .map(|k| nc.get(k)) + .collect::, _>>()?; + + let cals: Vec = named_cals + .iter() + .map(|n| match &*n.inner { + CalWrapper::Cal(value) => Ok(value.clone()), + _ => Err(PyValueError::new_err( + "Individual calendar name is not a Cal object.", + )), + }) + .collect::, _>>()?; + + container.push(cals); + } + if container.len() == 1 { + Ok((container[0].clone(), None)) + } else if parts.len() == 2 { + Ok((container[0].clone(), Some(container[1].clone()))) + } else { + Err(PyValueError::new_err( + "The calendar cannot be parsed. Is there more than one pipe character?", + )) + } +} + +// Insert a named calendar to the HashMap +fn insert_union_cal(k: &str, u: UnionCal) -> Option> { + // returns None when inserted correctly + let mut w = NAMED_CALENDARS.write().unwrap(); + w.insert(k.to_string(), Arc::new(CalWrapper::UnionCal(u))) +} + +// Remove a key and return the object +fn remove_any_calendar(k: &str) -> Option> { + let mut w = NAMED_CALENDARS.write().unwrap(); + w.remove(&k.to_string()) +} + +// Remove all other combinations that is a UnionCal and contains the name 'k'. +fn remove_all_combinations(k: &str) -> () { + let mut w = NAMED_CALENDARS.write().unwrap(); + let keys: Vec = w + .iter() + .filter(|(key, v)| key.contains(k) && is_union_cal((*v).clone())) + .map(|(key, _)| key.to_string()) + .collect(); + for key in keys.into_iter() { + let _ = w.remove(&key); + } +} + +fn is_union_cal(v: Arc) -> bool { + match *v { + CalWrapper::Cal(_) => false, + CalWrapper::UnionCal(_) => true, + } +} + +// UNIT TESTS +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sort_calendar_names() { + let result = sort_calendar_names("tgt,NYC, ldn|tyo, tro"); + assert_eq!(result, "ldn,nyc,tgt|tro,tyo"); + + let result = sort_calendar_names("tgt,NYC, ldn|tyo"); + assert_eq!(result, "ldn,nyc,tgt|tyo"); + + let result = sort_calendar_names("tgt,NYC, ldn "); + assert_eq!(result, "ldn,nyc,tgt"); + + let result = sort_calendar_names("tgt|ldn "); + assert_eq!(result, "tgt|ldn"); + + let result = sort_calendar_names("tgt "); + assert_eq!(result, "tgt"); + + let result = sort_calendar_names("a2, a1 | a3 "); + assert_eq!(result, "a1,a2|a3"); + } + + #[test] + fn test_extract_individual_calendars() { + let nc = CalendarManager::new(); + let result = extract_individual_calendars("ldn").unwrap(); + let expected = nc.get("ldn").unwrap(); + assert_eq!(result.0[0], expected); + + let a1 = Cal::new(vec![], vec![1]); + let a2 = Cal::new(vec![], vec![2]); + let a3 = Cal::new(vec![], vec![3]); + let _ = nc.add("a1", a1); + let _ = nc.add("a2", a2); + let _ = nc.add("a3", a3); + + let result = extract_individual_calendars("a2, a1 | a3").unwrap(); + let expected = ( + vec![Cal::new(vec![], vec![2]), Cal::new(vec![], vec![1])], + Some(vec![Cal::new(vec![], vec![3])]), + ); + assert_eq!(result, expected) + } + + #[test] + fn test_get_with_insert() { + let nc = CalendarManager::new(); + let result = nc.get_with_insert("ldn").unwrap(); + let result2 = nc.get("ldn").unwrap(); + assert_eq!(result, result2); + assert!(Arc::ptr_eq(&result.inner, &result2.inner)); + } + + #[test] + fn test_get_with_insert_composite() { + let nc = CalendarManager::new(); + let result = nc.get_with_insert("ldn,tgt").unwrap(); + let result2 = nc.get("ldn,tgt").unwrap(); + let result3 = nc.get("tgt,ldn").unwrap(); + assert_eq!(result, result2); + assert!(Arc::ptr_eq(&result.inner, &result2.inner)); + assert_eq!(result, result3); + assert!(Arc::ptr_eq(&result.inner, &result3.inner)); + } + + #[test] + fn test_remove_composites_calendars() { + let nc = CalendarManager::new(); + + let a1 = Cal::new(vec![], vec![1]); + let a2 = Cal::new(vec![], vec![2]); + let a3 = Cal::new(vec![], vec![3]); + let _ = nc.add("a1", a1); + let _ = nc.add("a2", a2); + let _ = nc.add("a3", a3); + let _ = nc.get_with_insert("a1,a2"); + let _ = nc.get_with_insert("a1,a3"); + let _ = nc.get_with_insert("a2,a3"); + let _ = nc.get_with_insert("a1,a2,a3"); + + let _ = nc.pop("a1"); + assert!(!nc.keys().contains(&"a1,a2".to_string())); + assert!(!nc.keys().contains(&"a1,a3".to_string())); + assert!(nc.keys().contains(&"a2,a3".to_string())); + assert!(!nc.keys().contains(&"a1,a2,a3".to_string())); + } +} diff --git a/rust/scheduling/calendars/mod.rs b/rust/scheduling/calendars/mod.rs index d58fd407f..1faf62c93 100644 --- a/rust/scheduling/calendars/mod.rs +++ b/rust/scheduling/calendars/mod.rs @@ -1,7 +1,20 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + mod adjuster; mod cal; mod calendar; mod dateroll; +mod manager; mod named; mod named_cal; mod union_cal; @@ -11,6 +24,36 @@ pub use crate::scheduling::calendars::{ cal::Cal, calendar::{ndt, Calendar}, dateroll::DateRoll, + manager::CalendarManager, named_cal::NamedCal, union_cal::UnionCal, }; + +pub(crate) use crate::scheduling::calendars::named_cal::CalWrapper; + +macro_rules! impl_date_roll_partial_eq { + ($t1:ty, $t2:ty) => { + // Implement T1 == T2 + impl PartialEq<$t2> for $t1 { + fn eq(&self, other: &$t2) -> bool { + let c = self + .cal_date_range(&ndt(1970, 1, 1), &ndt(2200, 12, 31)) + .unwrap(); + c.iter().all(|d| { + self.is_bus_day(d) == other.is_bus_day(d) + && self.is_settlement(d) == other.is_settlement(d) + }) + } + } + }; +} + +// Usage: Just list the pairs you want to support +impl_date_roll_partial_eq!(Cal, UnionCal); +impl_date_roll_partial_eq!(Cal, NamedCal); +impl_date_roll_partial_eq!(UnionCal, Cal); +impl_date_roll_partial_eq!(UnionCal, UnionCal); +impl_date_roll_partial_eq!(UnionCal, NamedCal); +impl_date_roll_partial_eq!(NamedCal, Cal); +impl_date_roll_partial_eq!(NamedCal, UnionCal); +impl_date_roll_partial_eq!(NamedCal, NamedCal); diff --git a/rust/scheduling/calendars/named/all.rs b/rust/scheduling/calendars/named/all.rs index d578daba3..b04125a5b 100644 --- a/rust/scheduling/calendars/named/all.rs +++ b/rust/scheduling/calendars/named/all.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a calendar which asserts every possible date as a business day. pub const WEEKMASK: &[u8] = &[]; // all days are weekdays diff --git a/rust/scheduling/calendars/named/bjs.rs b/rust/scheduling/calendars/named/bjs.rs new file mode 100644 index 000000000..268d6cd5b --- /dev/null +++ b/rust/scheduling/calendars/named/bjs.rs @@ -0,0 +1,17303 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//! Define a Chinese Interbank business day calendar, + +pub const WEEKMASK: &[u8] = &[]; // Saturday and Sunday weekend are added specifically as holidays + +// pub const RULES: &[&str] = &[ +// "Jan 1 (New Year)", +// "Jan 2 (New Year)", +// "Jan 3 (New Year)", +// "Jan 2nd Mon (Coming-of-Age)", +// "Feb 11: Sun->Mon (Foundation)", +// "Feb 23: Sun->Mon (Emperor Naruhito Birthday est. 2020)", +// "Mar 20/21: Sun->Mon (Vernal Equinox)", +// "Apr 29: Sun->Mon (Showa)", +// "May 3: Sun->Mon (Constitution)", +// "May 4: Sun->Mon->Tue (Greenery)", +// "May 5: Sun->Mon->Tue->Wed (Children)", +// "Jul 3rd Mon (Marine)", +// "Aug 11: Sun->Mon (Mountain est. 2016)", +// "Sep 3rd Mon (Respect Aged)", +// "Sep 22/23: Sun->Mon (Autumn Equinox)", +// "Oct 2nd Mon (Sports)", +// "Nov 3: Sun->Mon (Culture)", +// "Nov 23: Sun->Mon (Labor Thanksgiving)", +// "Dec 23: Sun->Mon (Emperor Akihito Birthday end. 2019)", +// "Dec 31 (New Year)", +// "Note: 2020 Olympics adjustments.", +// ]; + +pub const HOLIDAYS: &[&str] = &[ + "1970-01-03 00:00:00", + "1970-01-04 00:00:00", + "1970-01-10 00:00:00", + "1970-01-11 00:00:00", + "1970-01-17 00:00:00", + "1970-01-18 00:00:00", + "1970-01-24 00:00:00", + "1970-01-25 00:00:00", + "1970-01-31 00:00:00", + "1970-02-01 00:00:00", + "1970-02-07 00:00:00", + "1970-02-08 00:00:00", + "1970-02-14 00:00:00", + "1970-02-15 00:00:00", + "1970-02-21 00:00:00", + "1970-02-22 00:00:00", + "1970-02-28 00:00:00", + "1970-03-01 00:00:00", + "1970-03-07 00:00:00", + "1970-03-08 00:00:00", + "1970-03-14 00:00:00", + "1970-03-15 00:00:00", + "1970-03-21 00:00:00", + "1970-03-22 00:00:00", + "1970-03-28 00:00:00", + "1970-03-29 00:00:00", + "1970-04-04 00:00:00", + "1970-04-05 00:00:00", + "1970-04-11 00:00:00", + "1970-04-12 00:00:00", + "1970-04-18 00:00:00", + "1970-04-19 00:00:00", + "1970-04-25 00:00:00", + "1970-04-26 00:00:00", + "1970-05-02 00:00:00", + "1970-05-03 00:00:00", + "1970-05-09 00:00:00", + "1970-05-10 00:00:00", + "1970-05-16 00:00:00", + "1970-05-17 00:00:00", + "1970-05-23 00:00:00", + "1970-05-24 00:00:00", + "1970-05-30 00:00:00", + "1970-05-31 00:00:00", + "1970-06-06 00:00:00", + "1970-06-07 00:00:00", + "1970-06-13 00:00:00", + "1970-06-14 00:00:00", + "1970-06-20 00:00:00", + "1970-06-21 00:00:00", + "1970-06-27 00:00:00", + "1970-06-28 00:00:00", + "1970-07-04 00:00:00", + "1970-07-05 00:00:00", + "1970-07-11 00:00:00", + "1970-07-12 00:00:00", + "1970-07-18 00:00:00", + "1970-07-19 00:00:00", + "1970-07-25 00:00:00", + "1970-07-26 00:00:00", + "1970-08-01 00:00:00", + "1970-08-02 00:00:00", + "1970-08-08 00:00:00", + "1970-08-09 00:00:00", + "1970-08-15 00:00:00", + "1970-08-16 00:00:00", + "1970-08-22 00:00:00", + "1970-08-23 00:00:00", + "1970-08-29 00:00:00", + "1970-08-30 00:00:00", + "1970-09-05 00:00:00", + "1970-09-06 00:00:00", + "1970-09-12 00:00:00", + "1970-09-13 00:00:00", + "1970-09-19 00:00:00", + "1970-09-20 00:00:00", + "1970-09-26 00:00:00", + "1970-09-27 00:00:00", + "1970-10-03 00:00:00", + "1970-10-04 00:00:00", + "1970-10-10 00:00:00", + "1970-10-11 00:00:00", + "1970-10-17 00:00:00", + "1970-10-18 00:00:00", + "1970-10-24 00:00:00", + "1970-10-25 00:00:00", + "1970-10-31 00:00:00", + "1970-11-01 00:00:00", + "1970-11-07 00:00:00", + "1970-11-08 00:00:00", + "1970-11-14 00:00:00", + "1970-11-15 00:00:00", + "1970-11-21 00:00:00", + "1970-11-22 00:00:00", + "1970-11-28 00:00:00", + "1970-11-29 00:00:00", + "1970-12-05 00:00:00", + "1970-12-06 00:00:00", + "1970-12-12 00:00:00", + "1970-12-13 00:00:00", + "1970-12-19 00:00:00", + "1970-12-20 00:00:00", + "1970-12-26 00:00:00", + "1970-12-27 00:00:00", + "1971-01-02 00:00:00", + "1971-01-03 00:00:00", + "1971-01-09 00:00:00", + "1971-01-10 00:00:00", + "1971-01-16 00:00:00", + "1971-01-17 00:00:00", + "1971-01-23 00:00:00", + "1971-01-24 00:00:00", + "1971-01-30 00:00:00", + "1971-01-31 00:00:00", + "1971-02-06 00:00:00", + "1971-02-07 00:00:00", + "1971-02-13 00:00:00", + "1971-02-14 00:00:00", + "1971-02-20 00:00:00", + "1971-02-21 00:00:00", + "1971-02-27 00:00:00", + "1971-02-28 00:00:00", + "1971-03-06 00:00:00", + "1971-03-07 00:00:00", + "1971-03-13 00:00:00", + "1971-03-14 00:00:00", + "1971-03-20 00:00:00", + "1971-03-21 00:00:00", + "1971-03-27 00:00:00", + "1971-03-28 00:00:00", + "1971-04-03 00:00:00", + "1971-04-04 00:00:00", + "1971-04-10 00:00:00", + "1971-04-11 00:00:00", + "1971-04-17 00:00:00", + "1971-04-18 00:00:00", + "1971-04-24 00:00:00", + "1971-04-25 00:00:00", + "1971-05-01 00:00:00", + "1971-05-02 00:00:00", + "1971-05-08 00:00:00", + "1971-05-09 00:00:00", + "1971-05-15 00:00:00", + "1971-05-16 00:00:00", + "1971-05-22 00:00:00", + "1971-05-23 00:00:00", + "1971-05-29 00:00:00", + "1971-05-30 00:00:00", + "1971-06-05 00:00:00", + "1971-06-06 00:00:00", + "1971-06-12 00:00:00", + "1971-06-13 00:00:00", + "1971-06-19 00:00:00", + "1971-06-20 00:00:00", + "1971-06-26 00:00:00", + "1971-06-27 00:00:00", + "1971-07-03 00:00:00", + "1971-07-04 00:00:00", + "1971-07-10 00:00:00", + "1971-07-11 00:00:00", + "1971-07-17 00:00:00", + "1971-07-18 00:00:00", + "1971-07-24 00:00:00", + "1971-07-25 00:00:00", + "1971-07-31 00:00:00", + "1971-08-01 00:00:00", + "1971-08-07 00:00:00", + "1971-08-08 00:00:00", + "1971-08-14 00:00:00", + "1971-08-15 00:00:00", + "1971-08-21 00:00:00", + "1971-08-22 00:00:00", + "1971-08-28 00:00:00", + "1971-08-29 00:00:00", + "1971-09-04 00:00:00", + "1971-09-05 00:00:00", + "1971-09-11 00:00:00", + "1971-09-12 00:00:00", + "1971-09-18 00:00:00", + "1971-09-19 00:00:00", + "1971-09-25 00:00:00", + "1971-09-26 00:00:00", + "1971-10-02 00:00:00", + "1971-10-03 00:00:00", + "1971-10-09 00:00:00", + "1971-10-10 00:00:00", + "1971-10-16 00:00:00", + "1971-10-17 00:00:00", + "1971-10-23 00:00:00", + "1971-10-24 00:00:00", + "1971-10-30 00:00:00", + "1971-10-31 00:00:00", + "1971-11-06 00:00:00", + "1971-11-07 00:00:00", + "1971-11-13 00:00:00", + "1971-11-14 00:00:00", + "1971-11-20 00:00:00", + "1971-11-21 00:00:00", + "1971-11-27 00:00:00", + "1971-11-28 00:00:00", + "1971-12-04 00:00:00", + "1971-12-05 00:00:00", + "1971-12-11 00:00:00", + "1971-12-12 00:00:00", + "1971-12-18 00:00:00", + "1971-12-19 00:00:00", + "1971-12-25 00:00:00", + "1971-12-26 00:00:00", + "1972-01-01 00:00:00", + "1972-01-02 00:00:00", + "1972-01-08 00:00:00", + "1972-01-09 00:00:00", + "1972-01-15 00:00:00", + "1972-01-16 00:00:00", + "1972-01-22 00:00:00", + "1972-01-23 00:00:00", + "1972-01-29 00:00:00", + "1972-01-30 00:00:00", + "1972-02-05 00:00:00", + "1972-02-06 00:00:00", + "1972-02-12 00:00:00", + "1972-02-13 00:00:00", + "1972-02-19 00:00:00", + "1972-02-20 00:00:00", + "1972-02-26 00:00:00", + "1972-02-27 00:00:00", + "1972-03-04 00:00:00", + "1972-03-05 00:00:00", + "1972-03-11 00:00:00", + "1972-03-12 00:00:00", + "1972-03-18 00:00:00", + "1972-03-19 00:00:00", + "1972-03-25 00:00:00", + "1972-03-26 00:00:00", + "1972-04-01 00:00:00", + "1972-04-02 00:00:00", + "1972-04-08 00:00:00", + "1972-04-09 00:00:00", + "1972-04-15 00:00:00", + "1972-04-16 00:00:00", + "1972-04-22 00:00:00", + "1972-04-23 00:00:00", + "1972-04-29 00:00:00", + "1972-04-30 00:00:00", + "1972-05-06 00:00:00", + "1972-05-07 00:00:00", + "1972-05-13 00:00:00", + "1972-05-14 00:00:00", + "1972-05-20 00:00:00", + "1972-05-21 00:00:00", + "1972-05-27 00:00:00", + "1972-05-28 00:00:00", + "1972-06-03 00:00:00", + "1972-06-04 00:00:00", + "1972-06-10 00:00:00", + "1972-06-11 00:00:00", + "1972-06-17 00:00:00", + "1972-06-18 00:00:00", + "1972-06-24 00:00:00", + "1972-06-25 00:00:00", + "1972-07-01 00:00:00", + "1972-07-02 00:00:00", + "1972-07-08 00:00:00", + "1972-07-09 00:00:00", + "1972-07-15 00:00:00", + "1972-07-16 00:00:00", + "1972-07-22 00:00:00", + "1972-07-23 00:00:00", + "1972-07-29 00:00:00", + "1972-07-30 00:00:00", + "1972-08-05 00:00:00", + "1972-08-06 00:00:00", + "1972-08-12 00:00:00", + "1972-08-13 00:00:00", + "1972-08-19 00:00:00", + "1972-08-20 00:00:00", + "1972-08-26 00:00:00", + "1972-08-27 00:00:00", + "1972-09-02 00:00:00", + "1972-09-03 00:00:00", + "1972-09-09 00:00:00", + "1972-09-10 00:00:00", + "1972-09-16 00:00:00", + "1972-09-17 00:00:00", + "1972-09-23 00:00:00", + "1972-09-24 00:00:00", + "1972-09-30 00:00:00", + "1972-10-01 00:00:00", + "1972-10-07 00:00:00", + "1972-10-08 00:00:00", + "1972-10-14 00:00:00", + "1972-10-15 00:00:00", + "1972-10-21 00:00:00", + "1972-10-22 00:00:00", + "1972-10-28 00:00:00", + "1972-10-29 00:00:00", + "1972-11-04 00:00:00", + "1972-11-05 00:00:00", + "1972-11-11 00:00:00", + "1972-11-12 00:00:00", + "1972-11-18 00:00:00", + "1972-11-19 00:00:00", + "1972-11-25 00:00:00", + "1972-11-26 00:00:00", + "1972-12-02 00:00:00", + "1972-12-03 00:00:00", + "1972-12-09 00:00:00", + "1972-12-10 00:00:00", + "1972-12-16 00:00:00", + "1972-12-17 00:00:00", + "1972-12-23 00:00:00", + "1972-12-24 00:00:00", + "1972-12-30 00:00:00", + "1972-12-31 00:00:00", + "1973-01-06 00:00:00", + "1973-01-07 00:00:00", + "1973-01-13 00:00:00", + "1973-01-14 00:00:00", + "1973-01-20 00:00:00", + "1973-01-21 00:00:00", + "1973-01-27 00:00:00", + "1973-01-28 00:00:00", + "1973-02-03 00:00:00", + "1973-02-04 00:00:00", + "1973-02-10 00:00:00", + "1973-02-11 00:00:00", + "1973-02-17 00:00:00", + "1973-02-18 00:00:00", + "1973-02-24 00:00:00", + "1973-02-25 00:00:00", + "1973-03-03 00:00:00", + "1973-03-04 00:00:00", + "1973-03-10 00:00:00", + "1973-03-11 00:00:00", + "1973-03-17 00:00:00", + "1973-03-18 00:00:00", + "1973-03-24 00:00:00", + "1973-03-25 00:00:00", + "1973-03-31 00:00:00", + "1973-04-01 00:00:00", + "1973-04-07 00:00:00", + "1973-04-08 00:00:00", + "1973-04-14 00:00:00", + "1973-04-15 00:00:00", + "1973-04-21 00:00:00", + "1973-04-22 00:00:00", + "1973-04-28 00:00:00", + "1973-04-29 00:00:00", + "1973-05-05 00:00:00", + "1973-05-06 00:00:00", + "1973-05-12 00:00:00", + "1973-05-13 00:00:00", + "1973-05-19 00:00:00", + "1973-05-20 00:00:00", + "1973-05-26 00:00:00", + "1973-05-27 00:00:00", + "1973-06-02 00:00:00", + "1973-06-03 00:00:00", + "1973-06-09 00:00:00", + "1973-06-10 00:00:00", + "1973-06-16 00:00:00", + "1973-06-17 00:00:00", + "1973-06-23 00:00:00", + "1973-06-24 00:00:00", + "1973-06-30 00:00:00", + "1973-07-01 00:00:00", + "1973-07-07 00:00:00", + "1973-07-08 00:00:00", + "1973-07-14 00:00:00", + "1973-07-15 00:00:00", + "1973-07-21 00:00:00", + "1973-07-22 00:00:00", + "1973-07-28 00:00:00", + "1973-07-29 00:00:00", + "1973-08-04 00:00:00", + "1973-08-05 00:00:00", + "1973-08-11 00:00:00", + "1973-08-12 00:00:00", + "1973-08-18 00:00:00", + "1973-08-19 00:00:00", + "1973-08-25 00:00:00", + "1973-08-26 00:00:00", + "1973-09-01 00:00:00", + "1973-09-02 00:00:00", + "1973-09-08 00:00:00", + "1973-09-09 00:00:00", + "1973-09-15 00:00:00", + "1973-09-16 00:00:00", + "1973-09-22 00:00:00", + "1973-09-23 00:00:00", + "1973-09-29 00:00:00", + "1973-09-30 00:00:00", + "1973-10-06 00:00:00", + "1973-10-07 00:00:00", + "1973-10-13 00:00:00", + "1973-10-14 00:00:00", + "1973-10-20 00:00:00", + "1973-10-21 00:00:00", + "1973-10-27 00:00:00", + "1973-10-28 00:00:00", + "1973-11-03 00:00:00", + "1973-11-04 00:00:00", + "1973-11-10 00:00:00", + "1973-11-11 00:00:00", + "1973-11-17 00:00:00", + "1973-11-18 00:00:00", + "1973-11-24 00:00:00", + "1973-11-25 00:00:00", + "1973-12-01 00:00:00", + "1973-12-02 00:00:00", + "1973-12-08 00:00:00", + "1973-12-09 00:00:00", + "1973-12-15 00:00:00", + "1973-12-16 00:00:00", + "1973-12-22 00:00:00", + "1973-12-23 00:00:00", + "1973-12-29 00:00:00", + "1973-12-30 00:00:00", + "1974-01-05 00:00:00", + "1974-01-06 00:00:00", + "1974-01-12 00:00:00", + "1974-01-13 00:00:00", + "1974-01-19 00:00:00", + "1974-01-20 00:00:00", + "1974-01-26 00:00:00", + "1974-01-27 00:00:00", + "1974-02-02 00:00:00", + "1974-02-03 00:00:00", + "1974-02-09 00:00:00", + "1974-02-10 00:00:00", + "1974-02-16 00:00:00", + "1974-02-17 00:00:00", + "1974-02-23 00:00:00", + "1974-02-24 00:00:00", + "1974-03-02 00:00:00", + "1974-03-03 00:00:00", + "1974-03-09 00:00:00", + "1974-03-10 00:00:00", + "1974-03-16 00:00:00", + "1974-03-17 00:00:00", + "1974-03-23 00:00:00", + "1974-03-24 00:00:00", + "1974-03-30 00:00:00", + "1974-03-31 00:00:00", + "1974-04-06 00:00:00", + "1974-04-07 00:00:00", + "1974-04-13 00:00:00", + "1974-04-14 00:00:00", + "1974-04-20 00:00:00", + "1974-04-21 00:00:00", + "1974-04-27 00:00:00", + "1974-04-28 00:00:00", + "1974-05-04 00:00:00", + "1974-05-05 00:00:00", + "1974-05-11 00:00:00", + "1974-05-12 00:00:00", + "1974-05-18 00:00:00", + "1974-05-19 00:00:00", + "1974-05-25 00:00:00", + "1974-05-26 00:00:00", + "1974-06-01 00:00:00", + "1974-06-02 00:00:00", + "1974-06-08 00:00:00", + "1974-06-09 00:00:00", + "1974-06-15 00:00:00", + "1974-06-16 00:00:00", + "1974-06-22 00:00:00", + "1974-06-23 00:00:00", + "1974-06-29 00:00:00", + "1974-06-30 00:00:00", + "1974-07-06 00:00:00", + "1974-07-07 00:00:00", + "1974-07-13 00:00:00", + "1974-07-14 00:00:00", + "1974-07-20 00:00:00", + "1974-07-21 00:00:00", + "1974-07-27 00:00:00", + "1974-07-28 00:00:00", + "1974-08-03 00:00:00", + "1974-08-04 00:00:00", + "1974-08-10 00:00:00", + "1974-08-11 00:00:00", + "1974-08-17 00:00:00", + "1974-08-18 00:00:00", + "1974-08-24 00:00:00", + "1974-08-25 00:00:00", + "1974-08-31 00:00:00", + "1974-09-01 00:00:00", + "1974-09-07 00:00:00", + "1974-09-08 00:00:00", + "1974-09-14 00:00:00", + "1974-09-15 00:00:00", + "1974-09-21 00:00:00", + "1974-09-22 00:00:00", + "1974-09-28 00:00:00", + "1974-09-29 00:00:00", + "1974-10-05 00:00:00", + "1974-10-06 00:00:00", + "1974-10-12 00:00:00", + "1974-10-13 00:00:00", + "1974-10-19 00:00:00", + "1974-10-20 00:00:00", + "1974-10-26 00:00:00", + "1974-10-27 00:00:00", + "1974-11-02 00:00:00", + "1974-11-03 00:00:00", + "1974-11-09 00:00:00", + "1974-11-10 00:00:00", + "1974-11-16 00:00:00", + "1974-11-17 00:00:00", + "1974-11-23 00:00:00", + "1974-11-24 00:00:00", + "1974-11-30 00:00:00", + "1974-12-01 00:00:00", + "1974-12-07 00:00:00", + "1974-12-08 00:00:00", + "1974-12-14 00:00:00", + "1974-12-15 00:00:00", + "1974-12-21 00:00:00", + "1974-12-22 00:00:00", + "1974-12-28 00:00:00", + "1974-12-29 00:00:00", + "1975-01-04 00:00:00", + "1975-01-05 00:00:00", + "1975-01-11 00:00:00", + "1975-01-12 00:00:00", + "1975-01-18 00:00:00", + "1975-01-19 00:00:00", + "1975-01-25 00:00:00", + "1975-01-26 00:00:00", + "1975-02-01 00:00:00", + "1975-02-02 00:00:00", + "1975-02-08 00:00:00", + "1975-02-09 00:00:00", + "1975-02-15 00:00:00", + "1975-02-16 00:00:00", + "1975-02-22 00:00:00", + "1975-02-23 00:00:00", + "1975-03-01 00:00:00", + "1975-03-02 00:00:00", + "1975-03-08 00:00:00", + "1975-03-09 00:00:00", + "1975-03-15 00:00:00", + "1975-03-16 00:00:00", + "1975-03-22 00:00:00", + "1975-03-23 00:00:00", + "1975-03-29 00:00:00", + "1975-03-30 00:00:00", + "1975-04-05 00:00:00", + "1975-04-06 00:00:00", + "1975-04-12 00:00:00", + "1975-04-13 00:00:00", + "1975-04-19 00:00:00", + "1975-04-20 00:00:00", + "1975-04-26 00:00:00", + "1975-04-27 00:00:00", + "1975-05-03 00:00:00", + "1975-05-04 00:00:00", + "1975-05-10 00:00:00", + "1975-05-11 00:00:00", + "1975-05-17 00:00:00", + "1975-05-18 00:00:00", + "1975-05-24 00:00:00", + "1975-05-25 00:00:00", + "1975-05-31 00:00:00", + "1975-06-01 00:00:00", + "1975-06-07 00:00:00", + "1975-06-08 00:00:00", + "1975-06-14 00:00:00", + "1975-06-15 00:00:00", + "1975-06-21 00:00:00", + "1975-06-22 00:00:00", + "1975-06-28 00:00:00", + "1975-06-29 00:00:00", + "1975-07-05 00:00:00", + "1975-07-06 00:00:00", + "1975-07-12 00:00:00", + "1975-07-13 00:00:00", + "1975-07-19 00:00:00", + "1975-07-20 00:00:00", + "1975-07-26 00:00:00", + "1975-07-27 00:00:00", + "1975-08-02 00:00:00", + "1975-08-03 00:00:00", + "1975-08-09 00:00:00", + "1975-08-10 00:00:00", + "1975-08-16 00:00:00", + "1975-08-17 00:00:00", + "1975-08-23 00:00:00", + "1975-08-24 00:00:00", + "1975-08-30 00:00:00", + "1975-08-31 00:00:00", + "1975-09-06 00:00:00", + "1975-09-07 00:00:00", + "1975-09-13 00:00:00", + "1975-09-14 00:00:00", + "1975-09-20 00:00:00", + "1975-09-21 00:00:00", + "1975-09-27 00:00:00", + "1975-09-28 00:00:00", + "1975-10-04 00:00:00", + "1975-10-05 00:00:00", + "1975-10-11 00:00:00", + "1975-10-12 00:00:00", + "1975-10-18 00:00:00", + "1975-10-19 00:00:00", + "1975-10-25 00:00:00", + "1975-10-26 00:00:00", + "1975-11-01 00:00:00", + "1975-11-02 00:00:00", + "1975-11-08 00:00:00", + "1975-11-09 00:00:00", + "1975-11-15 00:00:00", + "1975-11-16 00:00:00", + "1975-11-22 00:00:00", + "1975-11-23 00:00:00", + "1975-11-29 00:00:00", + "1975-11-30 00:00:00", + "1975-12-06 00:00:00", + "1975-12-07 00:00:00", + "1975-12-13 00:00:00", + "1975-12-14 00:00:00", + "1975-12-20 00:00:00", + "1975-12-21 00:00:00", + "1975-12-27 00:00:00", + "1975-12-28 00:00:00", + "1976-01-03 00:00:00", + "1976-01-04 00:00:00", + "1976-01-10 00:00:00", + "1976-01-11 00:00:00", + "1976-01-17 00:00:00", + "1976-01-18 00:00:00", + "1976-01-24 00:00:00", + "1976-01-25 00:00:00", + "1976-01-31 00:00:00", + "1976-02-01 00:00:00", + "1976-02-07 00:00:00", + "1976-02-08 00:00:00", + "1976-02-14 00:00:00", + "1976-02-15 00:00:00", + "1976-02-21 00:00:00", + "1976-02-22 00:00:00", + "1976-02-28 00:00:00", + "1976-02-29 00:00:00", + "1976-03-06 00:00:00", + "1976-03-07 00:00:00", + "1976-03-13 00:00:00", + "1976-03-14 00:00:00", + "1976-03-20 00:00:00", + "1976-03-21 00:00:00", + "1976-03-27 00:00:00", + "1976-03-28 00:00:00", + "1976-04-03 00:00:00", + "1976-04-04 00:00:00", + "1976-04-10 00:00:00", + "1976-04-11 00:00:00", + "1976-04-17 00:00:00", + "1976-04-18 00:00:00", + "1976-04-24 00:00:00", + "1976-04-25 00:00:00", + "1976-05-01 00:00:00", + "1976-05-02 00:00:00", + "1976-05-08 00:00:00", + "1976-05-09 00:00:00", + "1976-05-15 00:00:00", + "1976-05-16 00:00:00", + "1976-05-22 00:00:00", + "1976-05-23 00:00:00", + "1976-05-29 00:00:00", + "1976-05-30 00:00:00", + "1976-06-05 00:00:00", + "1976-06-06 00:00:00", + "1976-06-12 00:00:00", + "1976-06-13 00:00:00", + "1976-06-19 00:00:00", + "1976-06-20 00:00:00", + "1976-06-26 00:00:00", + "1976-06-27 00:00:00", + "1976-07-03 00:00:00", + "1976-07-04 00:00:00", + "1976-07-10 00:00:00", + "1976-07-11 00:00:00", + "1976-07-17 00:00:00", + "1976-07-18 00:00:00", + "1976-07-24 00:00:00", + "1976-07-25 00:00:00", + "1976-07-31 00:00:00", + "1976-08-01 00:00:00", + "1976-08-07 00:00:00", + "1976-08-08 00:00:00", + "1976-08-14 00:00:00", + "1976-08-15 00:00:00", + "1976-08-21 00:00:00", + "1976-08-22 00:00:00", + "1976-08-28 00:00:00", + "1976-08-29 00:00:00", + "1976-09-04 00:00:00", + "1976-09-05 00:00:00", + "1976-09-11 00:00:00", + "1976-09-12 00:00:00", + "1976-09-18 00:00:00", + "1976-09-19 00:00:00", + "1976-09-25 00:00:00", + "1976-09-26 00:00:00", + "1976-10-02 00:00:00", + "1976-10-03 00:00:00", + "1976-10-09 00:00:00", + "1976-10-10 00:00:00", + "1976-10-16 00:00:00", + "1976-10-17 00:00:00", + "1976-10-23 00:00:00", + "1976-10-24 00:00:00", + "1976-10-30 00:00:00", + "1976-10-31 00:00:00", + "1976-11-06 00:00:00", + "1976-11-07 00:00:00", + "1976-11-13 00:00:00", + "1976-11-14 00:00:00", + "1976-11-20 00:00:00", + "1976-11-21 00:00:00", + "1976-11-27 00:00:00", + "1976-11-28 00:00:00", + "1976-12-04 00:00:00", + "1976-12-05 00:00:00", + "1976-12-11 00:00:00", + "1976-12-12 00:00:00", + "1976-12-18 00:00:00", + "1976-12-19 00:00:00", + "1976-12-25 00:00:00", + "1976-12-26 00:00:00", + "1977-01-01 00:00:00", + "1977-01-02 00:00:00", + "1977-01-08 00:00:00", + "1977-01-09 00:00:00", + "1977-01-15 00:00:00", + "1977-01-16 00:00:00", + "1977-01-22 00:00:00", + "1977-01-23 00:00:00", + "1977-01-29 00:00:00", + "1977-01-30 00:00:00", + "1977-02-05 00:00:00", + "1977-02-06 00:00:00", + "1977-02-12 00:00:00", + "1977-02-13 00:00:00", + "1977-02-19 00:00:00", + "1977-02-20 00:00:00", + "1977-02-26 00:00:00", + "1977-02-27 00:00:00", + "1977-03-05 00:00:00", + "1977-03-06 00:00:00", + "1977-03-12 00:00:00", + "1977-03-13 00:00:00", + "1977-03-19 00:00:00", + "1977-03-20 00:00:00", + "1977-03-26 00:00:00", + "1977-03-27 00:00:00", + "1977-04-02 00:00:00", + "1977-04-03 00:00:00", + "1977-04-09 00:00:00", + "1977-04-10 00:00:00", + "1977-04-16 00:00:00", + "1977-04-17 00:00:00", + "1977-04-23 00:00:00", + "1977-04-24 00:00:00", + "1977-04-30 00:00:00", + "1977-05-01 00:00:00", + "1977-05-07 00:00:00", + "1977-05-08 00:00:00", + "1977-05-14 00:00:00", + "1977-05-15 00:00:00", + "1977-05-21 00:00:00", + "1977-05-22 00:00:00", + "1977-05-28 00:00:00", + "1977-05-29 00:00:00", + "1977-06-04 00:00:00", + "1977-06-05 00:00:00", + "1977-06-11 00:00:00", + "1977-06-12 00:00:00", + "1977-06-18 00:00:00", + "1977-06-19 00:00:00", + "1977-06-25 00:00:00", + "1977-06-26 00:00:00", + "1977-07-02 00:00:00", + "1977-07-03 00:00:00", + "1977-07-09 00:00:00", + "1977-07-10 00:00:00", + "1977-07-16 00:00:00", + "1977-07-17 00:00:00", + "1977-07-23 00:00:00", + "1977-07-24 00:00:00", + "1977-07-30 00:00:00", + "1977-07-31 00:00:00", + "1977-08-06 00:00:00", + "1977-08-07 00:00:00", + "1977-08-13 00:00:00", + "1977-08-14 00:00:00", + "1977-08-20 00:00:00", + "1977-08-21 00:00:00", + "1977-08-27 00:00:00", + "1977-08-28 00:00:00", + "1977-09-03 00:00:00", + "1977-09-04 00:00:00", + "1977-09-10 00:00:00", + "1977-09-11 00:00:00", + "1977-09-17 00:00:00", + "1977-09-18 00:00:00", + "1977-09-24 00:00:00", + "1977-09-25 00:00:00", + "1977-10-01 00:00:00", + "1977-10-02 00:00:00", + "1977-10-08 00:00:00", + "1977-10-09 00:00:00", + "1977-10-15 00:00:00", + "1977-10-16 00:00:00", + "1977-10-22 00:00:00", + "1977-10-23 00:00:00", + "1977-10-29 00:00:00", + "1977-10-30 00:00:00", + "1977-11-05 00:00:00", + "1977-11-06 00:00:00", + "1977-11-12 00:00:00", + "1977-11-13 00:00:00", + "1977-11-19 00:00:00", + "1977-11-20 00:00:00", + "1977-11-26 00:00:00", + "1977-11-27 00:00:00", + "1977-12-03 00:00:00", + "1977-12-04 00:00:00", + "1977-12-10 00:00:00", + "1977-12-11 00:00:00", + "1977-12-17 00:00:00", + "1977-12-18 00:00:00", + "1977-12-24 00:00:00", + "1977-12-25 00:00:00", + "1977-12-31 00:00:00", + "1978-01-01 00:00:00", + "1978-01-07 00:00:00", + "1978-01-08 00:00:00", + "1978-01-14 00:00:00", + "1978-01-15 00:00:00", + "1978-01-21 00:00:00", + "1978-01-22 00:00:00", + "1978-01-28 00:00:00", + "1978-01-29 00:00:00", + "1978-02-04 00:00:00", + "1978-02-05 00:00:00", + "1978-02-11 00:00:00", + "1978-02-12 00:00:00", + "1978-02-18 00:00:00", + "1978-02-19 00:00:00", + "1978-02-25 00:00:00", + "1978-02-26 00:00:00", + "1978-03-04 00:00:00", + "1978-03-05 00:00:00", + "1978-03-11 00:00:00", + "1978-03-12 00:00:00", + "1978-03-18 00:00:00", + "1978-03-19 00:00:00", + "1978-03-25 00:00:00", + "1978-03-26 00:00:00", + "1978-04-01 00:00:00", + "1978-04-02 00:00:00", + "1978-04-08 00:00:00", + "1978-04-09 00:00:00", + "1978-04-15 00:00:00", + "1978-04-16 00:00:00", + "1978-04-22 00:00:00", + "1978-04-23 00:00:00", + "1978-04-29 00:00:00", + "1978-04-30 00:00:00", + "1978-05-06 00:00:00", + "1978-05-07 00:00:00", + "1978-05-13 00:00:00", + "1978-05-14 00:00:00", + "1978-05-20 00:00:00", + "1978-05-21 00:00:00", + "1978-05-27 00:00:00", + "1978-05-28 00:00:00", + "1978-06-03 00:00:00", + "1978-06-04 00:00:00", + "1978-06-10 00:00:00", + "1978-06-11 00:00:00", + "1978-06-17 00:00:00", + "1978-06-18 00:00:00", + "1978-06-24 00:00:00", + "1978-06-25 00:00:00", + "1978-07-01 00:00:00", + "1978-07-02 00:00:00", + "1978-07-08 00:00:00", + "1978-07-09 00:00:00", + "1978-07-15 00:00:00", + "1978-07-16 00:00:00", + "1978-07-22 00:00:00", + "1978-07-23 00:00:00", + "1978-07-29 00:00:00", + "1978-07-30 00:00:00", + "1978-08-05 00:00:00", + "1978-08-06 00:00:00", + "1978-08-12 00:00:00", + "1978-08-13 00:00:00", + "1978-08-19 00:00:00", + "1978-08-20 00:00:00", + "1978-08-26 00:00:00", + "1978-08-27 00:00:00", + "1978-09-02 00:00:00", + "1978-09-03 00:00:00", + "1978-09-09 00:00:00", + "1978-09-10 00:00:00", + "1978-09-16 00:00:00", + "1978-09-17 00:00:00", + "1978-09-23 00:00:00", + "1978-09-24 00:00:00", + "1978-09-30 00:00:00", + "1978-10-01 00:00:00", + "1978-10-07 00:00:00", + "1978-10-08 00:00:00", + "1978-10-14 00:00:00", + "1978-10-15 00:00:00", + "1978-10-21 00:00:00", + "1978-10-22 00:00:00", + "1978-10-28 00:00:00", + "1978-10-29 00:00:00", + "1978-11-04 00:00:00", + "1978-11-05 00:00:00", + "1978-11-11 00:00:00", + "1978-11-12 00:00:00", + "1978-11-18 00:00:00", + "1978-11-19 00:00:00", + "1978-11-25 00:00:00", + "1978-11-26 00:00:00", + "1978-12-02 00:00:00", + "1978-12-03 00:00:00", + "1978-12-09 00:00:00", + "1978-12-10 00:00:00", + "1978-12-16 00:00:00", + "1978-12-17 00:00:00", + "1978-12-23 00:00:00", + "1978-12-24 00:00:00", + "1978-12-30 00:00:00", + "1978-12-31 00:00:00", + "1979-01-06 00:00:00", + "1979-01-07 00:00:00", + "1979-01-13 00:00:00", + "1979-01-14 00:00:00", + "1979-01-20 00:00:00", + "1979-01-21 00:00:00", + "1979-01-27 00:00:00", + "1979-01-28 00:00:00", + "1979-02-03 00:00:00", + "1979-02-04 00:00:00", + "1979-02-10 00:00:00", + "1979-02-11 00:00:00", + "1979-02-17 00:00:00", + "1979-02-18 00:00:00", + "1979-02-24 00:00:00", + "1979-02-25 00:00:00", + "1979-03-03 00:00:00", + "1979-03-04 00:00:00", + "1979-03-10 00:00:00", + "1979-03-11 00:00:00", + "1979-03-17 00:00:00", + "1979-03-18 00:00:00", + "1979-03-24 00:00:00", + "1979-03-25 00:00:00", + "1979-03-31 00:00:00", + "1979-04-01 00:00:00", + "1979-04-07 00:00:00", + "1979-04-08 00:00:00", + "1979-04-14 00:00:00", + "1979-04-15 00:00:00", + "1979-04-21 00:00:00", + "1979-04-22 00:00:00", + "1979-04-28 00:00:00", + "1979-04-29 00:00:00", + "1979-05-05 00:00:00", + "1979-05-06 00:00:00", + "1979-05-12 00:00:00", + "1979-05-13 00:00:00", + "1979-05-19 00:00:00", + "1979-05-20 00:00:00", + "1979-05-26 00:00:00", + "1979-05-27 00:00:00", + "1979-06-02 00:00:00", + "1979-06-03 00:00:00", + "1979-06-09 00:00:00", + "1979-06-10 00:00:00", + "1979-06-16 00:00:00", + "1979-06-17 00:00:00", + "1979-06-23 00:00:00", + "1979-06-24 00:00:00", + "1979-06-30 00:00:00", + "1979-07-01 00:00:00", + "1979-07-07 00:00:00", + "1979-07-08 00:00:00", + "1979-07-14 00:00:00", + "1979-07-15 00:00:00", + "1979-07-21 00:00:00", + "1979-07-22 00:00:00", + "1979-07-28 00:00:00", + "1979-07-29 00:00:00", + "1979-08-04 00:00:00", + "1979-08-05 00:00:00", + "1979-08-11 00:00:00", + "1979-08-12 00:00:00", + "1979-08-18 00:00:00", + "1979-08-19 00:00:00", + "1979-08-25 00:00:00", + "1979-08-26 00:00:00", + "1979-09-01 00:00:00", + "1979-09-02 00:00:00", + "1979-09-08 00:00:00", + "1979-09-09 00:00:00", + "1979-09-15 00:00:00", + "1979-09-16 00:00:00", + "1979-09-22 00:00:00", + "1979-09-23 00:00:00", + "1979-09-29 00:00:00", + "1979-09-30 00:00:00", + "1979-10-06 00:00:00", + "1979-10-07 00:00:00", + "1979-10-13 00:00:00", + "1979-10-14 00:00:00", + "1979-10-20 00:00:00", + "1979-10-21 00:00:00", + "1979-10-27 00:00:00", + "1979-10-28 00:00:00", + "1979-11-03 00:00:00", + "1979-11-04 00:00:00", + "1979-11-10 00:00:00", + "1979-11-11 00:00:00", + "1979-11-17 00:00:00", + "1979-11-18 00:00:00", + "1979-11-24 00:00:00", + "1979-11-25 00:00:00", + "1979-12-01 00:00:00", + "1979-12-02 00:00:00", + "1979-12-08 00:00:00", + "1979-12-09 00:00:00", + "1979-12-15 00:00:00", + "1979-12-16 00:00:00", + "1979-12-22 00:00:00", + "1979-12-23 00:00:00", + "1979-12-29 00:00:00", + "1979-12-30 00:00:00", + "1980-01-05 00:00:00", + "1980-01-06 00:00:00", + "1980-01-12 00:00:00", + "1980-01-13 00:00:00", + "1980-01-19 00:00:00", + "1980-01-20 00:00:00", + "1980-01-26 00:00:00", + "1980-01-27 00:00:00", + "1980-02-02 00:00:00", + "1980-02-03 00:00:00", + "1980-02-09 00:00:00", + "1980-02-10 00:00:00", + "1980-02-16 00:00:00", + "1980-02-17 00:00:00", + "1980-02-23 00:00:00", + "1980-02-24 00:00:00", + "1980-03-01 00:00:00", + "1980-03-02 00:00:00", + "1980-03-08 00:00:00", + "1980-03-09 00:00:00", + "1980-03-15 00:00:00", + "1980-03-16 00:00:00", + "1980-03-22 00:00:00", + "1980-03-23 00:00:00", + "1980-03-29 00:00:00", + "1980-03-30 00:00:00", + "1980-04-05 00:00:00", + "1980-04-06 00:00:00", + "1980-04-12 00:00:00", + "1980-04-13 00:00:00", + "1980-04-19 00:00:00", + "1980-04-20 00:00:00", + "1980-04-26 00:00:00", + "1980-04-27 00:00:00", + "1980-05-03 00:00:00", + "1980-05-04 00:00:00", + "1980-05-10 00:00:00", + "1980-05-11 00:00:00", + "1980-05-17 00:00:00", + "1980-05-18 00:00:00", + "1980-05-24 00:00:00", + "1980-05-25 00:00:00", + "1980-05-31 00:00:00", + "1980-06-01 00:00:00", + "1980-06-07 00:00:00", + "1980-06-08 00:00:00", + "1980-06-14 00:00:00", + "1980-06-15 00:00:00", + "1980-06-21 00:00:00", + "1980-06-22 00:00:00", + "1980-06-28 00:00:00", + "1980-06-29 00:00:00", + "1980-07-05 00:00:00", + "1980-07-06 00:00:00", + "1980-07-12 00:00:00", + "1980-07-13 00:00:00", + "1980-07-19 00:00:00", + "1980-07-20 00:00:00", + "1980-07-26 00:00:00", + "1980-07-27 00:00:00", + "1980-08-02 00:00:00", + "1980-08-03 00:00:00", + "1980-08-09 00:00:00", + "1980-08-10 00:00:00", + "1980-08-16 00:00:00", + "1980-08-17 00:00:00", + "1980-08-23 00:00:00", + "1980-08-24 00:00:00", + "1980-08-30 00:00:00", + "1980-08-31 00:00:00", + "1980-09-06 00:00:00", + "1980-09-07 00:00:00", + "1980-09-13 00:00:00", + "1980-09-14 00:00:00", + "1980-09-20 00:00:00", + "1980-09-21 00:00:00", + "1980-09-27 00:00:00", + "1980-09-28 00:00:00", + "1980-10-04 00:00:00", + "1980-10-05 00:00:00", + "1980-10-11 00:00:00", + "1980-10-12 00:00:00", + "1980-10-18 00:00:00", + "1980-10-19 00:00:00", + "1980-10-25 00:00:00", + "1980-10-26 00:00:00", + "1980-11-01 00:00:00", + "1980-11-02 00:00:00", + "1980-11-08 00:00:00", + "1980-11-09 00:00:00", + "1980-11-15 00:00:00", + "1980-11-16 00:00:00", + "1980-11-22 00:00:00", + "1980-11-23 00:00:00", + "1980-11-29 00:00:00", + "1980-11-30 00:00:00", + "1980-12-06 00:00:00", + "1980-12-07 00:00:00", + "1980-12-13 00:00:00", + "1980-12-14 00:00:00", + "1980-12-20 00:00:00", + "1980-12-21 00:00:00", + "1980-12-27 00:00:00", + "1980-12-28 00:00:00", + "1981-01-03 00:00:00", + "1981-01-04 00:00:00", + "1981-01-10 00:00:00", + "1981-01-11 00:00:00", + "1981-01-17 00:00:00", + "1981-01-18 00:00:00", + "1981-01-24 00:00:00", + "1981-01-25 00:00:00", + "1981-01-31 00:00:00", + "1981-02-01 00:00:00", + "1981-02-07 00:00:00", + "1981-02-08 00:00:00", + "1981-02-14 00:00:00", + "1981-02-15 00:00:00", + "1981-02-21 00:00:00", + "1981-02-22 00:00:00", + "1981-02-28 00:00:00", + "1981-03-01 00:00:00", + "1981-03-07 00:00:00", + "1981-03-08 00:00:00", + "1981-03-14 00:00:00", + "1981-03-15 00:00:00", + "1981-03-21 00:00:00", + "1981-03-22 00:00:00", + "1981-03-28 00:00:00", + "1981-03-29 00:00:00", + "1981-04-04 00:00:00", + "1981-04-05 00:00:00", + "1981-04-11 00:00:00", + "1981-04-12 00:00:00", + "1981-04-18 00:00:00", + "1981-04-19 00:00:00", + "1981-04-25 00:00:00", + "1981-04-26 00:00:00", + "1981-05-02 00:00:00", + "1981-05-03 00:00:00", + "1981-05-09 00:00:00", + "1981-05-10 00:00:00", + "1981-05-16 00:00:00", + "1981-05-17 00:00:00", + "1981-05-23 00:00:00", + "1981-05-24 00:00:00", + "1981-05-30 00:00:00", + "1981-05-31 00:00:00", + "1981-06-06 00:00:00", + "1981-06-07 00:00:00", + "1981-06-13 00:00:00", + "1981-06-14 00:00:00", + "1981-06-20 00:00:00", + "1981-06-21 00:00:00", + "1981-06-27 00:00:00", + "1981-06-28 00:00:00", + "1981-07-04 00:00:00", + "1981-07-05 00:00:00", + "1981-07-11 00:00:00", + "1981-07-12 00:00:00", + "1981-07-18 00:00:00", + "1981-07-19 00:00:00", + "1981-07-25 00:00:00", + "1981-07-26 00:00:00", + "1981-08-01 00:00:00", + "1981-08-02 00:00:00", + "1981-08-08 00:00:00", + "1981-08-09 00:00:00", + "1981-08-15 00:00:00", + "1981-08-16 00:00:00", + "1981-08-22 00:00:00", + "1981-08-23 00:00:00", + "1981-08-29 00:00:00", + "1981-08-30 00:00:00", + "1981-09-05 00:00:00", + "1981-09-06 00:00:00", + "1981-09-12 00:00:00", + "1981-09-13 00:00:00", + "1981-09-19 00:00:00", + "1981-09-20 00:00:00", + "1981-09-26 00:00:00", + "1981-09-27 00:00:00", + "1981-10-03 00:00:00", + "1981-10-04 00:00:00", + "1981-10-10 00:00:00", + "1981-10-11 00:00:00", + "1981-10-17 00:00:00", + "1981-10-18 00:00:00", + "1981-10-24 00:00:00", + "1981-10-25 00:00:00", + "1981-10-31 00:00:00", + "1981-11-01 00:00:00", + "1981-11-07 00:00:00", + "1981-11-08 00:00:00", + "1981-11-14 00:00:00", + "1981-11-15 00:00:00", + "1981-11-21 00:00:00", + "1981-11-22 00:00:00", + "1981-11-28 00:00:00", + "1981-11-29 00:00:00", + "1981-12-05 00:00:00", + "1981-12-06 00:00:00", + "1981-12-12 00:00:00", + "1981-12-13 00:00:00", + "1981-12-19 00:00:00", + "1981-12-20 00:00:00", + "1981-12-26 00:00:00", + "1981-12-27 00:00:00", + "1982-01-02 00:00:00", + "1982-01-03 00:00:00", + "1982-01-09 00:00:00", + "1982-01-10 00:00:00", + "1982-01-16 00:00:00", + "1982-01-17 00:00:00", + "1982-01-23 00:00:00", + "1982-01-24 00:00:00", + "1982-01-30 00:00:00", + "1982-01-31 00:00:00", + "1982-02-06 00:00:00", + "1982-02-07 00:00:00", + "1982-02-13 00:00:00", + "1982-02-14 00:00:00", + "1982-02-20 00:00:00", + "1982-02-21 00:00:00", + "1982-02-27 00:00:00", + "1982-02-28 00:00:00", + "1982-03-06 00:00:00", + "1982-03-07 00:00:00", + "1982-03-13 00:00:00", + "1982-03-14 00:00:00", + "1982-03-20 00:00:00", + "1982-03-21 00:00:00", + "1982-03-27 00:00:00", + "1982-03-28 00:00:00", + "1982-04-03 00:00:00", + "1982-04-04 00:00:00", + "1982-04-10 00:00:00", + "1982-04-11 00:00:00", + "1982-04-17 00:00:00", + "1982-04-18 00:00:00", + "1982-04-24 00:00:00", + "1982-04-25 00:00:00", + "1982-05-01 00:00:00", + "1982-05-02 00:00:00", + "1982-05-08 00:00:00", + "1982-05-09 00:00:00", + "1982-05-15 00:00:00", + "1982-05-16 00:00:00", + "1982-05-22 00:00:00", + "1982-05-23 00:00:00", + "1982-05-29 00:00:00", + "1982-05-30 00:00:00", + "1982-06-05 00:00:00", + "1982-06-06 00:00:00", + "1982-06-12 00:00:00", + "1982-06-13 00:00:00", + "1982-06-19 00:00:00", + "1982-06-20 00:00:00", + "1982-06-26 00:00:00", + "1982-06-27 00:00:00", + "1982-07-03 00:00:00", + "1982-07-04 00:00:00", + "1982-07-10 00:00:00", + "1982-07-11 00:00:00", + "1982-07-17 00:00:00", + "1982-07-18 00:00:00", + "1982-07-24 00:00:00", + "1982-07-25 00:00:00", + "1982-07-31 00:00:00", + "1982-08-01 00:00:00", + "1982-08-07 00:00:00", + "1982-08-08 00:00:00", + "1982-08-14 00:00:00", + "1982-08-15 00:00:00", + "1982-08-21 00:00:00", + "1982-08-22 00:00:00", + "1982-08-28 00:00:00", + "1982-08-29 00:00:00", + "1982-09-04 00:00:00", + "1982-09-05 00:00:00", + "1982-09-11 00:00:00", + "1982-09-12 00:00:00", + "1982-09-18 00:00:00", + "1982-09-19 00:00:00", + "1982-09-25 00:00:00", + "1982-09-26 00:00:00", + "1982-10-02 00:00:00", + "1982-10-03 00:00:00", + "1982-10-09 00:00:00", + "1982-10-10 00:00:00", + "1982-10-16 00:00:00", + "1982-10-17 00:00:00", + "1982-10-23 00:00:00", + "1982-10-24 00:00:00", + "1982-10-30 00:00:00", + "1982-10-31 00:00:00", + "1982-11-06 00:00:00", + "1982-11-07 00:00:00", + "1982-11-13 00:00:00", + "1982-11-14 00:00:00", + "1982-11-20 00:00:00", + "1982-11-21 00:00:00", + "1982-11-27 00:00:00", + "1982-11-28 00:00:00", + "1982-12-04 00:00:00", + "1982-12-05 00:00:00", + "1982-12-11 00:00:00", + "1982-12-12 00:00:00", + "1982-12-18 00:00:00", + "1982-12-19 00:00:00", + "1982-12-25 00:00:00", + "1982-12-26 00:00:00", + "1983-01-01 00:00:00", + "1983-01-02 00:00:00", + "1983-01-08 00:00:00", + "1983-01-09 00:00:00", + "1983-01-15 00:00:00", + "1983-01-16 00:00:00", + "1983-01-22 00:00:00", + "1983-01-23 00:00:00", + "1983-01-29 00:00:00", + "1983-01-30 00:00:00", + "1983-02-05 00:00:00", + "1983-02-06 00:00:00", + "1983-02-12 00:00:00", + "1983-02-13 00:00:00", + "1983-02-19 00:00:00", + "1983-02-20 00:00:00", + "1983-02-26 00:00:00", + "1983-02-27 00:00:00", + "1983-03-05 00:00:00", + "1983-03-06 00:00:00", + "1983-03-12 00:00:00", + "1983-03-13 00:00:00", + "1983-03-19 00:00:00", + "1983-03-20 00:00:00", + "1983-03-26 00:00:00", + "1983-03-27 00:00:00", + "1983-04-02 00:00:00", + "1983-04-03 00:00:00", + "1983-04-09 00:00:00", + "1983-04-10 00:00:00", + "1983-04-16 00:00:00", + "1983-04-17 00:00:00", + "1983-04-23 00:00:00", + "1983-04-24 00:00:00", + "1983-04-30 00:00:00", + "1983-05-01 00:00:00", + "1983-05-07 00:00:00", + "1983-05-08 00:00:00", + "1983-05-14 00:00:00", + "1983-05-15 00:00:00", + "1983-05-21 00:00:00", + "1983-05-22 00:00:00", + "1983-05-28 00:00:00", + "1983-05-29 00:00:00", + "1983-06-04 00:00:00", + "1983-06-05 00:00:00", + "1983-06-11 00:00:00", + "1983-06-12 00:00:00", + "1983-06-18 00:00:00", + "1983-06-19 00:00:00", + "1983-06-25 00:00:00", + "1983-06-26 00:00:00", + "1983-07-02 00:00:00", + "1983-07-03 00:00:00", + "1983-07-09 00:00:00", + "1983-07-10 00:00:00", + "1983-07-16 00:00:00", + "1983-07-17 00:00:00", + "1983-07-23 00:00:00", + "1983-07-24 00:00:00", + "1983-07-30 00:00:00", + "1983-07-31 00:00:00", + "1983-08-06 00:00:00", + "1983-08-07 00:00:00", + "1983-08-13 00:00:00", + "1983-08-14 00:00:00", + "1983-08-20 00:00:00", + "1983-08-21 00:00:00", + "1983-08-27 00:00:00", + "1983-08-28 00:00:00", + "1983-09-03 00:00:00", + "1983-09-04 00:00:00", + "1983-09-10 00:00:00", + "1983-09-11 00:00:00", + "1983-09-17 00:00:00", + "1983-09-18 00:00:00", + "1983-09-24 00:00:00", + "1983-09-25 00:00:00", + "1983-10-01 00:00:00", + "1983-10-02 00:00:00", + "1983-10-08 00:00:00", + "1983-10-09 00:00:00", + "1983-10-15 00:00:00", + "1983-10-16 00:00:00", + "1983-10-22 00:00:00", + "1983-10-23 00:00:00", + "1983-10-29 00:00:00", + "1983-10-30 00:00:00", + "1983-11-05 00:00:00", + "1983-11-06 00:00:00", + "1983-11-12 00:00:00", + "1983-11-13 00:00:00", + "1983-11-19 00:00:00", + "1983-11-20 00:00:00", + "1983-11-26 00:00:00", + "1983-11-27 00:00:00", + "1983-12-03 00:00:00", + "1983-12-04 00:00:00", + "1983-12-10 00:00:00", + "1983-12-11 00:00:00", + "1983-12-17 00:00:00", + "1983-12-18 00:00:00", + "1983-12-24 00:00:00", + "1983-12-25 00:00:00", + "1983-12-31 00:00:00", + "1984-01-01 00:00:00", + "1984-01-07 00:00:00", + "1984-01-08 00:00:00", + "1984-01-14 00:00:00", + "1984-01-15 00:00:00", + "1984-01-21 00:00:00", + "1984-01-22 00:00:00", + "1984-01-28 00:00:00", + "1984-01-29 00:00:00", + "1984-02-04 00:00:00", + "1984-02-05 00:00:00", + "1984-02-11 00:00:00", + "1984-02-12 00:00:00", + "1984-02-18 00:00:00", + "1984-02-19 00:00:00", + "1984-02-25 00:00:00", + "1984-02-26 00:00:00", + "1984-03-03 00:00:00", + "1984-03-04 00:00:00", + "1984-03-10 00:00:00", + "1984-03-11 00:00:00", + "1984-03-17 00:00:00", + "1984-03-18 00:00:00", + "1984-03-24 00:00:00", + "1984-03-25 00:00:00", + "1984-03-31 00:00:00", + "1984-04-01 00:00:00", + "1984-04-07 00:00:00", + "1984-04-08 00:00:00", + "1984-04-14 00:00:00", + "1984-04-15 00:00:00", + "1984-04-21 00:00:00", + "1984-04-22 00:00:00", + "1984-04-28 00:00:00", + "1984-04-29 00:00:00", + "1984-05-05 00:00:00", + "1984-05-06 00:00:00", + "1984-05-12 00:00:00", + "1984-05-13 00:00:00", + "1984-05-19 00:00:00", + "1984-05-20 00:00:00", + "1984-05-26 00:00:00", + "1984-05-27 00:00:00", + "1984-06-02 00:00:00", + "1984-06-03 00:00:00", + "1984-06-09 00:00:00", + "1984-06-10 00:00:00", + "1984-06-16 00:00:00", + "1984-06-17 00:00:00", + "1984-06-23 00:00:00", + "1984-06-24 00:00:00", + "1984-06-30 00:00:00", + "1984-07-01 00:00:00", + "1984-07-07 00:00:00", + "1984-07-08 00:00:00", + "1984-07-14 00:00:00", + "1984-07-15 00:00:00", + "1984-07-21 00:00:00", + "1984-07-22 00:00:00", + "1984-07-28 00:00:00", + "1984-07-29 00:00:00", + "1984-08-04 00:00:00", + "1984-08-05 00:00:00", + "1984-08-11 00:00:00", + "1984-08-12 00:00:00", + "1984-08-18 00:00:00", + "1984-08-19 00:00:00", + "1984-08-25 00:00:00", + "1984-08-26 00:00:00", + "1984-09-01 00:00:00", + "1984-09-02 00:00:00", + "1984-09-08 00:00:00", + "1984-09-09 00:00:00", + "1984-09-15 00:00:00", + "1984-09-16 00:00:00", + "1984-09-22 00:00:00", + "1984-09-23 00:00:00", + "1984-09-29 00:00:00", + "1984-09-30 00:00:00", + "1984-10-06 00:00:00", + "1984-10-07 00:00:00", + "1984-10-13 00:00:00", + "1984-10-14 00:00:00", + "1984-10-20 00:00:00", + "1984-10-21 00:00:00", + "1984-10-27 00:00:00", + "1984-10-28 00:00:00", + "1984-11-03 00:00:00", + "1984-11-04 00:00:00", + "1984-11-10 00:00:00", + "1984-11-11 00:00:00", + "1984-11-17 00:00:00", + "1984-11-18 00:00:00", + "1984-11-24 00:00:00", + "1984-11-25 00:00:00", + "1984-12-01 00:00:00", + "1984-12-02 00:00:00", + "1984-12-08 00:00:00", + "1984-12-09 00:00:00", + "1984-12-15 00:00:00", + "1984-12-16 00:00:00", + "1984-12-22 00:00:00", + "1984-12-23 00:00:00", + "1984-12-29 00:00:00", + "1984-12-30 00:00:00", + "1985-01-05 00:00:00", + "1985-01-06 00:00:00", + "1985-01-12 00:00:00", + "1985-01-13 00:00:00", + "1985-01-19 00:00:00", + "1985-01-20 00:00:00", + "1985-01-26 00:00:00", + "1985-01-27 00:00:00", + "1985-02-02 00:00:00", + "1985-02-03 00:00:00", + "1985-02-09 00:00:00", + "1985-02-10 00:00:00", + "1985-02-16 00:00:00", + "1985-02-17 00:00:00", + "1985-02-23 00:00:00", + "1985-02-24 00:00:00", + "1985-03-02 00:00:00", + "1985-03-03 00:00:00", + "1985-03-09 00:00:00", + "1985-03-10 00:00:00", + "1985-03-16 00:00:00", + "1985-03-17 00:00:00", + "1985-03-23 00:00:00", + "1985-03-24 00:00:00", + "1985-03-30 00:00:00", + "1985-03-31 00:00:00", + "1985-04-06 00:00:00", + "1985-04-07 00:00:00", + "1985-04-13 00:00:00", + "1985-04-14 00:00:00", + "1985-04-20 00:00:00", + "1985-04-21 00:00:00", + "1985-04-27 00:00:00", + "1985-04-28 00:00:00", + "1985-05-04 00:00:00", + "1985-05-05 00:00:00", + "1985-05-11 00:00:00", + "1985-05-12 00:00:00", + "1985-05-18 00:00:00", + "1985-05-19 00:00:00", + "1985-05-25 00:00:00", + "1985-05-26 00:00:00", + "1985-06-01 00:00:00", + "1985-06-02 00:00:00", + "1985-06-08 00:00:00", + "1985-06-09 00:00:00", + "1985-06-15 00:00:00", + "1985-06-16 00:00:00", + "1985-06-22 00:00:00", + "1985-06-23 00:00:00", + "1985-06-29 00:00:00", + "1985-06-30 00:00:00", + "1985-07-06 00:00:00", + "1985-07-07 00:00:00", + "1985-07-13 00:00:00", + "1985-07-14 00:00:00", + "1985-07-20 00:00:00", + "1985-07-21 00:00:00", + "1985-07-27 00:00:00", + "1985-07-28 00:00:00", + "1985-08-03 00:00:00", + "1985-08-04 00:00:00", + "1985-08-10 00:00:00", + "1985-08-11 00:00:00", + "1985-08-17 00:00:00", + "1985-08-18 00:00:00", + "1985-08-24 00:00:00", + "1985-08-25 00:00:00", + "1985-08-31 00:00:00", + "1985-09-01 00:00:00", + "1985-09-07 00:00:00", + "1985-09-08 00:00:00", + "1985-09-14 00:00:00", + "1985-09-15 00:00:00", + "1985-09-21 00:00:00", + "1985-09-22 00:00:00", + "1985-09-28 00:00:00", + "1985-09-29 00:00:00", + "1985-10-05 00:00:00", + "1985-10-06 00:00:00", + "1985-10-12 00:00:00", + "1985-10-13 00:00:00", + "1985-10-19 00:00:00", + "1985-10-20 00:00:00", + "1985-10-26 00:00:00", + "1985-10-27 00:00:00", + "1985-11-02 00:00:00", + "1985-11-03 00:00:00", + "1985-11-09 00:00:00", + "1985-11-10 00:00:00", + "1985-11-16 00:00:00", + "1985-11-17 00:00:00", + "1985-11-23 00:00:00", + "1985-11-24 00:00:00", + "1985-11-30 00:00:00", + "1985-12-01 00:00:00", + "1985-12-07 00:00:00", + "1985-12-08 00:00:00", + "1985-12-14 00:00:00", + "1985-12-15 00:00:00", + "1985-12-21 00:00:00", + "1985-12-22 00:00:00", + "1985-12-28 00:00:00", + "1985-12-29 00:00:00", + "1986-01-04 00:00:00", + "1986-01-05 00:00:00", + "1986-01-11 00:00:00", + "1986-01-12 00:00:00", + "1986-01-18 00:00:00", + "1986-01-19 00:00:00", + "1986-01-25 00:00:00", + "1986-01-26 00:00:00", + "1986-02-01 00:00:00", + "1986-02-02 00:00:00", + "1986-02-08 00:00:00", + "1986-02-09 00:00:00", + "1986-02-15 00:00:00", + "1986-02-16 00:00:00", + "1986-02-22 00:00:00", + "1986-02-23 00:00:00", + "1986-03-01 00:00:00", + "1986-03-02 00:00:00", + "1986-03-08 00:00:00", + "1986-03-09 00:00:00", + "1986-03-15 00:00:00", + "1986-03-16 00:00:00", + "1986-03-22 00:00:00", + "1986-03-23 00:00:00", + "1986-03-29 00:00:00", + "1986-03-30 00:00:00", + "1986-04-05 00:00:00", + "1986-04-06 00:00:00", + "1986-04-12 00:00:00", + "1986-04-13 00:00:00", + "1986-04-19 00:00:00", + "1986-04-20 00:00:00", + "1986-04-26 00:00:00", + "1986-04-27 00:00:00", + "1986-05-03 00:00:00", + "1986-05-04 00:00:00", + "1986-05-10 00:00:00", + "1986-05-11 00:00:00", + "1986-05-17 00:00:00", + "1986-05-18 00:00:00", + "1986-05-24 00:00:00", + "1986-05-25 00:00:00", + "1986-05-31 00:00:00", + "1986-06-01 00:00:00", + "1986-06-07 00:00:00", + "1986-06-08 00:00:00", + "1986-06-14 00:00:00", + "1986-06-15 00:00:00", + "1986-06-21 00:00:00", + "1986-06-22 00:00:00", + "1986-06-28 00:00:00", + "1986-06-29 00:00:00", + "1986-07-05 00:00:00", + "1986-07-06 00:00:00", + "1986-07-12 00:00:00", + "1986-07-13 00:00:00", + "1986-07-19 00:00:00", + "1986-07-20 00:00:00", + "1986-07-26 00:00:00", + "1986-07-27 00:00:00", + "1986-08-02 00:00:00", + "1986-08-03 00:00:00", + "1986-08-09 00:00:00", + "1986-08-10 00:00:00", + "1986-08-16 00:00:00", + "1986-08-17 00:00:00", + "1986-08-23 00:00:00", + "1986-08-24 00:00:00", + "1986-08-30 00:00:00", + "1986-08-31 00:00:00", + "1986-09-06 00:00:00", + "1986-09-07 00:00:00", + "1986-09-13 00:00:00", + "1986-09-14 00:00:00", + "1986-09-20 00:00:00", + "1986-09-21 00:00:00", + "1986-09-27 00:00:00", + "1986-09-28 00:00:00", + "1986-10-04 00:00:00", + "1986-10-05 00:00:00", + "1986-10-11 00:00:00", + "1986-10-12 00:00:00", + "1986-10-18 00:00:00", + "1986-10-19 00:00:00", + "1986-10-25 00:00:00", + "1986-10-26 00:00:00", + "1986-11-01 00:00:00", + "1986-11-02 00:00:00", + "1986-11-08 00:00:00", + "1986-11-09 00:00:00", + "1986-11-15 00:00:00", + "1986-11-16 00:00:00", + "1986-11-22 00:00:00", + "1986-11-23 00:00:00", + "1986-11-29 00:00:00", + "1986-11-30 00:00:00", + "1986-12-06 00:00:00", + "1986-12-07 00:00:00", + "1986-12-13 00:00:00", + "1986-12-14 00:00:00", + "1986-12-20 00:00:00", + "1986-12-21 00:00:00", + "1986-12-27 00:00:00", + "1986-12-28 00:00:00", + "1987-01-03 00:00:00", + "1987-01-04 00:00:00", + "1987-01-10 00:00:00", + "1987-01-11 00:00:00", + "1987-01-17 00:00:00", + "1987-01-18 00:00:00", + "1987-01-24 00:00:00", + "1987-01-25 00:00:00", + "1987-01-31 00:00:00", + "1987-02-01 00:00:00", + "1987-02-07 00:00:00", + "1987-02-08 00:00:00", + "1987-02-14 00:00:00", + "1987-02-15 00:00:00", + "1987-02-21 00:00:00", + "1987-02-22 00:00:00", + "1987-02-28 00:00:00", + "1987-03-01 00:00:00", + "1987-03-07 00:00:00", + "1987-03-08 00:00:00", + "1987-03-14 00:00:00", + "1987-03-15 00:00:00", + "1987-03-21 00:00:00", + "1987-03-22 00:00:00", + "1987-03-28 00:00:00", + "1987-03-29 00:00:00", + "1987-04-04 00:00:00", + "1987-04-05 00:00:00", + "1987-04-11 00:00:00", + "1987-04-12 00:00:00", + "1987-04-18 00:00:00", + "1987-04-19 00:00:00", + "1987-04-25 00:00:00", + "1987-04-26 00:00:00", + "1987-05-02 00:00:00", + "1987-05-03 00:00:00", + "1987-05-09 00:00:00", + "1987-05-10 00:00:00", + "1987-05-16 00:00:00", + "1987-05-17 00:00:00", + "1987-05-23 00:00:00", + "1987-05-24 00:00:00", + "1987-05-30 00:00:00", + "1987-05-31 00:00:00", + "1987-06-06 00:00:00", + "1987-06-07 00:00:00", + "1987-06-13 00:00:00", + "1987-06-14 00:00:00", + "1987-06-20 00:00:00", + "1987-06-21 00:00:00", + "1987-06-27 00:00:00", + "1987-06-28 00:00:00", + "1987-07-04 00:00:00", + "1987-07-05 00:00:00", + "1987-07-11 00:00:00", + "1987-07-12 00:00:00", + "1987-07-18 00:00:00", + "1987-07-19 00:00:00", + "1987-07-25 00:00:00", + "1987-07-26 00:00:00", + "1987-08-01 00:00:00", + "1987-08-02 00:00:00", + "1987-08-08 00:00:00", + "1987-08-09 00:00:00", + "1987-08-15 00:00:00", + "1987-08-16 00:00:00", + "1987-08-22 00:00:00", + "1987-08-23 00:00:00", + "1987-08-29 00:00:00", + "1987-08-30 00:00:00", + "1987-09-05 00:00:00", + "1987-09-06 00:00:00", + "1987-09-12 00:00:00", + "1987-09-13 00:00:00", + "1987-09-19 00:00:00", + "1987-09-20 00:00:00", + "1987-09-26 00:00:00", + "1987-09-27 00:00:00", + "1987-10-03 00:00:00", + "1987-10-04 00:00:00", + "1987-10-10 00:00:00", + "1987-10-11 00:00:00", + "1987-10-17 00:00:00", + "1987-10-18 00:00:00", + "1987-10-24 00:00:00", + "1987-10-25 00:00:00", + "1987-10-31 00:00:00", + "1987-11-01 00:00:00", + "1987-11-07 00:00:00", + "1987-11-08 00:00:00", + "1987-11-14 00:00:00", + "1987-11-15 00:00:00", + "1987-11-21 00:00:00", + "1987-11-22 00:00:00", + "1987-11-28 00:00:00", + "1987-11-29 00:00:00", + "1987-12-05 00:00:00", + "1987-12-06 00:00:00", + "1987-12-12 00:00:00", + "1987-12-13 00:00:00", + "1987-12-19 00:00:00", + "1987-12-20 00:00:00", + "1987-12-26 00:00:00", + "1987-12-27 00:00:00", + "1988-01-02 00:00:00", + "1988-01-03 00:00:00", + "1988-01-09 00:00:00", + "1988-01-10 00:00:00", + "1988-01-16 00:00:00", + "1988-01-17 00:00:00", + "1988-01-23 00:00:00", + "1988-01-24 00:00:00", + "1988-01-30 00:00:00", + "1988-01-31 00:00:00", + "1988-02-06 00:00:00", + "1988-02-07 00:00:00", + "1988-02-13 00:00:00", + "1988-02-14 00:00:00", + "1988-02-20 00:00:00", + "1988-02-21 00:00:00", + "1988-02-27 00:00:00", + "1988-02-28 00:00:00", + "1988-03-05 00:00:00", + "1988-03-06 00:00:00", + "1988-03-12 00:00:00", + "1988-03-13 00:00:00", + "1988-03-19 00:00:00", + "1988-03-20 00:00:00", + "1988-03-26 00:00:00", + "1988-03-27 00:00:00", + "1988-04-02 00:00:00", + "1988-04-03 00:00:00", + "1988-04-09 00:00:00", + "1988-04-10 00:00:00", + "1988-04-16 00:00:00", + "1988-04-17 00:00:00", + "1988-04-23 00:00:00", + "1988-04-24 00:00:00", + "1988-04-30 00:00:00", + "1988-05-01 00:00:00", + "1988-05-07 00:00:00", + "1988-05-08 00:00:00", + "1988-05-14 00:00:00", + "1988-05-15 00:00:00", + "1988-05-21 00:00:00", + "1988-05-22 00:00:00", + "1988-05-28 00:00:00", + "1988-05-29 00:00:00", + "1988-06-04 00:00:00", + "1988-06-05 00:00:00", + "1988-06-11 00:00:00", + "1988-06-12 00:00:00", + "1988-06-18 00:00:00", + "1988-06-19 00:00:00", + "1988-06-25 00:00:00", + "1988-06-26 00:00:00", + "1988-07-02 00:00:00", + "1988-07-03 00:00:00", + "1988-07-09 00:00:00", + "1988-07-10 00:00:00", + "1988-07-16 00:00:00", + "1988-07-17 00:00:00", + "1988-07-23 00:00:00", + "1988-07-24 00:00:00", + "1988-07-30 00:00:00", + "1988-07-31 00:00:00", + "1988-08-06 00:00:00", + "1988-08-07 00:00:00", + "1988-08-13 00:00:00", + "1988-08-14 00:00:00", + "1988-08-20 00:00:00", + "1988-08-21 00:00:00", + "1988-08-27 00:00:00", + "1988-08-28 00:00:00", + "1988-09-03 00:00:00", + "1988-09-04 00:00:00", + "1988-09-10 00:00:00", + "1988-09-11 00:00:00", + "1988-09-17 00:00:00", + "1988-09-18 00:00:00", + "1988-09-24 00:00:00", + "1988-09-25 00:00:00", + "1988-10-01 00:00:00", + "1988-10-02 00:00:00", + "1988-10-08 00:00:00", + "1988-10-09 00:00:00", + "1988-10-15 00:00:00", + "1988-10-16 00:00:00", + "1988-10-22 00:00:00", + "1988-10-23 00:00:00", + "1988-10-29 00:00:00", + "1988-10-30 00:00:00", + "1988-11-05 00:00:00", + "1988-11-06 00:00:00", + "1988-11-12 00:00:00", + "1988-11-13 00:00:00", + "1988-11-19 00:00:00", + "1988-11-20 00:00:00", + "1988-11-26 00:00:00", + "1988-11-27 00:00:00", + "1988-12-03 00:00:00", + "1988-12-04 00:00:00", + "1988-12-10 00:00:00", + "1988-12-11 00:00:00", + "1988-12-17 00:00:00", + "1988-12-18 00:00:00", + "1988-12-24 00:00:00", + "1988-12-25 00:00:00", + "1988-12-31 00:00:00", + "1989-01-01 00:00:00", + "1989-01-07 00:00:00", + "1989-01-08 00:00:00", + "1989-01-14 00:00:00", + "1989-01-15 00:00:00", + "1989-01-21 00:00:00", + "1989-01-22 00:00:00", + "1989-01-28 00:00:00", + "1989-01-29 00:00:00", + "1989-02-04 00:00:00", + "1989-02-05 00:00:00", + "1989-02-11 00:00:00", + "1989-02-12 00:00:00", + "1989-02-18 00:00:00", + "1989-02-19 00:00:00", + "1989-02-25 00:00:00", + "1989-02-26 00:00:00", + "1989-03-04 00:00:00", + "1989-03-05 00:00:00", + "1989-03-11 00:00:00", + "1989-03-12 00:00:00", + "1989-03-18 00:00:00", + "1989-03-19 00:00:00", + "1989-03-25 00:00:00", + "1989-03-26 00:00:00", + "1989-04-01 00:00:00", + "1989-04-02 00:00:00", + "1989-04-08 00:00:00", + "1989-04-09 00:00:00", + "1989-04-15 00:00:00", + "1989-04-16 00:00:00", + "1989-04-22 00:00:00", + "1989-04-23 00:00:00", + "1989-04-29 00:00:00", + "1989-04-30 00:00:00", + "1989-05-06 00:00:00", + "1989-05-07 00:00:00", + "1989-05-13 00:00:00", + "1989-05-14 00:00:00", + "1989-05-20 00:00:00", + "1989-05-21 00:00:00", + "1989-05-27 00:00:00", + "1989-05-28 00:00:00", + "1989-06-03 00:00:00", + "1989-06-04 00:00:00", + "1989-06-10 00:00:00", + "1989-06-11 00:00:00", + "1989-06-17 00:00:00", + "1989-06-18 00:00:00", + "1989-06-24 00:00:00", + "1989-06-25 00:00:00", + "1989-07-01 00:00:00", + "1989-07-02 00:00:00", + "1989-07-08 00:00:00", + "1989-07-09 00:00:00", + "1989-07-15 00:00:00", + "1989-07-16 00:00:00", + "1989-07-22 00:00:00", + "1989-07-23 00:00:00", + "1989-07-29 00:00:00", + "1989-07-30 00:00:00", + "1989-08-05 00:00:00", + "1989-08-06 00:00:00", + "1989-08-12 00:00:00", + "1989-08-13 00:00:00", + "1989-08-19 00:00:00", + "1989-08-20 00:00:00", + "1989-08-26 00:00:00", + "1989-08-27 00:00:00", + "1989-09-02 00:00:00", + "1989-09-03 00:00:00", + "1989-09-09 00:00:00", + "1989-09-10 00:00:00", + "1989-09-16 00:00:00", + "1989-09-17 00:00:00", + "1989-09-23 00:00:00", + "1989-09-24 00:00:00", + "1989-09-30 00:00:00", + "1989-10-01 00:00:00", + "1989-10-07 00:00:00", + "1989-10-08 00:00:00", + "1989-10-14 00:00:00", + "1989-10-15 00:00:00", + "1989-10-21 00:00:00", + "1989-10-22 00:00:00", + "1989-10-28 00:00:00", + "1989-10-29 00:00:00", + "1989-11-04 00:00:00", + "1989-11-05 00:00:00", + "1989-11-11 00:00:00", + "1989-11-12 00:00:00", + "1989-11-18 00:00:00", + "1989-11-19 00:00:00", + "1989-11-25 00:00:00", + "1989-11-26 00:00:00", + "1989-12-02 00:00:00", + "1989-12-03 00:00:00", + "1989-12-09 00:00:00", + "1989-12-10 00:00:00", + "1989-12-16 00:00:00", + "1989-12-17 00:00:00", + "1989-12-23 00:00:00", + "1989-12-24 00:00:00", + "1989-12-30 00:00:00", + "1989-12-31 00:00:00", + "1990-01-06 00:00:00", + "1990-01-07 00:00:00", + "1990-01-13 00:00:00", + "1990-01-14 00:00:00", + "1990-01-20 00:00:00", + "1990-01-21 00:00:00", + "1990-01-27 00:00:00", + "1990-01-28 00:00:00", + "1990-02-03 00:00:00", + "1990-02-04 00:00:00", + "1990-02-10 00:00:00", + "1990-02-11 00:00:00", + "1990-02-17 00:00:00", + "1990-02-18 00:00:00", + "1990-02-24 00:00:00", + "1990-02-25 00:00:00", + "1990-03-03 00:00:00", + "1990-03-04 00:00:00", + "1990-03-10 00:00:00", + "1990-03-11 00:00:00", + "1990-03-17 00:00:00", + "1990-03-18 00:00:00", + "1990-03-24 00:00:00", + "1990-03-25 00:00:00", + "1990-03-31 00:00:00", + "1990-04-01 00:00:00", + "1990-04-07 00:00:00", + "1990-04-08 00:00:00", + "1990-04-14 00:00:00", + "1990-04-15 00:00:00", + "1990-04-21 00:00:00", + "1990-04-22 00:00:00", + "1990-04-28 00:00:00", + "1990-04-29 00:00:00", + "1990-05-05 00:00:00", + "1990-05-06 00:00:00", + "1990-05-12 00:00:00", + "1990-05-13 00:00:00", + "1990-05-19 00:00:00", + "1990-05-20 00:00:00", + "1990-05-26 00:00:00", + "1990-05-27 00:00:00", + "1990-06-02 00:00:00", + "1990-06-03 00:00:00", + "1990-06-09 00:00:00", + "1990-06-10 00:00:00", + "1990-06-16 00:00:00", + "1990-06-17 00:00:00", + "1990-06-23 00:00:00", + "1990-06-24 00:00:00", + "1990-06-30 00:00:00", + "1990-07-01 00:00:00", + "1990-07-07 00:00:00", + "1990-07-08 00:00:00", + "1990-07-14 00:00:00", + "1990-07-15 00:00:00", + "1990-07-21 00:00:00", + "1990-07-22 00:00:00", + "1990-07-28 00:00:00", + "1990-07-29 00:00:00", + "1990-08-04 00:00:00", + "1990-08-05 00:00:00", + "1990-08-11 00:00:00", + "1990-08-12 00:00:00", + "1990-08-18 00:00:00", + "1990-08-19 00:00:00", + "1990-08-25 00:00:00", + "1990-08-26 00:00:00", + "1990-09-01 00:00:00", + "1990-09-02 00:00:00", + "1990-09-08 00:00:00", + "1990-09-09 00:00:00", + "1990-09-15 00:00:00", + "1990-09-16 00:00:00", + "1990-09-22 00:00:00", + "1990-09-23 00:00:00", + "1990-09-29 00:00:00", + "1990-09-30 00:00:00", + "1990-10-06 00:00:00", + "1990-10-07 00:00:00", + "1990-10-13 00:00:00", + "1990-10-14 00:00:00", + "1990-10-20 00:00:00", + "1990-10-21 00:00:00", + "1990-10-27 00:00:00", + "1990-10-28 00:00:00", + "1990-11-03 00:00:00", + "1990-11-04 00:00:00", + "1990-11-10 00:00:00", + "1990-11-11 00:00:00", + "1990-11-17 00:00:00", + "1990-11-18 00:00:00", + "1990-11-24 00:00:00", + "1990-11-25 00:00:00", + "1990-12-01 00:00:00", + "1990-12-02 00:00:00", + "1990-12-08 00:00:00", + "1990-12-09 00:00:00", + "1990-12-15 00:00:00", + "1990-12-16 00:00:00", + "1990-12-22 00:00:00", + "1990-12-23 00:00:00", + "1990-12-29 00:00:00", + "1990-12-30 00:00:00", + "1991-01-05 00:00:00", + "1991-01-06 00:00:00", + "1991-01-12 00:00:00", + "1991-01-13 00:00:00", + "1991-01-19 00:00:00", + "1991-01-20 00:00:00", + "1991-01-26 00:00:00", + "1991-01-27 00:00:00", + "1991-02-02 00:00:00", + "1991-02-03 00:00:00", + "1991-02-09 00:00:00", + "1991-02-10 00:00:00", + "1991-02-16 00:00:00", + "1991-02-17 00:00:00", + "1991-02-23 00:00:00", + "1991-02-24 00:00:00", + "1991-03-02 00:00:00", + "1991-03-03 00:00:00", + "1991-03-09 00:00:00", + "1991-03-10 00:00:00", + "1991-03-16 00:00:00", + "1991-03-17 00:00:00", + "1991-03-23 00:00:00", + "1991-03-24 00:00:00", + "1991-03-30 00:00:00", + "1991-03-31 00:00:00", + "1991-04-06 00:00:00", + "1991-04-07 00:00:00", + "1991-04-13 00:00:00", + "1991-04-14 00:00:00", + "1991-04-20 00:00:00", + "1991-04-21 00:00:00", + "1991-04-27 00:00:00", + "1991-04-28 00:00:00", + "1991-05-04 00:00:00", + "1991-05-05 00:00:00", + "1991-05-11 00:00:00", + "1991-05-12 00:00:00", + "1991-05-18 00:00:00", + "1991-05-19 00:00:00", + "1991-05-25 00:00:00", + "1991-05-26 00:00:00", + "1991-06-01 00:00:00", + "1991-06-02 00:00:00", + "1991-06-08 00:00:00", + "1991-06-09 00:00:00", + "1991-06-15 00:00:00", + "1991-06-16 00:00:00", + "1991-06-22 00:00:00", + "1991-06-23 00:00:00", + "1991-06-29 00:00:00", + "1991-06-30 00:00:00", + "1991-07-06 00:00:00", + "1991-07-07 00:00:00", + "1991-07-13 00:00:00", + "1991-07-14 00:00:00", + "1991-07-20 00:00:00", + "1991-07-21 00:00:00", + "1991-07-27 00:00:00", + "1991-07-28 00:00:00", + "1991-08-03 00:00:00", + "1991-08-04 00:00:00", + "1991-08-10 00:00:00", + "1991-08-11 00:00:00", + "1991-08-17 00:00:00", + "1991-08-18 00:00:00", + "1991-08-24 00:00:00", + "1991-08-25 00:00:00", + "1991-08-31 00:00:00", + "1991-09-01 00:00:00", + "1991-09-07 00:00:00", + "1991-09-08 00:00:00", + "1991-09-14 00:00:00", + "1991-09-15 00:00:00", + "1991-09-21 00:00:00", + "1991-09-22 00:00:00", + "1991-09-28 00:00:00", + "1991-09-29 00:00:00", + "1991-10-05 00:00:00", + "1991-10-06 00:00:00", + "1991-10-12 00:00:00", + "1991-10-13 00:00:00", + "1991-10-19 00:00:00", + "1991-10-20 00:00:00", + "1991-10-26 00:00:00", + "1991-10-27 00:00:00", + "1991-11-02 00:00:00", + "1991-11-03 00:00:00", + "1991-11-09 00:00:00", + "1991-11-10 00:00:00", + "1991-11-16 00:00:00", + "1991-11-17 00:00:00", + "1991-11-23 00:00:00", + "1991-11-24 00:00:00", + "1991-11-30 00:00:00", + "1991-12-01 00:00:00", + "1991-12-07 00:00:00", + "1991-12-08 00:00:00", + "1991-12-14 00:00:00", + "1991-12-15 00:00:00", + "1991-12-21 00:00:00", + "1991-12-22 00:00:00", + "1991-12-28 00:00:00", + "1991-12-29 00:00:00", + "1992-01-04 00:00:00", + "1992-01-05 00:00:00", + "1992-01-11 00:00:00", + "1992-01-12 00:00:00", + "1992-01-18 00:00:00", + "1992-01-19 00:00:00", + "1992-01-25 00:00:00", + "1992-01-26 00:00:00", + "1992-02-01 00:00:00", + "1992-02-02 00:00:00", + "1992-02-08 00:00:00", + "1992-02-09 00:00:00", + "1992-02-15 00:00:00", + "1992-02-16 00:00:00", + "1992-02-22 00:00:00", + "1992-02-23 00:00:00", + "1992-02-29 00:00:00", + "1992-03-01 00:00:00", + "1992-03-07 00:00:00", + "1992-03-08 00:00:00", + "1992-03-14 00:00:00", + "1992-03-15 00:00:00", + "1992-03-21 00:00:00", + "1992-03-22 00:00:00", + "1992-03-28 00:00:00", + "1992-03-29 00:00:00", + "1992-04-04 00:00:00", + "1992-04-05 00:00:00", + "1992-04-11 00:00:00", + "1992-04-12 00:00:00", + "1992-04-18 00:00:00", + "1992-04-19 00:00:00", + "1992-04-25 00:00:00", + "1992-04-26 00:00:00", + "1992-05-02 00:00:00", + "1992-05-03 00:00:00", + "1992-05-09 00:00:00", + "1992-05-10 00:00:00", + "1992-05-16 00:00:00", + "1992-05-17 00:00:00", + "1992-05-23 00:00:00", + "1992-05-24 00:00:00", + "1992-05-30 00:00:00", + "1992-05-31 00:00:00", + "1992-06-06 00:00:00", + "1992-06-07 00:00:00", + "1992-06-13 00:00:00", + "1992-06-14 00:00:00", + "1992-06-20 00:00:00", + "1992-06-21 00:00:00", + "1992-06-27 00:00:00", + "1992-06-28 00:00:00", + "1992-07-04 00:00:00", + "1992-07-05 00:00:00", + "1992-07-11 00:00:00", + "1992-07-12 00:00:00", + "1992-07-18 00:00:00", + "1992-07-19 00:00:00", + "1992-07-25 00:00:00", + "1992-07-26 00:00:00", + "1992-08-01 00:00:00", + "1992-08-02 00:00:00", + "1992-08-08 00:00:00", + "1992-08-09 00:00:00", + "1992-08-15 00:00:00", + "1992-08-16 00:00:00", + "1992-08-22 00:00:00", + "1992-08-23 00:00:00", + "1992-08-29 00:00:00", + "1992-08-30 00:00:00", + "1992-09-05 00:00:00", + "1992-09-06 00:00:00", + "1992-09-12 00:00:00", + "1992-09-13 00:00:00", + "1992-09-19 00:00:00", + "1992-09-20 00:00:00", + "1992-09-26 00:00:00", + "1992-09-27 00:00:00", + "1992-10-03 00:00:00", + "1992-10-04 00:00:00", + "1992-10-10 00:00:00", + "1992-10-11 00:00:00", + "1992-10-17 00:00:00", + "1992-10-18 00:00:00", + "1992-10-24 00:00:00", + "1992-10-25 00:00:00", + "1992-10-31 00:00:00", + "1992-11-01 00:00:00", + "1992-11-07 00:00:00", + "1992-11-08 00:00:00", + "1992-11-14 00:00:00", + "1992-11-15 00:00:00", + "1992-11-21 00:00:00", + "1992-11-22 00:00:00", + "1992-11-28 00:00:00", + "1992-11-29 00:00:00", + "1992-12-05 00:00:00", + "1992-12-06 00:00:00", + "1992-12-12 00:00:00", + "1992-12-13 00:00:00", + "1992-12-19 00:00:00", + "1992-12-20 00:00:00", + "1992-12-26 00:00:00", + "1992-12-27 00:00:00", + "1993-01-02 00:00:00", + "1993-01-03 00:00:00", + "1993-01-09 00:00:00", + "1993-01-10 00:00:00", + "1993-01-16 00:00:00", + "1993-01-17 00:00:00", + "1993-01-23 00:00:00", + "1993-01-24 00:00:00", + "1993-01-30 00:00:00", + "1993-01-31 00:00:00", + "1993-02-06 00:00:00", + "1993-02-07 00:00:00", + "1993-02-13 00:00:00", + "1993-02-14 00:00:00", + "1993-02-20 00:00:00", + "1993-02-21 00:00:00", + "1993-02-27 00:00:00", + "1993-02-28 00:00:00", + "1993-03-06 00:00:00", + "1993-03-07 00:00:00", + "1993-03-13 00:00:00", + "1993-03-14 00:00:00", + "1993-03-20 00:00:00", + "1993-03-21 00:00:00", + "1993-03-27 00:00:00", + "1993-03-28 00:00:00", + "1993-04-03 00:00:00", + "1993-04-04 00:00:00", + "1993-04-10 00:00:00", + "1993-04-11 00:00:00", + "1993-04-17 00:00:00", + "1993-04-18 00:00:00", + "1993-04-24 00:00:00", + "1993-04-25 00:00:00", + "1993-05-01 00:00:00", + "1993-05-02 00:00:00", + "1993-05-08 00:00:00", + "1993-05-09 00:00:00", + "1993-05-15 00:00:00", + "1993-05-16 00:00:00", + "1993-05-22 00:00:00", + "1993-05-23 00:00:00", + "1993-05-29 00:00:00", + "1993-05-30 00:00:00", + "1993-06-05 00:00:00", + "1993-06-06 00:00:00", + "1993-06-12 00:00:00", + "1993-06-13 00:00:00", + "1993-06-19 00:00:00", + "1993-06-20 00:00:00", + "1993-06-26 00:00:00", + "1993-06-27 00:00:00", + "1993-07-03 00:00:00", + "1993-07-04 00:00:00", + "1993-07-10 00:00:00", + "1993-07-11 00:00:00", + "1993-07-17 00:00:00", + "1993-07-18 00:00:00", + "1993-07-24 00:00:00", + "1993-07-25 00:00:00", + "1993-07-31 00:00:00", + "1993-08-01 00:00:00", + "1993-08-07 00:00:00", + "1993-08-08 00:00:00", + "1993-08-14 00:00:00", + "1993-08-15 00:00:00", + "1993-08-21 00:00:00", + "1993-08-22 00:00:00", + "1993-08-28 00:00:00", + "1993-08-29 00:00:00", + "1993-09-04 00:00:00", + "1993-09-05 00:00:00", + "1993-09-11 00:00:00", + "1993-09-12 00:00:00", + "1993-09-18 00:00:00", + "1993-09-19 00:00:00", + "1993-09-25 00:00:00", + "1993-09-26 00:00:00", + "1993-10-02 00:00:00", + "1993-10-03 00:00:00", + "1993-10-09 00:00:00", + "1993-10-10 00:00:00", + "1993-10-16 00:00:00", + "1993-10-17 00:00:00", + "1993-10-23 00:00:00", + "1993-10-24 00:00:00", + "1993-10-30 00:00:00", + "1993-10-31 00:00:00", + "1993-11-06 00:00:00", + "1993-11-07 00:00:00", + "1993-11-13 00:00:00", + "1993-11-14 00:00:00", + "1993-11-20 00:00:00", + "1993-11-21 00:00:00", + "1993-11-27 00:00:00", + "1993-11-28 00:00:00", + "1993-12-04 00:00:00", + "1993-12-05 00:00:00", + "1993-12-11 00:00:00", + "1993-12-12 00:00:00", + "1993-12-18 00:00:00", + "1993-12-19 00:00:00", + "1993-12-25 00:00:00", + "1993-12-26 00:00:00", + "1994-01-01 00:00:00", + "1994-01-02 00:00:00", + "1994-01-08 00:00:00", + "1994-01-09 00:00:00", + "1994-01-15 00:00:00", + "1994-01-16 00:00:00", + "1994-01-22 00:00:00", + "1994-01-23 00:00:00", + "1994-01-29 00:00:00", + "1994-01-30 00:00:00", + "1994-02-05 00:00:00", + "1994-02-06 00:00:00", + "1994-02-12 00:00:00", + "1994-02-13 00:00:00", + "1994-02-19 00:00:00", + "1994-02-20 00:00:00", + "1994-02-26 00:00:00", + "1994-02-27 00:00:00", + "1994-03-05 00:00:00", + "1994-03-06 00:00:00", + "1994-03-12 00:00:00", + "1994-03-13 00:00:00", + "1994-03-19 00:00:00", + "1994-03-20 00:00:00", + "1994-03-26 00:00:00", + "1994-03-27 00:00:00", + "1994-04-02 00:00:00", + "1994-04-03 00:00:00", + "1994-04-09 00:00:00", + "1994-04-10 00:00:00", + "1994-04-16 00:00:00", + "1994-04-17 00:00:00", + "1994-04-23 00:00:00", + "1994-04-24 00:00:00", + "1994-04-30 00:00:00", + "1994-05-01 00:00:00", + "1994-05-07 00:00:00", + "1994-05-08 00:00:00", + "1994-05-14 00:00:00", + "1994-05-15 00:00:00", + "1994-05-21 00:00:00", + "1994-05-22 00:00:00", + "1994-05-28 00:00:00", + "1994-05-29 00:00:00", + "1994-06-04 00:00:00", + "1994-06-05 00:00:00", + "1994-06-11 00:00:00", + "1994-06-12 00:00:00", + "1994-06-18 00:00:00", + "1994-06-19 00:00:00", + "1994-06-25 00:00:00", + "1994-06-26 00:00:00", + "1994-07-02 00:00:00", + "1994-07-03 00:00:00", + "1994-07-09 00:00:00", + "1994-07-10 00:00:00", + "1994-07-16 00:00:00", + "1994-07-17 00:00:00", + "1994-07-23 00:00:00", + "1994-07-24 00:00:00", + "1994-07-30 00:00:00", + "1994-07-31 00:00:00", + "1994-08-06 00:00:00", + "1994-08-07 00:00:00", + "1994-08-13 00:00:00", + "1994-08-14 00:00:00", + "1994-08-20 00:00:00", + "1994-08-21 00:00:00", + "1994-08-27 00:00:00", + "1994-08-28 00:00:00", + "1994-09-03 00:00:00", + "1994-09-04 00:00:00", + "1994-09-10 00:00:00", + "1994-09-11 00:00:00", + "1994-09-17 00:00:00", + "1994-09-18 00:00:00", + "1994-09-24 00:00:00", + "1994-09-25 00:00:00", + "1994-10-01 00:00:00", + "1994-10-02 00:00:00", + "1994-10-08 00:00:00", + "1994-10-09 00:00:00", + "1994-10-15 00:00:00", + "1994-10-16 00:00:00", + "1994-10-22 00:00:00", + "1994-10-23 00:00:00", + "1994-10-29 00:00:00", + "1994-10-30 00:00:00", + "1994-11-05 00:00:00", + "1994-11-06 00:00:00", + "1994-11-12 00:00:00", + "1994-11-13 00:00:00", + "1994-11-19 00:00:00", + "1994-11-20 00:00:00", + "1994-11-26 00:00:00", + "1994-11-27 00:00:00", + "1994-12-03 00:00:00", + "1994-12-04 00:00:00", + "1994-12-10 00:00:00", + "1994-12-11 00:00:00", + "1994-12-17 00:00:00", + "1994-12-18 00:00:00", + "1994-12-24 00:00:00", + "1994-12-25 00:00:00", + "1994-12-31 00:00:00", + "1995-01-01 00:00:00", + "1995-01-07 00:00:00", + "1995-01-08 00:00:00", + "1995-01-14 00:00:00", + "1995-01-15 00:00:00", + "1995-01-21 00:00:00", + "1995-01-22 00:00:00", + "1995-01-28 00:00:00", + "1995-01-29 00:00:00", + "1995-02-04 00:00:00", + "1995-02-05 00:00:00", + "1995-02-11 00:00:00", + "1995-02-12 00:00:00", + "1995-02-18 00:00:00", + "1995-02-19 00:00:00", + "1995-02-25 00:00:00", + "1995-02-26 00:00:00", + "1995-03-04 00:00:00", + "1995-03-05 00:00:00", + "1995-03-11 00:00:00", + "1995-03-12 00:00:00", + "1995-03-18 00:00:00", + "1995-03-19 00:00:00", + "1995-03-25 00:00:00", + "1995-03-26 00:00:00", + "1995-04-01 00:00:00", + "1995-04-02 00:00:00", + "1995-04-08 00:00:00", + "1995-04-09 00:00:00", + "1995-04-15 00:00:00", + "1995-04-16 00:00:00", + "1995-04-22 00:00:00", + "1995-04-23 00:00:00", + "1995-04-29 00:00:00", + "1995-04-30 00:00:00", + "1995-05-06 00:00:00", + "1995-05-07 00:00:00", + "1995-05-13 00:00:00", + "1995-05-14 00:00:00", + "1995-05-20 00:00:00", + "1995-05-21 00:00:00", + "1995-05-27 00:00:00", + "1995-05-28 00:00:00", + "1995-06-03 00:00:00", + "1995-06-04 00:00:00", + "1995-06-10 00:00:00", + "1995-06-11 00:00:00", + "1995-06-17 00:00:00", + "1995-06-18 00:00:00", + "1995-06-24 00:00:00", + "1995-06-25 00:00:00", + "1995-07-01 00:00:00", + "1995-07-02 00:00:00", + "1995-07-08 00:00:00", + "1995-07-09 00:00:00", + "1995-07-15 00:00:00", + "1995-07-16 00:00:00", + "1995-07-22 00:00:00", + "1995-07-23 00:00:00", + "1995-07-29 00:00:00", + "1995-07-30 00:00:00", + "1995-08-05 00:00:00", + "1995-08-06 00:00:00", + "1995-08-12 00:00:00", + "1995-08-13 00:00:00", + "1995-08-19 00:00:00", + "1995-08-20 00:00:00", + "1995-08-26 00:00:00", + "1995-08-27 00:00:00", + "1995-09-02 00:00:00", + "1995-09-03 00:00:00", + "1995-09-09 00:00:00", + "1995-09-10 00:00:00", + "1995-09-16 00:00:00", + "1995-09-17 00:00:00", + "1995-09-23 00:00:00", + "1995-09-24 00:00:00", + "1995-09-30 00:00:00", + "1995-10-01 00:00:00", + "1995-10-07 00:00:00", + "1995-10-08 00:00:00", + "1995-10-14 00:00:00", + "1995-10-15 00:00:00", + "1995-10-21 00:00:00", + "1995-10-22 00:00:00", + "1995-10-28 00:00:00", + "1995-10-29 00:00:00", + "1995-11-04 00:00:00", + "1995-11-05 00:00:00", + "1995-11-11 00:00:00", + "1995-11-12 00:00:00", + "1995-11-18 00:00:00", + "1995-11-19 00:00:00", + "1995-11-25 00:00:00", + "1995-11-26 00:00:00", + "1995-12-02 00:00:00", + "1995-12-03 00:00:00", + "1995-12-09 00:00:00", + "1995-12-10 00:00:00", + "1995-12-16 00:00:00", + "1995-12-17 00:00:00", + "1995-12-23 00:00:00", + "1995-12-24 00:00:00", + "1995-12-30 00:00:00", + "1995-12-31 00:00:00", + "1996-01-06 00:00:00", + "1996-01-07 00:00:00", + "1996-01-13 00:00:00", + "1996-01-14 00:00:00", + "1996-01-20 00:00:00", + "1996-01-21 00:00:00", + "1996-01-27 00:00:00", + "1996-01-28 00:00:00", + "1996-02-03 00:00:00", + "1996-02-04 00:00:00", + "1996-02-10 00:00:00", + "1996-02-11 00:00:00", + "1996-02-17 00:00:00", + "1996-02-18 00:00:00", + "1996-02-24 00:00:00", + "1996-02-25 00:00:00", + "1996-03-02 00:00:00", + "1996-03-03 00:00:00", + "1996-03-09 00:00:00", + "1996-03-10 00:00:00", + "1996-03-16 00:00:00", + "1996-03-17 00:00:00", + "1996-03-23 00:00:00", + "1996-03-24 00:00:00", + "1996-03-30 00:00:00", + "1996-03-31 00:00:00", + "1996-04-06 00:00:00", + "1996-04-07 00:00:00", + "1996-04-13 00:00:00", + "1996-04-14 00:00:00", + "1996-04-20 00:00:00", + "1996-04-21 00:00:00", + "1996-04-27 00:00:00", + "1996-04-28 00:00:00", + "1996-05-04 00:00:00", + "1996-05-05 00:00:00", + "1996-05-11 00:00:00", + "1996-05-12 00:00:00", + "1996-05-18 00:00:00", + "1996-05-19 00:00:00", + "1996-05-25 00:00:00", + "1996-05-26 00:00:00", + "1996-06-01 00:00:00", + "1996-06-02 00:00:00", + "1996-06-08 00:00:00", + "1996-06-09 00:00:00", + "1996-06-15 00:00:00", + "1996-06-16 00:00:00", + "1996-06-22 00:00:00", + "1996-06-23 00:00:00", + "1996-06-29 00:00:00", + "1996-06-30 00:00:00", + "1996-07-06 00:00:00", + "1996-07-07 00:00:00", + "1996-07-13 00:00:00", + "1996-07-14 00:00:00", + "1996-07-20 00:00:00", + "1996-07-21 00:00:00", + "1996-07-27 00:00:00", + "1996-07-28 00:00:00", + "1996-08-03 00:00:00", + "1996-08-04 00:00:00", + "1996-08-10 00:00:00", + "1996-08-11 00:00:00", + "1996-08-17 00:00:00", + "1996-08-18 00:00:00", + "1996-08-24 00:00:00", + "1996-08-25 00:00:00", + "1996-08-31 00:00:00", + "1996-09-01 00:00:00", + "1996-09-07 00:00:00", + "1996-09-08 00:00:00", + "1996-09-14 00:00:00", + "1996-09-15 00:00:00", + "1996-09-21 00:00:00", + "1996-09-22 00:00:00", + "1996-09-28 00:00:00", + "1996-09-29 00:00:00", + "1996-10-05 00:00:00", + "1996-10-06 00:00:00", + "1996-10-12 00:00:00", + "1996-10-13 00:00:00", + "1996-10-19 00:00:00", + "1996-10-20 00:00:00", + "1996-10-26 00:00:00", + "1996-10-27 00:00:00", + "1996-11-02 00:00:00", + "1996-11-03 00:00:00", + "1996-11-09 00:00:00", + "1996-11-10 00:00:00", + "1996-11-16 00:00:00", + "1996-11-17 00:00:00", + "1996-11-23 00:00:00", + "1996-11-24 00:00:00", + "1996-11-30 00:00:00", + "1996-12-01 00:00:00", + "1996-12-07 00:00:00", + "1996-12-08 00:00:00", + "1996-12-14 00:00:00", + "1996-12-15 00:00:00", + "1996-12-21 00:00:00", + "1996-12-22 00:00:00", + "1996-12-28 00:00:00", + "1996-12-29 00:00:00", + "1997-01-04 00:00:00", + "1997-01-05 00:00:00", + "1997-01-11 00:00:00", + "1997-01-12 00:00:00", + "1997-01-18 00:00:00", + "1997-01-19 00:00:00", + "1997-01-25 00:00:00", + "1997-01-26 00:00:00", + "1997-02-01 00:00:00", + "1997-02-02 00:00:00", + "1997-02-08 00:00:00", + "1997-02-09 00:00:00", + "1997-02-15 00:00:00", + "1997-02-16 00:00:00", + "1997-02-22 00:00:00", + "1997-02-23 00:00:00", + "1997-03-01 00:00:00", + "1997-03-02 00:00:00", + "1997-03-08 00:00:00", + "1997-03-09 00:00:00", + "1997-03-15 00:00:00", + "1997-03-16 00:00:00", + "1997-03-22 00:00:00", + "1997-03-23 00:00:00", + "1997-03-29 00:00:00", + "1997-03-30 00:00:00", + "1997-04-05 00:00:00", + "1997-04-06 00:00:00", + "1997-04-12 00:00:00", + "1997-04-13 00:00:00", + "1997-04-19 00:00:00", + "1997-04-20 00:00:00", + "1997-04-26 00:00:00", + "1997-04-27 00:00:00", + "1997-05-03 00:00:00", + "1997-05-04 00:00:00", + "1997-05-10 00:00:00", + "1997-05-11 00:00:00", + "1997-05-17 00:00:00", + "1997-05-18 00:00:00", + "1997-05-24 00:00:00", + "1997-05-25 00:00:00", + "1997-05-31 00:00:00", + "1997-06-01 00:00:00", + "1997-06-07 00:00:00", + "1997-06-08 00:00:00", + "1997-06-14 00:00:00", + "1997-06-15 00:00:00", + "1997-06-21 00:00:00", + "1997-06-22 00:00:00", + "1997-06-28 00:00:00", + "1997-06-29 00:00:00", + "1997-07-05 00:00:00", + "1997-07-06 00:00:00", + "1997-07-12 00:00:00", + "1997-07-13 00:00:00", + "1997-07-19 00:00:00", + "1997-07-20 00:00:00", + "1997-07-26 00:00:00", + "1997-07-27 00:00:00", + "1997-08-02 00:00:00", + "1997-08-03 00:00:00", + "1997-08-09 00:00:00", + "1997-08-10 00:00:00", + "1997-08-16 00:00:00", + "1997-08-17 00:00:00", + "1997-08-23 00:00:00", + "1997-08-24 00:00:00", + "1997-08-30 00:00:00", + "1997-08-31 00:00:00", + "1997-09-06 00:00:00", + "1997-09-07 00:00:00", + "1997-09-13 00:00:00", + "1997-09-14 00:00:00", + "1997-09-20 00:00:00", + "1997-09-21 00:00:00", + "1997-09-27 00:00:00", + "1997-09-28 00:00:00", + "1997-10-04 00:00:00", + "1997-10-05 00:00:00", + "1997-10-11 00:00:00", + "1997-10-12 00:00:00", + "1997-10-18 00:00:00", + "1997-10-19 00:00:00", + "1997-10-25 00:00:00", + "1997-10-26 00:00:00", + "1997-11-01 00:00:00", + "1997-11-02 00:00:00", + "1997-11-08 00:00:00", + "1997-11-09 00:00:00", + "1997-11-15 00:00:00", + "1997-11-16 00:00:00", + "1997-11-22 00:00:00", + "1997-11-23 00:00:00", + "1997-11-29 00:00:00", + "1997-11-30 00:00:00", + "1997-12-06 00:00:00", + "1997-12-07 00:00:00", + "1997-12-13 00:00:00", + "1997-12-14 00:00:00", + "1997-12-20 00:00:00", + "1997-12-21 00:00:00", + "1997-12-27 00:00:00", + "1997-12-28 00:00:00", + "1998-01-03 00:00:00", + "1998-01-04 00:00:00", + "1998-01-10 00:00:00", + "1998-01-11 00:00:00", + "1998-01-17 00:00:00", + "1998-01-18 00:00:00", + "1998-01-24 00:00:00", + "1998-01-25 00:00:00", + "1998-01-31 00:00:00", + "1998-02-01 00:00:00", + "1998-02-07 00:00:00", + "1998-02-08 00:00:00", + "1998-02-14 00:00:00", + "1998-02-15 00:00:00", + "1998-02-21 00:00:00", + "1998-02-22 00:00:00", + "1998-02-28 00:00:00", + "1998-03-01 00:00:00", + "1998-03-07 00:00:00", + "1998-03-08 00:00:00", + "1998-03-14 00:00:00", + "1998-03-15 00:00:00", + "1998-03-21 00:00:00", + "1998-03-22 00:00:00", + "1998-03-28 00:00:00", + "1998-03-29 00:00:00", + "1998-04-04 00:00:00", + "1998-04-05 00:00:00", + "1998-04-11 00:00:00", + "1998-04-12 00:00:00", + "1998-04-18 00:00:00", + "1998-04-19 00:00:00", + "1998-04-25 00:00:00", + "1998-04-26 00:00:00", + "1998-05-02 00:00:00", + "1998-05-03 00:00:00", + "1998-05-09 00:00:00", + "1998-05-10 00:00:00", + "1998-05-16 00:00:00", + "1998-05-17 00:00:00", + "1998-05-23 00:00:00", + "1998-05-24 00:00:00", + "1998-05-30 00:00:00", + "1998-05-31 00:00:00", + "1998-06-06 00:00:00", + "1998-06-07 00:00:00", + "1998-06-13 00:00:00", + "1998-06-14 00:00:00", + "1998-06-20 00:00:00", + "1998-06-21 00:00:00", + "1998-06-27 00:00:00", + "1998-06-28 00:00:00", + "1998-07-04 00:00:00", + "1998-07-05 00:00:00", + "1998-07-11 00:00:00", + "1998-07-12 00:00:00", + "1998-07-18 00:00:00", + "1998-07-19 00:00:00", + "1998-07-25 00:00:00", + "1998-07-26 00:00:00", + "1998-08-01 00:00:00", + "1998-08-02 00:00:00", + "1998-08-08 00:00:00", + "1998-08-09 00:00:00", + "1998-08-15 00:00:00", + "1998-08-16 00:00:00", + "1998-08-22 00:00:00", + "1998-08-23 00:00:00", + "1998-08-29 00:00:00", + "1998-08-30 00:00:00", + "1998-09-05 00:00:00", + "1998-09-06 00:00:00", + "1998-09-12 00:00:00", + "1998-09-13 00:00:00", + "1998-09-19 00:00:00", + "1998-09-20 00:00:00", + "1998-09-26 00:00:00", + "1998-09-27 00:00:00", + "1998-10-03 00:00:00", + "1998-10-04 00:00:00", + "1998-10-10 00:00:00", + "1998-10-11 00:00:00", + "1998-10-17 00:00:00", + "1998-10-18 00:00:00", + "1998-10-24 00:00:00", + "1998-10-25 00:00:00", + "1998-10-31 00:00:00", + "1998-11-01 00:00:00", + "1998-11-07 00:00:00", + "1998-11-08 00:00:00", + "1998-11-14 00:00:00", + "1998-11-15 00:00:00", + "1998-11-21 00:00:00", + "1998-11-22 00:00:00", + "1998-11-28 00:00:00", + "1998-11-29 00:00:00", + "1998-12-05 00:00:00", + "1998-12-06 00:00:00", + "1998-12-12 00:00:00", + "1998-12-13 00:00:00", + "1998-12-19 00:00:00", + "1998-12-20 00:00:00", + "1998-12-26 00:00:00", + "1998-12-27 00:00:00", + "1999-01-02 00:00:00", + "1999-01-03 00:00:00", + "1999-01-09 00:00:00", + "1999-01-10 00:00:00", + "1999-01-16 00:00:00", + "1999-01-17 00:00:00", + "1999-01-23 00:00:00", + "1999-01-24 00:00:00", + "1999-01-30 00:00:00", + "1999-01-31 00:00:00", + "1999-02-06 00:00:00", + "1999-02-07 00:00:00", + "1999-02-13 00:00:00", + "1999-02-14 00:00:00", + "1999-02-20 00:00:00", + "1999-02-21 00:00:00", + "1999-02-27 00:00:00", + "1999-02-28 00:00:00", + "1999-03-06 00:00:00", + "1999-03-07 00:00:00", + "1999-03-13 00:00:00", + "1999-03-14 00:00:00", + "1999-03-20 00:00:00", + "1999-03-21 00:00:00", + "1999-03-27 00:00:00", + "1999-03-28 00:00:00", + "1999-04-03 00:00:00", + "1999-04-04 00:00:00", + "1999-04-10 00:00:00", + "1999-04-11 00:00:00", + "1999-04-17 00:00:00", + "1999-04-18 00:00:00", + "1999-04-24 00:00:00", + "1999-04-25 00:00:00", + "1999-05-01 00:00:00", + "1999-05-02 00:00:00", + "1999-05-08 00:00:00", + "1999-05-09 00:00:00", + "1999-05-15 00:00:00", + "1999-05-16 00:00:00", + "1999-05-22 00:00:00", + "1999-05-23 00:00:00", + "1999-05-29 00:00:00", + "1999-05-30 00:00:00", + "1999-06-05 00:00:00", + "1999-06-06 00:00:00", + "1999-06-12 00:00:00", + "1999-06-13 00:00:00", + "1999-06-19 00:00:00", + "1999-06-20 00:00:00", + "1999-06-26 00:00:00", + "1999-06-27 00:00:00", + "1999-07-03 00:00:00", + "1999-07-04 00:00:00", + "1999-07-10 00:00:00", + "1999-07-11 00:00:00", + "1999-07-17 00:00:00", + "1999-07-18 00:00:00", + "1999-07-24 00:00:00", + "1999-07-25 00:00:00", + "1999-07-31 00:00:00", + "1999-08-01 00:00:00", + "1999-08-07 00:00:00", + "1999-08-08 00:00:00", + "1999-08-14 00:00:00", + "1999-08-15 00:00:00", + "1999-08-21 00:00:00", + "1999-08-22 00:00:00", + "1999-08-28 00:00:00", + "1999-08-29 00:00:00", + "1999-09-04 00:00:00", + "1999-09-05 00:00:00", + "1999-09-11 00:00:00", + "1999-09-12 00:00:00", + "1999-09-18 00:00:00", + "1999-09-19 00:00:00", + "1999-09-25 00:00:00", + "1999-09-26 00:00:00", + "1999-10-02 00:00:00", + "1999-10-03 00:00:00", + "1999-10-09 00:00:00", + "1999-10-10 00:00:00", + "1999-10-16 00:00:00", + "1999-10-17 00:00:00", + "1999-10-23 00:00:00", + "1999-10-24 00:00:00", + "1999-10-30 00:00:00", + "1999-10-31 00:00:00", + "1999-11-06 00:00:00", + "1999-11-07 00:00:00", + "1999-11-13 00:00:00", + "1999-11-14 00:00:00", + "1999-11-20 00:00:00", + "1999-11-21 00:00:00", + "1999-11-27 00:00:00", + "1999-11-28 00:00:00", + "1999-12-04 00:00:00", + "1999-12-05 00:00:00", + "1999-12-11 00:00:00", + "1999-12-12 00:00:00", + "1999-12-18 00:00:00", + "1999-12-19 00:00:00", + "1999-12-25 00:00:00", + "1999-12-26 00:00:00", + "2000-01-01 00:00:00", + "2000-01-02 00:00:00", + "2000-01-08 00:00:00", + "2000-01-09 00:00:00", + "2000-01-15 00:00:00", + "2000-01-16 00:00:00", + "2000-01-22 00:00:00", + "2000-01-23 00:00:00", + "2000-01-29 00:00:00", + "2000-01-30 00:00:00", + "2000-02-05 00:00:00", + "2000-02-06 00:00:00", + "2000-02-12 00:00:00", + "2000-02-13 00:00:00", + "2000-02-19 00:00:00", + "2000-02-20 00:00:00", + "2000-02-26 00:00:00", + "2000-02-27 00:00:00", + "2000-03-04 00:00:00", + "2000-03-05 00:00:00", + "2000-03-11 00:00:00", + "2000-03-12 00:00:00", + "2000-03-18 00:00:00", + "2000-03-19 00:00:00", + "2000-03-25 00:00:00", + "2000-03-26 00:00:00", + "2000-04-01 00:00:00", + "2000-04-02 00:00:00", + "2000-04-08 00:00:00", + "2000-04-09 00:00:00", + "2000-04-15 00:00:00", + "2000-04-16 00:00:00", + "2000-04-22 00:00:00", + "2000-04-23 00:00:00", + "2000-04-29 00:00:00", + "2000-04-30 00:00:00", + "2000-05-06 00:00:00", + "2000-05-07 00:00:00", + "2000-05-13 00:00:00", + "2000-05-14 00:00:00", + "2000-05-20 00:00:00", + "2000-05-21 00:00:00", + "2000-05-27 00:00:00", + "2000-05-28 00:00:00", + "2000-06-03 00:00:00", + "2000-06-04 00:00:00", + "2000-06-10 00:00:00", + "2000-06-11 00:00:00", + "2000-06-17 00:00:00", + "2000-06-18 00:00:00", + "2000-06-24 00:00:00", + "2000-06-25 00:00:00", + "2000-07-01 00:00:00", + "2000-07-02 00:00:00", + "2000-07-08 00:00:00", + "2000-07-09 00:00:00", + "2000-07-15 00:00:00", + "2000-07-16 00:00:00", + "2000-07-22 00:00:00", + "2000-07-23 00:00:00", + "2000-07-29 00:00:00", + "2000-07-30 00:00:00", + "2000-08-05 00:00:00", + "2000-08-06 00:00:00", + "2000-08-12 00:00:00", + "2000-08-13 00:00:00", + "2000-08-19 00:00:00", + "2000-08-20 00:00:00", + "2000-08-26 00:00:00", + "2000-08-27 00:00:00", + "2000-09-02 00:00:00", + "2000-09-03 00:00:00", + "2000-09-09 00:00:00", + "2000-09-10 00:00:00", + "2000-09-16 00:00:00", + "2000-09-17 00:00:00", + "2000-09-23 00:00:00", + "2000-09-24 00:00:00", + "2000-09-30 00:00:00", + "2000-10-01 00:00:00", + "2000-10-07 00:00:00", + "2000-10-08 00:00:00", + "2000-10-14 00:00:00", + "2000-10-15 00:00:00", + "2000-10-21 00:00:00", + "2000-10-22 00:00:00", + "2000-10-28 00:00:00", + "2000-10-29 00:00:00", + "2000-11-04 00:00:00", + "2000-11-05 00:00:00", + "2000-11-11 00:00:00", + "2000-11-12 00:00:00", + "2000-11-18 00:00:00", + "2000-11-19 00:00:00", + "2000-11-25 00:00:00", + "2000-11-26 00:00:00", + "2000-12-02 00:00:00", + "2000-12-03 00:00:00", + "2000-12-09 00:00:00", + "2000-12-10 00:00:00", + "2000-12-16 00:00:00", + "2000-12-17 00:00:00", + "2000-12-23 00:00:00", + "2000-12-24 00:00:00", + "2000-12-30 00:00:00", + "2000-12-31 00:00:00", + "2001-01-06 00:00:00", + "2001-01-07 00:00:00", + "2001-01-13 00:00:00", + "2001-01-14 00:00:00", + "2001-01-20 00:00:00", + "2001-01-21 00:00:00", + "2001-01-27 00:00:00", + "2001-01-28 00:00:00", + "2001-02-03 00:00:00", + "2001-02-04 00:00:00", + "2001-02-10 00:00:00", + "2001-02-11 00:00:00", + "2001-02-17 00:00:00", + "2001-02-18 00:00:00", + "2001-02-24 00:00:00", + "2001-02-25 00:00:00", + "2001-03-03 00:00:00", + "2001-03-04 00:00:00", + "2001-03-10 00:00:00", + "2001-03-11 00:00:00", + "2001-03-17 00:00:00", + "2001-03-18 00:00:00", + "2001-03-24 00:00:00", + "2001-03-25 00:00:00", + "2001-03-31 00:00:00", + "2001-04-01 00:00:00", + "2001-04-07 00:00:00", + "2001-04-08 00:00:00", + "2001-04-14 00:00:00", + "2001-04-15 00:00:00", + "2001-04-21 00:00:00", + "2001-04-22 00:00:00", + "2001-04-28 00:00:00", + "2001-04-29 00:00:00", + "2001-05-05 00:00:00", + "2001-05-06 00:00:00", + "2001-05-12 00:00:00", + "2001-05-13 00:00:00", + "2001-05-19 00:00:00", + "2001-05-20 00:00:00", + "2001-05-26 00:00:00", + "2001-05-27 00:00:00", + "2001-06-02 00:00:00", + "2001-06-03 00:00:00", + "2001-06-09 00:00:00", + "2001-06-10 00:00:00", + "2001-06-16 00:00:00", + "2001-06-17 00:00:00", + "2001-06-23 00:00:00", + "2001-06-24 00:00:00", + "2001-06-30 00:00:00", + "2001-07-01 00:00:00", + "2001-07-07 00:00:00", + "2001-07-08 00:00:00", + "2001-07-14 00:00:00", + "2001-07-15 00:00:00", + "2001-07-21 00:00:00", + "2001-07-22 00:00:00", + "2001-07-28 00:00:00", + "2001-07-29 00:00:00", + "2001-08-04 00:00:00", + "2001-08-05 00:00:00", + "2001-08-11 00:00:00", + "2001-08-12 00:00:00", + "2001-08-18 00:00:00", + "2001-08-19 00:00:00", + "2001-08-25 00:00:00", + "2001-08-26 00:00:00", + "2001-09-01 00:00:00", + "2001-09-02 00:00:00", + "2001-09-08 00:00:00", + "2001-09-09 00:00:00", + "2001-09-15 00:00:00", + "2001-09-16 00:00:00", + "2001-09-22 00:00:00", + "2001-09-23 00:00:00", + "2001-09-29 00:00:00", + "2001-09-30 00:00:00", + "2001-10-06 00:00:00", + "2001-10-07 00:00:00", + "2001-10-13 00:00:00", + "2001-10-14 00:00:00", + "2001-10-20 00:00:00", + "2001-10-21 00:00:00", + "2001-10-27 00:00:00", + "2001-10-28 00:00:00", + "2001-11-03 00:00:00", + "2001-11-04 00:00:00", + "2001-11-10 00:00:00", + "2001-11-11 00:00:00", + "2001-11-17 00:00:00", + "2001-11-18 00:00:00", + "2001-11-24 00:00:00", + "2001-11-25 00:00:00", + "2001-12-01 00:00:00", + "2001-12-02 00:00:00", + "2001-12-08 00:00:00", + "2001-12-09 00:00:00", + "2001-12-15 00:00:00", + "2001-12-16 00:00:00", + "2001-12-22 00:00:00", + "2001-12-23 00:00:00", + "2001-12-29 00:00:00", + "2001-12-30 00:00:00", + "2002-01-05 00:00:00", + "2002-01-06 00:00:00", + "2002-01-12 00:00:00", + "2002-01-13 00:00:00", + "2002-01-19 00:00:00", + "2002-01-20 00:00:00", + "2002-01-26 00:00:00", + "2002-01-27 00:00:00", + "2002-02-02 00:00:00", + "2002-02-03 00:00:00", + "2002-02-09 00:00:00", + "2002-02-10 00:00:00", + "2002-02-16 00:00:00", + "2002-02-17 00:00:00", + "2002-02-23 00:00:00", + "2002-02-24 00:00:00", + "2002-03-02 00:00:00", + "2002-03-03 00:00:00", + "2002-03-09 00:00:00", + "2002-03-10 00:00:00", + "2002-03-16 00:00:00", + "2002-03-17 00:00:00", + "2002-03-23 00:00:00", + "2002-03-24 00:00:00", + "2002-03-30 00:00:00", + "2002-03-31 00:00:00", + "2002-04-06 00:00:00", + "2002-04-07 00:00:00", + "2002-04-13 00:00:00", + "2002-04-14 00:00:00", + "2002-04-20 00:00:00", + "2002-04-21 00:00:00", + "2002-04-27 00:00:00", + "2002-04-28 00:00:00", + "2002-05-04 00:00:00", + "2002-05-05 00:00:00", + "2002-05-11 00:00:00", + "2002-05-12 00:00:00", + "2002-05-18 00:00:00", + "2002-05-19 00:00:00", + "2002-05-25 00:00:00", + "2002-05-26 00:00:00", + "2002-06-01 00:00:00", + "2002-06-02 00:00:00", + "2002-06-08 00:00:00", + "2002-06-09 00:00:00", + "2002-06-15 00:00:00", + "2002-06-16 00:00:00", + "2002-06-22 00:00:00", + "2002-06-23 00:00:00", + "2002-06-29 00:00:00", + "2002-06-30 00:00:00", + "2002-07-06 00:00:00", + "2002-07-07 00:00:00", + "2002-07-13 00:00:00", + "2002-07-14 00:00:00", + "2002-07-20 00:00:00", + "2002-07-21 00:00:00", + "2002-07-27 00:00:00", + "2002-07-28 00:00:00", + "2002-08-03 00:00:00", + "2002-08-04 00:00:00", + "2002-08-10 00:00:00", + "2002-08-11 00:00:00", + "2002-08-17 00:00:00", + "2002-08-18 00:00:00", + "2002-08-24 00:00:00", + "2002-08-25 00:00:00", + "2002-08-31 00:00:00", + "2002-09-01 00:00:00", + "2002-09-07 00:00:00", + "2002-09-08 00:00:00", + "2002-09-14 00:00:00", + "2002-09-15 00:00:00", + "2002-09-21 00:00:00", + "2002-09-22 00:00:00", + "2002-09-28 00:00:00", + "2002-09-29 00:00:00", + "2002-10-05 00:00:00", + "2002-10-06 00:00:00", + "2002-10-12 00:00:00", + "2002-10-13 00:00:00", + "2002-10-19 00:00:00", + "2002-10-20 00:00:00", + "2002-10-26 00:00:00", + "2002-10-27 00:00:00", + "2002-11-02 00:00:00", + "2002-11-03 00:00:00", + "2002-11-09 00:00:00", + "2002-11-10 00:00:00", + "2002-11-16 00:00:00", + "2002-11-17 00:00:00", + "2002-11-23 00:00:00", + "2002-11-24 00:00:00", + "2002-11-30 00:00:00", + "2002-12-01 00:00:00", + "2002-12-07 00:00:00", + "2002-12-08 00:00:00", + "2002-12-14 00:00:00", + "2002-12-15 00:00:00", + "2002-12-21 00:00:00", + "2002-12-22 00:00:00", + "2002-12-28 00:00:00", + "2002-12-29 00:00:00", + "2003-01-04 00:00:00", + "2003-01-05 00:00:00", + "2003-01-11 00:00:00", + "2003-01-12 00:00:00", + "2003-01-18 00:00:00", + "2003-01-19 00:00:00", + "2003-01-25 00:00:00", + "2003-01-26 00:00:00", + "2003-02-01 00:00:00", + "2003-02-02 00:00:00", + "2003-02-08 00:00:00", + "2003-02-09 00:00:00", + "2003-02-15 00:00:00", + "2003-02-16 00:00:00", + "2003-02-22 00:00:00", + "2003-02-23 00:00:00", + "2003-03-01 00:00:00", + "2003-03-02 00:00:00", + "2003-03-08 00:00:00", + "2003-03-09 00:00:00", + "2003-03-15 00:00:00", + "2003-03-16 00:00:00", + "2003-03-22 00:00:00", + "2003-03-23 00:00:00", + "2003-03-29 00:00:00", + "2003-03-30 00:00:00", + "2003-04-05 00:00:00", + "2003-04-06 00:00:00", + "2003-04-12 00:00:00", + "2003-04-13 00:00:00", + "2003-04-19 00:00:00", + "2003-04-20 00:00:00", + "2003-04-26 00:00:00", + "2003-04-27 00:00:00", + "2003-05-03 00:00:00", + "2003-05-04 00:00:00", + "2003-05-10 00:00:00", + "2003-05-11 00:00:00", + "2003-05-17 00:00:00", + "2003-05-18 00:00:00", + "2003-05-24 00:00:00", + "2003-05-25 00:00:00", + "2003-05-31 00:00:00", + "2003-06-01 00:00:00", + "2003-06-07 00:00:00", + "2003-06-08 00:00:00", + "2003-06-14 00:00:00", + "2003-06-15 00:00:00", + "2003-06-21 00:00:00", + "2003-06-22 00:00:00", + "2003-06-28 00:00:00", + "2003-06-29 00:00:00", + "2003-07-05 00:00:00", + "2003-07-06 00:00:00", + "2003-07-12 00:00:00", + "2003-07-13 00:00:00", + "2003-07-19 00:00:00", + "2003-07-20 00:00:00", + "2003-07-26 00:00:00", + "2003-07-27 00:00:00", + "2003-08-02 00:00:00", + "2003-08-03 00:00:00", + "2003-08-09 00:00:00", + "2003-08-10 00:00:00", + "2003-08-16 00:00:00", + "2003-08-17 00:00:00", + "2003-08-23 00:00:00", + "2003-08-24 00:00:00", + "2003-08-30 00:00:00", + "2003-08-31 00:00:00", + "2003-09-06 00:00:00", + "2003-09-07 00:00:00", + "2003-09-13 00:00:00", + "2003-09-14 00:00:00", + "2003-09-20 00:00:00", + "2003-09-21 00:00:00", + "2003-09-27 00:00:00", + "2003-09-28 00:00:00", + "2003-10-04 00:00:00", + "2003-10-05 00:00:00", + "2003-10-11 00:00:00", + "2003-10-12 00:00:00", + "2003-10-18 00:00:00", + "2003-10-19 00:00:00", + "2003-10-25 00:00:00", + "2003-10-26 00:00:00", + "2003-11-01 00:00:00", + "2003-11-02 00:00:00", + "2003-11-08 00:00:00", + "2003-11-09 00:00:00", + "2003-11-15 00:00:00", + "2003-11-16 00:00:00", + "2003-11-22 00:00:00", + "2003-11-23 00:00:00", + "2003-11-29 00:00:00", + "2003-11-30 00:00:00", + "2003-12-06 00:00:00", + "2003-12-07 00:00:00", + "2003-12-13 00:00:00", + "2003-12-14 00:00:00", + "2003-12-20 00:00:00", + "2003-12-21 00:00:00", + "2003-12-27 00:00:00", + "2003-12-28 00:00:00", + "2004-01-03 00:00:00", + "2004-01-04 00:00:00", + "2004-01-10 00:00:00", + "2004-01-11 00:00:00", + "2004-01-17 00:00:00", + "2004-01-18 00:00:00", + "2004-01-24 00:00:00", + "2004-01-25 00:00:00", + "2004-01-31 00:00:00", + "2004-02-01 00:00:00", + "2004-02-07 00:00:00", + "2004-02-08 00:00:00", + "2004-02-14 00:00:00", + "2004-02-15 00:00:00", + "2004-02-21 00:00:00", + "2004-02-22 00:00:00", + "2004-02-28 00:00:00", + "2004-02-29 00:00:00", + "2004-03-06 00:00:00", + "2004-03-07 00:00:00", + "2004-03-13 00:00:00", + "2004-03-14 00:00:00", + "2004-03-20 00:00:00", + "2004-03-21 00:00:00", + "2004-03-27 00:00:00", + "2004-03-28 00:00:00", + "2004-04-03 00:00:00", + "2004-04-04 00:00:00", + "2004-04-10 00:00:00", + "2004-04-11 00:00:00", + "2004-04-17 00:00:00", + "2004-04-18 00:00:00", + "2004-04-24 00:00:00", + "2004-04-25 00:00:00", + "2004-05-01 00:00:00", + "2004-05-02 00:00:00", + "2004-05-08 00:00:00", + "2004-05-09 00:00:00", + "2004-05-15 00:00:00", + "2004-05-16 00:00:00", + "2004-05-22 00:00:00", + "2004-05-23 00:00:00", + "2004-05-29 00:00:00", + "2004-05-30 00:00:00", + "2004-06-05 00:00:00", + "2004-06-06 00:00:00", + "2004-06-12 00:00:00", + "2004-06-13 00:00:00", + "2004-06-19 00:00:00", + "2004-06-20 00:00:00", + "2004-06-26 00:00:00", + "2004-06-27 00:00:00", + "2004-07-03 00:00:00", + "2004-07-04 00:00:00", + "2004-07-10 00:00:00", + "2004-07-11 00:00:00", + "2004-07-17 00:00:00", + "2004-07-18 00:00:00", + "2004-07-24 00:00:00", + "2004-07-25 00:00:00", + "2004-07-31 00:00:00", + "2004-08-01 00:00:00", + "2004-08-07 00:00:00", + "2004-08-08 00:00:00", + "2004-08-14 00:00:00", + "2004-08-15 00:00:00", + "2004-08-21 00:00:00", + "2004-08-22 00:00:00", + "2004-08-28 00:00:00", + "2004-08-29 00:00:00", + "2004-09-04 00:00:00", + "2004-09-05 00:00:00", + "2004-09-11 00:00:00", + "2004-09-12 00:00:00", + "2004-09-18 00:00:00", + "2004-09-19 00:00:00", + "2004-09-25 00:00:00", + "2004-09-26 00:00:00", + "2004-10-02 00:00:00", + "2004-10-03 00:00:00", + "2004-10-09 00:00:00", + "2004-10-10 00:00:00", + "2004-10-16 00:00:00", + "2004-10-17 00:00:00", + "2004-10-23 00:00:00", + "2004-10-24 00:00:00", + "2004-10-30 00:00:00", + "2004-10-31 00:00:00", + "2004-11-06 00:00:00", + "2004-11-07 00:00:00", + "2004-11-13 00:00:00", + "2004-11-14 00:00:00", + "2004-11-20 00:00:00", + "2004-11-21 00:00:00", + "2004-11-27 00:00:00", + "2004-11-28 00:00:00", + "2004-12-04 00:00:00", + "2004-12-05 00:00:00", + "2004-12-11 00:00:00", + "2004-12-12 00:00:00", + "2004-12-18 00:00:00", + "2004-12-19 00:00:00", + "2004-12-25 00:00:00", + "2004-12-26 00:00:00", + "2005-01-01 00:00:00", + "2005-01-02 00:00:00", + "2005-01-08 00:00:00", + "2005-01-09 00:00:00", + "2005-01-15 00:00:00", + "2005-01-16 00:00:00", + "2005-01-22 00:00:00", + "2005-01-23 00:00:00", + "2005-01-29 00:00:00", + "2005-01-30 00:00:00", + "2005-02-05 00:00:00", + "2005-02-06 00:00:00", + "2005-02-12 00:00:00", + "2005-02-13 00:00:00", + "2005-02-19 00:00:00", + "2005-02-20 00:00:00", + "2005-02-26 00:00:00", + "2005-02-27 00:00:00", + "2005-03-05 00:00:00", + "2005-03-06 00:00:00", + "2005-03-12 00:00:00", + "2005-03-13 00:00:00", + "2005-03-19 00:00:00", + "2005-03-20 00:00:00", + "2005-03-26 00:00:00", + "2005-03-27 00:00:00", + "2005-04-02 00:00:00", + "2005-04-03 00:00:00", + "2005-04-09 00:00:00", + "2005-04-10 00:00:00", + "2005-04-16 00:00:00", + "2005-04-17 00:00:00", + "2005-04-23 00:00:00", + "2005-04-24 00:00:00", + "2005-04-30 00:00:00", + "2005-05-01 00:00:00", + "2005-05-07 00:00:00", + "2005-05-08 00:00:00", + "2005-05-14 00:00:00", + "2005-05-15 00:00:00", + "2005-05-21 00:00:00", + "2005-05-22 00:00:00", + "2005-05-28 00:00:00", + "2005-05-29 00:00:00", + "2005-06-04 00:00:00", + "2005-06-05 00:00:00", + "2005-06-11 00:00:00", + "2005-06-12 00:00:00", + "2005-06-18 00:00:00", + "2005-06-19 00:00:00", + "2005-06-25 00:00:00", + "2005-06-26 00:00:00", + "2005-07-02 00:00:00", + "2005-07-03 00:00:00", + "2005-07-09 00:00:00", + "2005-07-10 00:00:00", + "2005-07-16 00:00:00", + "2005-07-17 00:00:00", + "2005-07-23 00:00:00", + "2005-07-24 00:00:00", + "2005-07-30 00:00:00", + "2005-07-31 00:00:00", + "2005-08-06 00:00:00", + "2005-08-07 00:00:00", + "2005-08-13 00:00:00", + "2005-08-14 00:00:00", + "2005-08-20 00:00:00", + "2005-08-21 00:00:00", + "2005-08-27 00:00:00", + "2005-08-28 00:00:00", + "2005-09-03 00:00:00", + "2005-09-04 00:00:00", + "2005-09-10 00:00:00", + "2005-09-11 00:00:00", + "2005-09-17 00:00:00", + "2005-09-18 00:00:00", + "2005-09-24 00:00:00", + "2005-09-25 00:00:00", + "2005-10-01 00:00:00", + "2005-10-02 00:00:00", + "2005-10-08 00:00:00", + "2005-10-09 00:00:00", + "2005-10-15 00:00:00", + "2005-10-16 00:00:00", + "2005-10-22 00:00:00", + "2005-10-23 00:00:00", + "2005-10-29 00:00:00", + "2005-10-30 00:00:00", + "2005-11-05 00:00:00", + "2005-11-06 00:00:00", + "2005-11-12 00:00:00", + "2005-11-13 00:00:00", + "2005-11-19 00:00:00", + "2005-11-20 00:00:00", + "2005-11-26 00:00:00", + "2005-11-27 00:00:00", + "2005-12-03 00:00:00", + "2005-12-04 00:00:00", + "2005-12-10 00:00:00", + "2005-12-11 00:00:00", + "2005-12-17 00:00:00", + "2005-12-18 00:00:00", + "2005-12-24 00:00:00", + "2005-12-25 00:00:00", + "2005-12-31 00:00:00", + "2006-01-01 00:00:00", + "2006-01-07 00:00:00", + "2006-01-08 00:00:00", + "2006-01-14 00:00:00", + "2006-01-15 00:00:00", + "2006-01-21 00:00:00", + "2006-01-22 00:00:00", + "2006-01-28 00:00:00", + "2006-01-29 00:00:00", + "2006-02-04 00:00:00", + "2006-02-05 00:00:00", + "2006-02-11 00:00:00", + "2006-02-12 00:00:00", + "2006-02-18 00:00:00", + "2006-02-19 00:00:00", + "2006-02-25 00:00:00", + "2006-02-26 00:00:00", + "2006-03-04 00:00:00", + "2006-03-05 00:00:00", + "2006-03-11 00:00:00", + "2006-03-12 00:00:00", + "2006-03-18 00:00:00", + "2006-03-19 00:00:00", + "2006-03-25 00:00:00", + "2006-03-26 00:00:00", + "2006-04-01 00:00:00", + "2006-04-02 00:00:00", + "2006-04-08 00:00:00", + "2006-04-09 00:00:00", + "2006-04-15 00:00:00", + "2006-04-16 00:00:00", + "2006-04-22 00:00:00", + "2006-04-23 00:00:00", + "2006-04-29 00:00:00", + "2006-04-30 00:00:00", + "2006-05-06 00:00:00", + "2006-05-07 00:00:00", + "2006-05-13 00:00:00", + "2006-05-14 00:00:00", + "2006-05-20 00:00:00", + "2006-05-21 00:00:00", + "2006-05-27 00:00:00", + "2006-05-28 00:00:00", + "2006-06-03 00:00:00", + "2006-06-04 00:00:00", + "2006-06-10 00:00:00", + "2006-06-11 00:00:00", + "2006-06-17 00:00:00", + "2006-06-18 00:00:00", + "2006-06-24 00:00:00", + "2006-06-25 00:00:00", + "2006-07-01 00:00:00", + "2006-07-02 00:00:00", + "2006-07-08 00:00:00", + "2006-07-09 00:00:00", + "2006-07-15 00:00:00", + "2006-07-16 00:00:00", + "2006-07-22 00:00:00", + "2006-07-23 00:00:00", + "2006-07-29 00:00:00", + "2006-07-30 00:00:00", + "2006-08-05 00:00:00", + "2006-08-06 00:00:00", + "2006-08-12 00:00:00", + "2006-08-13 00:00:00", + "2006-08-19 00:00:00", + "2006-08-20 00:00:00", + "2006-08-26 00:00:00", + "2006-08-27 00:00:00", + "2006-09-02 00:00:00", + "2006-09-03 00:00:00", + "2006-09-09 00:00:00", + "2006-09-10 00:00:00", + "2006-09-16 00:00:00", + "2006-09-17 00:00:00", + "2006-09-23 00:00:00", + "2006-09-24 00:00:00", + "2006-09-30 00:00:00", + "2006-10-01 00:00:00", + "2006-10-07 00:00:00", + "2006-10-08 00:00:00", + "2006-10-14 00:00:00", + "2006-10-15 00:00:00", + "2006-10-21 00:00:00", + "2006-10-22 00:00:00", + "2006-10-28 00:00:00", + "2006-10-29 00:00:00", + "2006-11-04 00:00:00", + "2006-11-05 00:00:00", + "2006-11-11 00:00:00", + "2006-11-12 00:00:00", + "2006-11-18 00:00:00", + "2006-11-19 00:00:00", + "2006-11-25 00:00:00", + "2006-11-26 00:00:00", + "2006-12-02 00:00:00", + "2006-12-03 00:00:00", + "2006-12-09 00:00:00", + "2006-12-10 00:00:00", + "2006-12-16 00:00:00", + "2006-12-17 00:00:00", + "2006-12-23 00:00:00", + "2006-12-24 00:00:00", + "2006-12-30 00:00:00", + "2006-12-31 00:00:00", + "2007-01-06 00:00:00", + "2007-01-07 00:00:00", + "2007-01-13 00:00:00", + "2007-01-14 00:00:00", + "2007-01-20 00:00:00", + "2007-01-21 00:00:00", + "2007-01-27 00:00:00", + "2007-01-28 00:00:00", + "2007-02-03 00:00:00", + "2007-02-04 00:00:00", + "2007-02-10 00:00:00", + "2007-02-11 00:00:00", + "2007-02-17 00:00:00", + "2007-02-18 00:00:00", + "2007-02-24 00:00:00", + "2007-02-25 00:00:00", + "2007-03-03 00:00:00", + "2007-03-04 00:00:00", + "2007-03-10 00:00:00", + "2007-03-11 00:00:00", + "2007-03-17 00:00:00", + "2007-03-18 00:00:00", + "2007-03-24 00:00:00", + "2007-03-25 00:00:00", + "2007-03-31 00:00:00", + "2007-04-01 00:00:00", + "2007-04-07 00:00:00", + "2007-04-08 00:00:00", + "2007-04-14 00:00:00", + "2007-04-15 00:00:00", + "2007-04-21 00:00:00", + "2007-04-22 00:00:00", + "2007-04-28 00:00:00", + "2007-04-29 00:00:00", + "2007-05-05 00:00:00", + "2007-05-06 00:00:00", + "2007-05-12 00:00:00", + "2007-05-13 00:00:00", + "2007-05-19 00:00:00", + "2007-05-20 00:00:00", + "2007-05-26 00:00:00", + "2007-05-27 00:00:00", + "2007-06-02 00:00:00", + "2007-06-03 00:00:00", + "2007-06-09 00:00:00", + "2007-06-10 00:00:00", + "2007-06-16 00:00:00", + "2007-06-17 00:00:00", + "2007-06-23 00:00:00", + "2007-06-24 00:00:00", + "2007-06-30 00:00:00", + "2007-07-01 00:00:00", + "2007-07-07 00:00:00", + "2007-07-08 00:00:00", + "2007-07-14 00:00:00", + "2007-07-15 00:00:00", + "2007-07-21 00:00:00", + "2007-07-22 00:00:00", + "2007-07-28 00:00:00", + "2007-07-29 00:00:00", + "2007-08-04 00:00:00", + "2007-08-05 00:00:00", + "2007-08-11 00:00:00", + "2007-08-12 00:00:00", + "2007-08-18 00:00:00", + "2007-08-19 00:00:00", + "2007-08-25 00:00:00", + "2007-08-26 00:00:00", + "2007-09-01 00:00:00", + "2007-09-02 00:00:00", + "2007-09-08 00:00:00", + "2007-09-09 00:00:00", + "2007-09-15 00:00:00", + "2007-09-16 00:00:00", + "2007-09-22 00:00:00", + "2007-09-23 00:00:00", + "2007-09-29 00:00:00", + "2007-09-30 00:00:00", + "2007-10-06 00:00:00", + "2007-10-07 00:00:00", + "2007-10-13 00:00:00", + "2007-10-14 00:00:00", + "2007-10-20 00:00:00", + "2007-10-21 00:00:00", + "2007-10-27 00:00:00", + "2007-10-28 00:00:00", + "2007-11-03 00:00:00", + "2007-11-04 00:00:00", + "2007-11-10 00:00:00", + "2007-11-11 00:00:00", + "2007-11-17 00:00:00", + "2007-11-18 00:00:00", + "2007-11-24 00:00:00", + "2007-11-25 00:00:00", + "2007-12-01 00:00:00", + "2007-12-02 00:00:00", + "2007-12-08 00:00:00", + "2007-12-09 00:00:00", + "2007-12-15 00:00:00", + "2007-12-16 00:00:00", + "2007-12-22 00:00:00", + "2007-12-23 00:00:00", + "2007-12-29 00:00:00", + "2007-12-30 00:00:00", + "2008-01-05 00:00:00", + "2008-01-06 00:00:00", + "2008-01-12 00:00:00", + "2008-01-13 00:00:00", + "2008-01-19 00:00:00", + "2008-01-20 00:00:00", + "2008-01-26 00:00:00", + "2008-01-27 00:00:00", + "2008-02-02 00:00:00", + "2008-02-03 00:00:00", + "2008-02-09 00:00:00", + "2008-02-10 00:00:00", + "2008-02-16 00:00:00", + "2008-02-17 00:00:00", + "2008-02-23 00:00:00", + "2008-02-24 00:00:00", + "2008-03-01 00:00:00", + "2008-03-02 00:00:00", + "2008-03-08 00:00:00", + "2008-03-09 00:00:00", + "2008-03-15 00:00:00", + "2008-03-16 00:00:00", + "2008-03-22 00:00:00", + "2008-03-23 00:00:00", + "2008-03-29 00:00:00", + "2008-03-30 00:00:00", + "2008-04-05 00:00:00", + "2008-04-06 00:00:00", + "2008-04-12 00:00:00", + "2008-04-13 00:00:00", + "2008-04-19 00:00:00", + "2008-04-20 00:00:00", + "2008-04-26 00:00:00", + "2008-04-27 00:00:00", + "2008-05-03 00:00:00", + "2008-05-04 00:00:00", + "2008-05-10 00:00:00", + "2008-05-11 00:00:00", + "2008-05-17 00:00:00", + "2008-05-18 00:00:00", + "2008-05-24 00:00:00", + "2008-05-25 00:00:00", + "2008-05-31 00:00:00", + "2008-06-01 00:00:00", + "2008-06-07 00:00:00", + "2008-06-08 00:00:00", + "2008-06-14 00:00:00", + "2008-06-15 00:00:00", + "2008-06-21 00:00:00", + "2008-06-22 00:00:00", + "2008-06-28 00:00:00", + "2008-06-29 00:00:00", + "2008-07-05 00:00:00", + "2008-07-06 00:00:00", + "2008-07-12 00:00:00", + "2008-07-13 00:00:00", + "2008-07-19 00:00:00", + "2008-07-20 00:00:00", + "2008-07-26 00:00:00", + "2008-07-27 00:00:00", + "2008-08-02 00:00:00", + "2008-08-03 00:00:00", + "2008-08-09 00:00:00", + "2008-08-10 00:00:00", + "2008-08-16 00:00:00", + "2008-08-17 00:00:00", + "2008-08-23 00:00:00", + "2008-08-24 00:00:00", + "2008-08-30 00:00:00", + "2008-08-31 00:00:00", + "2008-09-06 00:00:00", + "2008-09-07 00:00:00", + "2008-09-13 00:00:00", + "2008-09-14 00:00:00", + "2008-09-20 00:00:00", + "2008-09-21 00:00:00", + "2008-09-27 00:00:00", + "2008-09-28 00:00:00", + "2008-10-04 00:00:00", + "2008-10-05 00:00:00", + "2008-10-11 00:00:00", + "2008-10-12 00:00:00", + "2008-10-18 00:00:00", + "2008-10-19 00:00:00", + "2008-10-25 00:00:00", + "2008-10-26 00:00:00", + "2008-11-01 00:00:00", + "2008-11-02 00:00:00", + "2008-11-08 00:00:00", + "2008-11-09 00:00:00", + "2008-11-15 00:00:00", + "2008-11-16 00:00:00", + "2008-11-22 00:00:00", + "2008-11-23 00:00:00", + "2008-11-29 00:00:00", + "2008-11-30 00:00:00", + "2008-12-06 00:00:00", + "2008-12-07 00:00:00", + "2008-12-13 00:00:00", + "2008-12-14 00:00:00", + "2008-12-20 00:00:00", + "2008-12-21 00:00:00", + "2008-12-27 00:00:00", + "2008-12-28 00:00:00", + "2009-01-03 00:00:00", + "2009-01-04 00:00:00", + "2009-01-10 00:00:00", + "2009-01-11 00:00:00", + "2009-01-17 00:00:00", + "2009-01-18 00:00:00", + "2009-01-24 00:00:00", + "2009-01-25 00:00:00", + "2009-01-31 00:00:00", + "2009-02-01 00:00:00", + "2009-02-07 00:00:00", + "2009-02-08 00:00:00", + "2009-02-14 00:00:00", + "2009-02-15 00:00:00", + "2009-02-21 00:00:00", + "2009-02-22 00:00:00", + "2009-02-28 00:00:00", + "2009-03-01 00:00:00", + "2009-03-07 00:00:00", + "2009-03-08 00:00:00", + "2009-03-14 00:00:00", + "2009-03-15 00:00:00", + "2009-03-21 00:00:00", + "2009-03-22 00:00:00", + "2009-03-28 00:00:00", + "2009-03-29 00:00:00", + "2009-04-04 00:00:00", + "2009-04-05 00:00:00", + "2009-04-11 00:00:00", + "2009-04-12 00:00:00", + "2009-04-18 00:00:00", + "2009-04-19 00:00:00", + "2009-04-25 00:00:00", + "2009-04-26 00:00:00", + "2009-05-02 00:00:00", + "2009-05-03 00:00:00", + "2009-05-09 00:00:00", + "2009-05-10 00:00:00", + "2009-05-16 00:00:00", + "2009-05-17 00:00:00", + "2009-05-23 00:00:00", + "2009-05-24 00:00:00", + "2009-05-30 00:00:00", + "2009-05-31 00:00:00", + "2009-06-06 00:00:00", + "2009-06-07 00:00:00", + "2009-06-13 00:00:00", + "2009-06-14 00:00:00", + "2009-06-20 00:00:00", + "2009-06-21 00:00:00", + "2009-06-27 00:00:00", + "2009-06-28 00:00:00", + "2009-07-04 00:00:00", + "2009-07-05 00:00:00", + "2009-07-11 00:00:00", + "2009-07-12 00:00:00", + "2009-07-18 00:00:00", + "2009-07-19 00:00:00", + "2009-07-25 00:00:00", + "2009-07-26 00:00:00", + "2009-08-01 00:00:00", + "2009-08-02 00:00:00", + "2009-08-08 00:00:00", + "2009-08-09 00:00:00", + "2009-08-15 00:00:00", + "2009-08-16 00:00:00", + "2009-08-22 00:00:00", + "2009-08-23 00:00:00", + "2009-08-29 00:00:00", + "2009-08-30 00:00:00", + "2009-09-05 00:00:00", + "2009-09-06 00:00:00", + "2009-09-12 00:00:00", + "2009-09-13 00:00:00", + "2009-09-19 00:00:00", + "2009-09-20 00:00:00", + "2009-09-26 00:00:00", + "2009-09-27 00:00:00", + "2009-10-03 00:00:00", + "2009-10-04 00:00:00", + "2009-10-10 00:00:00", + "2009-10-11 00:00:00", + "2009-10-17 00:00:00", + "2009-10-18 00:00:00", + "2009-10-24 00:00:00", + "2009-10-25 00:00:00", + "2009-10-31 00:00:00", + "2009-11-01 00:00:00", + "2009-11-07 00:00:00", + "2009-11-08 00:00:00", + "2009-11-14 00:00:00", + "2009-11-15 00:00:00", + "2009-11-21 00:00:00", + "2009-11-22 00:00:00", + "2009-11-28 00:00:00", + "2009-11-29 00:00:00", + "2009-12-05 00:00:00", + "2009-12-06 00:00:00", + "2009-12-12 00:00:00", + "2009-12-13 00:00:00", + "2009-12-19 00:00:00", + "2009-12-20 00:00:00", + "2009-12-26 00:00:00", + "2009-12-27 00:00:00", + "2010-01-02 00:00:00", + "2010-01-03 00:00:00", + "2010-01-09 00:00:00", + "2010-01-10 00:00:00", + "2010-01-16 00:00:00", + "2010-01-17 00:00:00", + "2010-01-23 00:00:00", + "2010-01-24 00:00:00", + "2010-01-30 00:00:00", + "2010-01-31 00:00:00", + "2010-02-06 00:00:00", + "2010-02-07 00:00:00", + "2010-02-13 00:00:00", + "2010-02-14 00:00:00", + "2010-02-20 00:00:00", + "2010-02-21 00:00:00", + "2010-02-27 00:00:00", + "2010-02-28 00:00:00", + "2010-03-06 00:00:00", + "2010-03-07 00:00:00", + "2010-03-13 00:00:00", + "2010-03-14 00:00:00", + "2010-03-20 00:00:00", + "2010-03-21 00:00:00", + "2010-03-27 00:00:00", + "2010-03-28 00:00:00", + "2010-04-03 00:00:00", + "2010-04-04 00:00:00", + "2010-04-10 00:00:00", + "2010-04-11 00:00:00", + "2010-04-17 00:00:00", + "2010-04-18 00:00:00", + "2010-04-24 00:00:00", + "2010-04-25 00:00:00", + "2010-05-01 00:00:00", + "2010-05-02 00:00:00", + "2010-05-08 00:00:00", + "2010-05-09 00:00:00", + "2010-05-15 00:00:00", + "2010-05-16 00:00:00", + "2010-05-22 00:00:00", + "2010-05-23 00:00:00", + "2010-05-29 00:00:00", + "2010-05-30 00:00:00", + "2010-06-05 00:00:00", + "2010-06-06 00:00:00", + "2010-06-12 00:00:00", + "2010-06-13 00:00:00", + "2010-06-19 00:00:00", + "2010-06-20 00:00:00", + "2010-06-26 00:00:00", + "2010-06-27 00:00:00", + "2010-07-03 00:00:00", + "2010-07-04 00:00:00", + "2010-07-10 00:00:00", + "2010-07-11 00:00:00", + "2010-07-17 00:00:00", + "2010-07-18 00:00:00", + "2010-07-24 00:00:00", + "2010-07-25 00:00:00", + "2010-07-31 00:00:00", + "2010-08-01 00:00:00", + "2010-08-07 00:00:00", + "2010-08-08 00:00:00", + "2010-08-14 00:00:00", + "2010-08-15 00:00:00", + "2010-08-21 00:00:00", + "2010-08-22 00:00:00", + "2010-08-28 00:00:00", + "2010-08-29 00:00:00", + "2010-09-04 00:00:00", + "2010-09-05 00:00:00", + "2010-09-11 00:00:00", + "2010-09-12 00:00:00", + "2010-09-18 00:00:00", + "2010-09-19 00:00:00", + "2010-09-25 00:00:00", + "2010-09-26 00:00:00", + "2010-10-02 00:00:00", + "2010-10-03 00:00:00", + "2010-10-09 00:00:00", + "2010-10-10 00:00:00", + "2010-10-16 00:00:00", + "2010-10-17 00:00:00", + "2010-10-23 00:00:00", + "2010-10-24 00:00:00", + "2010-10-30 00:00:00", + "2010-10-31 00:00:00", + "2010-11-06 00:00:00", + "2010-11-07 00:00:00", + "2010-11-13 00:00:00", + "2010-11-14 00:00:00", + "2010-11-20 00:00:00", + "2010-11-21 00:00:00", + "2010-11-27 00:00:00", + "2010-11-28 00:00:00", + "2010-12-04 00:00:00", + "2010-12-05 00:00:00", + "2010-12-11 00:00:00", + "2010-12-12 00:00:00", + "2010-12-18 00:00:00", + "2010-12-19 00:00:00", + "2010-12-25 00:00:00", + "2010-12-26 00:00:00", + "2011-01-01 00:00:00", + "2011-01-02 00:00:00", + "2011-01-08 00:00:00", + "2011-01-09 00:00:00", + "2011-01-15 00:00:00", + "2011-01-16 00:00:00", + "2011-01-22 00:00:00", + "2011-01-23 00:00:00", + "2011-01-29 00:00:00", + "2011-01-30 00:00:00", + "2011-02-05 00:00:00", + "2011-02-06 00:00:00", + "2011-02-12 00:00:00", + "2011-02-13 00:00:00", + "2011-02-19 00:00:00", + "2011-02-20 00:00:00", + "2011-02-26 00:00:00", + "2011-02-27 00:00:00", + "2011-03-05 00:00:00", + "2011-03-06 00:00:00", + "2011-03-12 00:00:00", + "2011-03-13 00:00:00", + "2011-03-19 00:00:00", + "2011-03-20 00:00:00", + "2011-03-26 00:00:00", + "2011-03-27 00:00:00", + "2011-04-02 00:00:00", + "2011-04-03 00:00:00", + "2011-04-09 00:00:00", + "2011-04-10 00:00:00", + "2011-04-16 00:00:00", + "2011-04-17 00:00:00", + "2011-04-23 00:00:00", + "2011-04-24 00:00:00", + "2011-04-30 00:00:00", + "2011-05-01 00:00:00", + "2011-05-07 00:00:00", + "2011-05-08 00:00:00", + "2011-05-14 00:00:00", + "2011-05-15 00:00:00", + "2011-05-21 00:00:00", + "2011-05-22 00:00:00", + "2011-05-28 00:00:00", + "2011-05-29 00:00:00", + "2011-06-04 00:00:00", + "2011-06-05 00:00:00", + "2011-06-11 00:00:00", + "2011-06-12 00:00:00", + "2011-06-18 00:00:00", + "2011-06-19 00:00:00", + "2011-06-25 00:00:00", + "2011-06-26 00:00:00", + "2011-07-02 00:00:00", + "2011-07-03 00:00:00", + "2011-07-09 00:00:00", + "2011-07-10 00:00:00", + "2011-07-16 00:00:00", + "2011-07-17 00:00:00", + "2011-07-23 00:00:00", + "2011-07-24 00:00:00", + "2011-07-30 00:00:00", + "2011-07-31 00:00:00", + "2011-08-06 00:00:00", + "2011-08-07 00:00:00", + "2011-08-13 00:00:00", + "2011-08-14 00:00:00", + "2011-08-20 00:00:00", + "2011-08-21 00:00:00", + "2011-08-27 00:00:00", + "2011-08-28 00:00:00", + "2011-09-03 00:00:00", + "2011-09-04 00:00:00", + "2011-09-10 00:00:00", + "2011-09-11 00:00:00", + "2011-09-17 00:00:00", + "2011-09-18 00:00:00", + "2011-09-24 00:00:00", + "2011-09-25 00:00:00", + "2011-10-01 00:00:00", + "2011-10-02 00:00:00", + "2011-10-08 00:00:00", + "2011-10-09 00:00:00", + "2011-10-15 00:00:00", + "2011-10-16 00:00:00", + "2011-10-22 00:00:00", + "2011-10-23 00:00:00", + "2011-10-29 00:00:00", + "2011-10-30 00:00:00", + "2011-11-05 00:00:00", + "2011-11-06 00:00:00", + "2011-11-12 00:00:00", + "2011-11-13 00:00:00", + "2011-11-19 00:00:00", + "2011-11-20 00:00:00", + "2011-11-26 00:00:00", + "2011-11-27 00:00:00", + "2011-12-03 00:00:00", + "2011-12-04 00:00:00", + "2011-12-10 00:00:00", + "2011-12-11 00:00:00", + "2011-12-17 00:00:00", + "2011-12-18 00:00:00", + "2011-12-24 00:00:00", + "2011-12-25 00:00:00", + "2011-12-31 00:00:00", + "2012-01-01 00:00:00", + "2012-01-07 00:00:00", + "2012-01-08 00:00:00", + "2012-01-14 00:00:00", + "2012-01-15 00:00:00", + "2012-01-21 00:00:00", + "2012-01-22 00:00:00", + "2012-01-28 00:00:00", + "2012-01-29 00:00:00", + "2012-02-04 00:00:00", + "2012-02-05 00:00:00", + "2012-02-11 00:00:00", + "2012-02-12 00:00:00", + "2012-02-18 00:00:00", + "2012-02-19 00:00:00", + "2012-02-25 00:00:00", + "2012-02-26 00:00:00", + "2012-03-03 00:00:00", + "2012-03-04 00:00:00", + "2012-03-10 00:00:00", + "2012-03-11 00:00:00", + "2012-03-17 00:00:00", + "2012-03-18 00:00:00", + "2012-03-24 00:00:00", + "2012-03-25 00:00:00", + "2012-03-31 00:00:00", + "2012-04-01 00:00:00", + "2012-04-07 00:00:00", + "2012-04-08 00:00:00", + "2012-04-14 00:00:00", + "2012-04-15 00:00:00", + "2012-04-21 00:00:00", + "2012-04-22 00:00:00", + "2012-04-28 00:00:00", + "2012-04-29 00:00:00", + "2012-05-05 00:00:00", + "2012-05-06 00:00:00", + "2012-05-12 00:00:00", + "2012-05-13 00:00:00", + "2012-05-19 00:00:00", + "2012-05-20 00:00:00", + "2012-05-26 00:00:00", + "2012-05-27 00:00:00", + "2012-06-02 00:00:00", + "2012-06-03 00:00:00", + "2012-06-09 00:00:00", + "2012-06-10 00:00:00", + "2012-06-16 00:00:00", + "2012-06-17 00:00:00", + "2012-06-23 00:00:00", + "2012-06-24 00:00:00", + "2012-06-30 00:00:00", + "2012-07-01 00:00:00", + "2012-07-07 00:00:00", + "2012-07-08 00:00:00", + "2012-07-14 00:00:00", + "2012-07-15 00:00:00", + "2012-07-21 00:00:00", + "2012-07-22 00:00:00", + "2012-07-28 00:00:00", + "2012-07-29 00:00:00", + "2012-08-04 00:00:00", + "2012-08-05 00:00:00", + "2012-08-11 00:00:00", + "2012-08-12 00:00:00", + "2012-08-18 00:00:00", + "2012-08-19 00:00:00", + "2012-08-25 00:00:00", + "2012-08-26 00:00:00", + "2012-09-01 00:00:00", + "2012-09-02 00:00:00", + "2012-09-08 00:00:00", + "2012-09-09 00:00:00", + "2012-09-15 00:00:00", + "2012-09-16 00:00:00", + "2012-09-22 00:00:00", + "2012-09-23 00:00:00", + "2012-09-29 00:00:00", + "2012-09-30 00:00:00", + "2012-10-06 00:00:00", + "2012-10-07 00:00:00", + "2012-10-13 00:00:00", + "2012-10-14 00:00:00", + "2012-10-20 00:00:00", + "2012-10-21 00:00:00", + "2012-10-27 00:00:00", + "2012-10-28 00:00:00", + "2012-11-03 00:00:00", + "2012-11-04 00:00:00", + "2012-11-10 00:00:00", + "2012-11-11 00:00:00", + "2012-11-17 00:00:00", + "2012-11-18 00:00:00", + "2012-11-24 00:00:00", + "2012-11-25 00:00:00", + "2012-12-01 00:00:00", + "2012-12-02 00:00:00", + "2012-12-08 00:00:00", + "2012-12-09 00:00:00", + "2012-12-15 00:00:00", + "2012-12-16 00:00:00", + "2012-12-22 00:00:00", + "2012-12-23 00:00:00", + "2012-12-29 00:00:00", + "2012-12-30 00:00:00", + "2013-01-05 00:00:00", + "2013-01-06 00:00:00", + "2013-01-12 00:00:00", + "2013-01-13 00:00:00", + "2013-01-19 00:00:00", + "2013-01-20 00:00:00", + "2013-01-26 00:00:00", + "2013-01-27 00:00:00", + "2013-02-02 00:00:00", + "2013-02-03 00:00:00", + "2013-02-09 00:00:00", + "2013-02-10 00:00:00", + "2013-02-16 00:00:00", + "2013-02-17 00:00:00", + "2013-02-23 00:00:00", + "2013-02-24 00:00:00", + "2013-03-02 00:00:00", + "2013-03-03 00:00:00", + "2013-03-09 00:00:00", + "2013-03-10 00:00:00", + "2013-03-16 00:00:00", + "2013-03-17 00:00:00", + "2013-03-23 00:00:00", + "2013-03-24 00:00:00", + "2013-03-30 00:00:00", + "2013-03-31 00:00:00", + "2013-04-06 00:00:00", + "2013-04-07 00:00:00", + "2013-04-13 00:00:00", + "2013-04-14 00:00:00", + "2013-04-20 00:00:00", + "2013-04-21 00:00:00", + "2013-04-27 00:00:00", + "2013-04-28 00:00:00", + "2013-05-04 00:00:00", + "2013-05-05 00:00:00", + "2013-05-11 00:00:00", + "2013-05-12 00:00:00", + "2013-05-18 00:00:00", + "2013-05-19 00:00:00", + "2013-05-25 00:00:00", + "2013-05-26 00:00:00", + "2013-06-01 00:00:00", + "2013-06-02 00:00:00", + "2013-06-08 00:00:00", + "2013-06-09 00:00:00", + "2013-06-15 00:00:00", + "2013-06-16 00:00:00", + "2013-06-22 00:00:00", + "2013-06-23 00:00:00", + "2013-06-29 00:00:00", + "2013-06-30 00:00:00", + "2013-07-06 00:00:00", + "2013-07-07 00:00:00", + "2013-07-13 00:00:00", + "2013-07-14 00:00:00", + "2013-07-20 00:00:00", + "2013-07-21 00:00:00", + "2013-07-27 00:00:00", + "2013-07-28 00:00:00", + "2013-08-03 00:00:00", + "2013-08-04 00:00:00", + "2013-08-10 00:00:00", + "2013-08-11 00:00:00", + "2013-08-17 00:00:00", + "2013-08-18 00:00:00", + "2013-08-24 00:00:00", + "2013-08-25 00:00:00", + "2013-08-31 00:00:00", + "2013-09-01 00:00:00", + "2013-09-07 00:00:00", + "2013-09-08 00:00:00", + "2013-09-14 00:00:00", + "2013-09-15 00:00:00", + "2013-09-21 00:00:00", + "2013-09-22 00:00:00", + "2013-09-28 00:00:00", + "2013-09-29 00:00:00", + "2013-10-05 00:00:00", + "2013-10-06 00:00:00", + "2013-10-12 00:00:00", + "2013-10-13 00:00:00", + "2013-10-19 00:00:00", + "2013-10-20 00:00:00", + "2013-10-26 00:00:00", + "2013-10-27 00:00:00", + "2013-11-02 00:00:00", + "2013-11-03 00:00:00", + "2013-11-09 00:00:00", + "2013-11-10 00:00:00", + "2013-11-16 00:00:00", + "2013-11-17 00:00:00", + "2013-11-23 00:00:00", + "2013-11-24 00:00:00", + "2013-11-30 00:00:00", + "2013-12-01 00:00:00", + "2013-12-07 00:00:00", + "2013-12-08 00:00:00", + "2013-12-14 00:00:00", + "2013-12-15 00:00:00", + "2013-12-21 00:00:00", + "2013-12-22 00:00:00", + "2013-12-28 00:00:00", + "2013-12-29 00:00:00", + "2014-01-04 00:00:00", + "2014-01-05 00:00:00", + "2014-01-11 00:00:00", + "2014-01-12 00:00:00", + "2014-01-18 00:00:00", + "2014-01-19 00:00:00", + "2014-01-25 00:00:00", + "2014-01-26 00:00:00", + "2014-02-01 00:00:00", + "2014-02-02 00:00:00", + "2014-02-08 00:00:00", + "2014-02-09 00:00:00", + "2014-02-15 00:00:00", + "2014-02-16 00:00:00", + "2014-02-22 00:00:00", + "2014-02-23 00:00:00", + "2014-03-01 00:00:00", + "2014-03-02 00:00:00", + "2014-03-08 00:00:00", + "2014-03-09 00:00:00", + "2014-03-15 00:00:00", + "2014-03-16 00:00:00", + "2014-03-22 00:00:00", + "2014-03-23 00:00:00", + "2014-03-29 00:00:00", + "2014-03-30 00:00:00", + "2014-04-05 00:00:00", + "2014-04-06 00:00:00", + "2014-04-12 00:00:00", + "2014-04-13 00:00:00", + "2014-04-19 00:00:00", + "2014-04-20 00:00:00", + "2014-04-26 00:00:00", + "2014-04-27 00:00:00", + "2014-05-03 00:00:00", + "2014-05-04 00:00:00", + "2014-05-10 00:00:00", + "2014-05-11 00:00:00", + "2014-05-17 00:00:00", + "2014-05-18 00:00:00", + "2014-05-24 00:00:00", + "2014-05-25 00:00:00", + "2014-05-31 00:00:00", + "2014-06-01 00:00:00", + "2014-06-07 00:00:00", + "2014-06-08 00:00:00", + "2014-06-14 00:00:00", + "2014-06-15 00:00:00", + "2014-06-21 00:00:00", + "2014-06-22 00:00:00", + "2014-06-28 00:00:00", + "2014-06-29 00:00:00", + "2014-07-05 00:00:00", + "2014-07-06 00:00:00", + "2014-07-12 00:00:00", + "2014-07-13 00:00:00", + "2014-07-19 00:00:00", + "2014-07-20 00:00:00", + "2014-07-26 00:00:00", + "2014-07-27 00:00:00", + "2014-08-02 00:00:00", + "2014-08-03 00:00:00", + "2014-08-09 00:00:00", + "2014-08-10 00:00:00", + "2014-08-16 00:00:00", + "2014-08-17 00:00:00", + "2014-08-23 00:00:00", + "2014-08-24 00:00:00", + "2014-08-30 00:00:00", + "2014-08-31 00:00:00", + "2014-09-06 00:00:00", + "2014-09-07 00:00:00", + "2014-09-13 00:00:00", + "2014-09-14 00:00:00", + "2014-09-20 00:00:00", + "2014-09-21 00:00:00", + "2014-09-27 00:00:00", + "2014-09-28 00:00:00", + "2014-10-04 00:00:00", + "2014-10-05 00:00:00", + "2014-10-11 00:00:00", + "2014-10-12 00:00:00", + "2014-10-18 00:00:00", + "2014-10-19 00:00:00", + "2014-10-25 00:00:00", + "2014-10-26 00:00:00", + "2014-11-01 00:00:00", + "2014-11-02 00:00:00", + "2014-11-08 00:00:00", + "2014-11-09 00:00:00", + "2014-11-15 00:00:00", + "2014-11-16 00:00:00", + "2014-11-22 00:00:00", + "2014-11-23 00:00:00", + "2014-11-29 00:00:00", + "2014-11-30 00:00:00", + "2014-12-06 00:00:00", + "2014-12-07 00:00:00", + "2014-12-13 00:00:00", + "2014-12-14 00:00:00", + "2014-12-20 00:00:00", + "2014-12-21 00:00:00", + "2014-12-27 00:00:00", + "2014-12-28 00:00:00", + "2015-01-03 00:00:00", + "2015-01-04 00:00:00", + "2015-01-10 00:00:00", + "2015-01-11 00:00:00", + "2015-01-17 00:00:00", + "2015-01-18 00:00:00", + "2015-01-24 00:00:00", + "2015-01-25 00:00:00", + "2015-01-31 00:00:00", + "2015-02-01 00:00:00", + "2015-02-07 00:00:00", + "2015-02-08 00:00:00", + "2015-02-14 00:00:00", + "2015-02-15 00:00:00", + "2015-02-21 00:00:00", + "2015-02-22 00:00:00", + "2015-02-28 00:00:00", + "2015-03-01 00:00:00", + "2015-03-07 00:00:00", + "2015-03-08 00:00:00", + "2015-03-14 00:00:00", + "2015-03-15 00:00:00", + "2015-03-21 00:00:00", + "2015-03-22 00:00:00", + "2015-03-28 00:00:00", + "2015-03-29 00:00:00", + "2015-04-04 00:00:00", + "2015-04-05 00:00:00", + "2015-04-11 00:00:00", + "2015-04-12 00:00:00", + "2015-04-18 00:00:00", + "2015-04-19 00:00:00", + "2015-04-25 00:00:00", + "2015-04-26 00:00:00", + "2015-05-02 00:00:00", + "2015-05-03 00:00:00", + "2015-05-09 00:00:00", + "2015-05-10 00:00:00", + "2015-05-16 00:00:00", + "2015-05-17 00:00:00", + "2015-05-23 00:00:00", + "2015-05-24 00:00:00", + "2015-05-30 00:00:00", + "2015-05-31 00:00:00", + "2015-06-06 00:00:00", + "2015-06-07 00:00:00", + "2015-06-13 00:00:00", + "2015-06-14 00:00:00", + "2015-06-20 00:00:00", + "2015-06-21 00:00:00", + "2015-06-27 00:00:00", + "2015-06-28 00:00:00", + "2015-07-04 00:00:00", + "2015-07-05 00:00:00", + "2015-07-11 00:00:00", + "2015-07-12 00:00:00", + "2015-07-18 00:00:00", + "2015-07-19 00:00:00", + "2015-07-25 00:00:00", + "2015-07-26 00:00:00", + "2015-08-01 00:00:00", + "2015-08-02 00:00:00", + "2015-08-08 00:00:00", + "2015-08-09 00:00:00", + "2015-08-15 00:00:00", + "2015-08-16 00:00:00", + "2015-08-22 00:00:00", + "2015-08-23 00:00:00", + "2015-08-29 00:00:00", + "2015-08-30 00:00:00", + "2015-09-05 00:00:00", + "2015-09-06 00:00:00", + "2015-09-12 00:00:00", + "2015-09-13 00:00:00", + "2015-09-19 00:00:00", + "2015-09-20 00:00:00", + "2015-09-26 00:00:00", + "2015-09-27 00:00:00", + "2015-10-03 00:00:00", + "2015-10-04 00:00:00", + "2015-10-10 00:00:00", + "2015-10-11 00:00:00", + "2015-10-17 00:00:00", + "2015-10-18 00:00:00", + "2015-10-24 00:00:00", + "2015-10-25 00:00:00", + "2015-10-31 00:00:00", + "2015-11-01 00:00:00", + "2015-11-07 00:00:00", + "2015-11-08 00:00:00", + "2015-11-14 00:00:00", + "2015-11-15 00:00:00", + "2015-11-21 00:00:00", + "2015-11-22 00:00:00", + "2015-11-28 00:00:00", + "2015-11-29 00:00:00", + "2015-12-05 00:00:00", + "2015-12-06 00:00:00", + "2015-12-12 00:00:00", + "2015-12-13 00:00:00", + "2015-12-19 00:00:00", + "2015-12-20 00:00:00", + "2015-12-26 00:00:00", + "2015-12-27 00:00:00", + "2016-01-02 00:00:00", + "2016-01-03 00:00:00", + "2016-01-09 00:00:00", + "2016-01-10 00:00:00", + "2016-01-16 00:00:00", + "2016-01-17 00:00:00", + "2016-01-23 00:00:00", + "2016-01-24 00:00:00", + "2016-01-30 00:00:00", + "2016-01-31 00:00:00", + "2016-02-06 00:00:00", + "2016-02-07 00:00:00", + "2016-02-13 00:00:00", + "2016-02-14 00:00:00", + "2016-02-20 00:00:00", + "2016-02-21 00:00:00", + "2016-02-27 00:00:00", + "2016-02-28 00:00:00", + "2016-03-05 00:00:00", + "2016-03-06 00:00:00", + "2016-03-12 00:00:00", + "2016-03-13 00:00:00", + "2016-03-19 00:00:00", + "2016-03-20 00:00:00", + "2016-03-26 00:00:00", + "2016-03-27 00:00:00", + "2016-04-02 00:00:00", + "2016-04-03 00:00:00", + "2016-04-09 00:00:00", + "2016-04-10 00:00:00", + "2016-04-16 00:00:00", + "2016-04-17 00:00:00", + "2016-04-23 00:00:00", + "2016-04-24 00:00:00", + "2016-04-30 00:00:00", + "2016-05-01 00:00:00", + "2016-05-07 00:00:00", + "2016-05-08 00:00:00", + "2016-05-14 00:00:00", + "2016-05-15 00:00:00", + "2016-05-21 00:00:00", + "2016-05-22 00:00:00", + "2016-05-28 00:00:00", + "2016-05-29 00:00:00", + "2016-06-04 00:00:00", + "2016-06-05 00:00:00", + "2016-06-11 00:00:00", + "2016-06-12 00:00:00", + "2016-06-18 00:00:00", + "2016-06-19 00:00:00", + "2016-06-25 00:00:00", + "2016-06-26 00:00:00", + "2016-07-02 00:00:00", + "2016-07-03 00:00:00", + "2016-07-09 00:00:00", + "2016-07-10 00:00:00", + "2016-07-16 00:00:00", + "2016-07-17 00:00:00", + "2016-07-23 00:00:00", + "2016-07-24 00:00:00", + "2016-07-30 00:00:00", + "2016-07-31 00:00:00", + "2016-08-06 00:00:00", + "2016-08-07 00:00:00", + "2016-08-13 00:00:00", + "2016-08-14 00:00:00", + "2016-08-20 00:00:00", + "2016-08-21 00:00:00", + "2016-08-27 00:00:00", + "2016-08-28 00:00:00", + "2016-09-03 00:00:00", + "2016-09-04 00:00:00", + "2016-09-10 00:00:00", + "2016-09-11 00:00:00", + "2016-09-17 00:00:00", + "2016-09-18 00:00:00", + "2016-09-24 00:00:00", + "2016-09-25 00:00:00", + "2016-10-01 00:00:00", + "2016-10-02 00:00:00", + "2016-10-08 00:00:00", + "2016-10-09 00:00:00", + "2016-10-15 00:00:00", + "2016-10-16 00:00:00", + "2016-10-22 00:00:00", + "2016-10-23 00:00:00", + "2016-10-29 00:00:00", + "2016-10-30 00:00:00", + "2016-11-05 00:00:00", + "2016-11-06 00:00:00", + "2016-11-12 00:00:00", + "2016-11-13 00:00:00", + "2016-11-19 00:00:00", + "2016-11-20 00:00:00", + "2016-11-26 00:00:00", + "2016-11-27 00:00:00", + "2016-12-03 00:00:00", + "2016-12-04 00:00:00", + "2016-12-10 00:00:00", + "2016-12-11 00:00:00", + "2016-12-17 00:00:00", + "2016-12-18 00:00:00", + "2016-12-24 00:00:00", + "2016-12-25 00:00:00", + "2016-12-31 00:00:00", + "2017-01-01 00:00:00", + "2017-01-07 00:00:00", + "2017-01-08 00:00:00", + "2017-01-14 00:00:00", + "2017-01-15 00:00:00", + "2017-01-21 00:00:00", + "2017-01-22 00:00:00", + "2017-01-28 00:00:00", + "2017-01-29 00:00:00", + "2017-02-04 00:00:00", + "2017-02-05 00:00:00", + "2017-02-11 00:00:00", + "2017-02-12 00:00:00", + "2017-02-18 00:00:00", + "2017-02-19 00:00:00", + "2017-02-25 00:00:00", + "2017-02-26 00:00:00", + "2017-03-04 00:00:00", + "2017-03-05 00:00:00", + "2017-03-11 00:00:00", + "2017-03-12 00:00:00", + "2017-03-18 00:00:00", + "2017-03-19 00:00:00", + "2017-03-25 00:00:00", + "2017-03-26 00:00:00", + "2017-04-01 00:00:00", + "2017-04-02 00:00:00", + "2017-04-08 00:00:00", + "2017-04-09 00:00:00", + "2017-04-15 00:00:00", + "2017-04-16 00:00:00", + "2017-04-22 00:00:00", + "2017-04-23 00:00:00", + "2017-04-29 00:00:00", + "2017-04-30 00:00:00", + "2017-05-06 00:00:00", + "2017-05-07 00:00:00", + "2017-05-13 00:00:00", + "2017-05-14 00:00:00", + "2017-05-20 00:00:00", + "2017-05-21 00:00:00", + "2017-05-27 00:00:00", + "2017-05-28 00:00:00", + "2017-06-03 00:00:00", + "2017-06-04 00:00:00", + "2017-06-10 00:00:00", + "2017-06-11 00:00:00", + "2017-06-17 00:00:00", + "2017-06-18 00:00:00", + "2017-06-24 00:00:00", + "2017-06-25 00:00:00", + "2017-07-01 00:00:00", + "2017-07-02 00:00:00", + "2017-07-08 00:00:00", + "2017-07-09 00:00:00", + "2017-07-15 00:00:00", + "2017-07-16 00:00:00", + "2017-07-22 00:00:00", + "2017-07-23 00:00:00", + "2017-07-29 00:00:00", + "2017-07-30 00:00:00", + "2017-08-05 00:00:00", + "2017-08-06 00:00:00", + "2017-08-12 00:00:00", + "2017-08-13 00:00:00", + "2017-08-19 00:00:00", + "2017-08-20 00:00:00", + "2017-08-26 00:00:00", + "2017-08-27 00:00:00", + "2017-09-02 00:00:00", + "2017-09-03 00:00:00", + "2017-09-09 00:00:00", + "2017-09-10 00:00:00", + "2017-09-16 00:00:00", + "2017-09-17 00:00:00", + "2017-09-23 00:00:00", + "2017-09-24 00:00:00", + "2017-09-30 00:00:00", + "2017-10-01 00:00:00", + "2017-10-07 00:00:00", + "2017-10-08 00:00:00", + "2017-10-14 00:00:00", + "2017-10-15 00:00:00", + "2017-10-21 00:00:00", + "2017-10-22 00:00:00", + "2017-10-28 00:00:00", + "2017-10-29 00:00:00", + "2017-11-04 00:00:00", + "2017-11-05 00:00:00", + "2017-11-11 00:00:00", + "2017-11-12 00:00:00", + "2017-11-18 00:00:00", + "2017-11-19 00:00:00", + "2017-11-25 00:00:00", + "2017-11-26 00:00:00", + "2017-12-02 00:00:00", + "2017-12-03 00:00:00", + "2017-12-09 00:00:00", + "2017-12-10 00:00:00", + "2017-12-16 00:00:00", + "2017-12-17 00:00:00", + "2017-12-23 00:00:00", + "2017-12-24 00:00:00", + "2017-12-30 00:00:00", + "2017-12-31 00:00:00", + "2018-01-06 00:00:00", + "2018-01-07 00:00:00", + "2018-01-13 00:00:00", + "2018-01-14 00:00:00", + "2018-01-20 00:00:00", + "2018-01-21 00:00:00", + "2018-01-27 00:00:00", + "2018-01-28 00:00:00", + "2018-02-03 00:00:00", + "2018-02-04 00:00:00", + "2018-02-10 00:00:00", + "2018-02-11 00:00:00", + "2018-02-17 00:00:00", + "2018-02-18 00:00:00", + "2018-02-24 00:00:00", + "2018-02-25 00:00:00", + "2018-03-03 00:00:00", + "2018-03-04 00:00:00", + "2018-03-10 00:00:00", + "2018-03-11 00:00:00", + "2018-03-17 00:00:00", + "2018-03-18 00:00:00", + "2018-03-24 00:00:00", + "2018-03-25 00:00:00", + "2018-03-31 00:00:00", + "2018-04-01 00:00:00", + "2018-04-07 00:00:00", + "2018-04-08 00:00:00", + "2018-04-14 00:00:00", + "2018-04-15 00:00:00", + "2018-04-21 00:00:00", + "2018-04-22 00:00:00", + "2018-04-28 00:00:00", + "2018-04-29 00:00:00", + "2018-05-05 00:00:00", + "2018-05-06 00:00:00", + "2018-05-12 00:00:00", + "2018-05-13 00:00:00", + "2018-05-19 00:00:00", + "2018-05-20 00:00:00", + "2018-05-26 00:00:00", + "2018-05-27 00:00:00", + "2018-06-02 00:00:00", + "2018-06-03 00:00:00", + "2018-06-09 00:00:00", + "2018-06-10 00:00:00", + "2018-06-16 00:00:00", + "2018-06-17 00:00:00", + "2018-06-23 00:00:00", + "2018-06-24 00:00:00", + "2018-06-30 00:00:00", + "2018-07-01 00:00:00", + "2018-07-07 00:00:00", + "2018-07-08 00:00:00", + "2018-07-14 00:00:00", + "2018-07-15 00:00:00", + "2018-07-21 00:00:00", + "2018-07-22 00:00:00", + "2018-07-28 00:00:00", + "2018-07-29 00:00:00", + "2018-08-04 00:00:00", + "2018-08-05 00:00:00", + "2018-08-11 00:00:00", + "2018-08-12 00:00:00", + "2018-08-18 00:00:00", + "2018-08-19 00:00:00", + "2018-08-25 00:00:00", + "2018-08-26 00:00:00", + "2018-09-01 00:00:00", + "2018-09-02 00:00:00", + "2018-09-08 00:00:00", + "2018-09-09 00:00:00", + "2018-09-15 00:00:00", + "2018-09-16 00:00:00", + "2018-09-22 00:00:00", + "2018-09-23 00:00:00", + "2018-09-29 00:00:00", + "2018-09-30 00:00:00", + "2018-10-06 00:00:00", + "2018-10-07 00:00:00", + "2018-10-13 00:00:00", + "2018-10-14 00:00:00", + "2018-10-20 00:00:00", + "2018-10-21 00:00:00", + "2018-10-27 00:00:00", + "2018-10-28 00:00:00", + "2018-11-03 00:00:00", + "2018-11-04 00:00:00", + "2018-11-10 00:00:00", + "2018-11-11 00:00:00", + "2018-11-17 00:00:00", + "2018-11-18 00:00:00", + "2018-11-24 00:00:00", + "2018-11-25 00:00:00", + "2018-12-01 00:00:00", + "2018-12-02 00:00:00", + "2018-12-08 00:00:00", + "2018-12-09 00:00:00", + "2018-12-15 00:00:00", + "2018-12-16 00:00:00", + "2018-12-22 00:00:00", + "2018-12-23 00:00:00", + "2018-12-29 00:00:00", + "2018-12-30 00:00:00", + "2019-01-05 00:00:00", + "2019-01-06 00:00:00", + "2019-01-12 00:00:00", + "2019-01-13 00:00:00", + "2019-01-19 00:00:00", + "2019-01-20 00:00:00", + "2019-01-26 00:00:00", + "2019-01-27 00:00:00", + "2019-02-02 00:00:00", + "2019-02-03 00:00:00", + "2019-02-09 00:00:00", + "2019-02-10 00:00:00", + "2019-02-16 00:00:00", + "2019-02-17 00:00:00", + "2019-02-23 00:00:00", + "2019-02-24 00:00:00", + "2019-03-02 00:00:00", + "2019-03-03 00:00:00", + "2019-03-09 00:00:00", + "2019-03-10 00:00:00", + "2019-03-16 00:00:00", + "2019-03-17 00:00:00", + "2019-03-23 00:00:00", + "2019-03-24 00:00:00", + "2019-03-30 00:00:00", + "2019-03-31 00:00:00", + "2019-04-06 00:00:00", + "2019-04-07 00:00:00", + "2019-04-13 00:00:00", + "2019-04-14 00:00:00", + "2019-04-20 00:00:00", + "2019-04-21 00:00:00", + "2019-04-27 00:00:00", + "2019-04-28 00:00:00", + "2019-05-04 00:00:00", + "2019-05-05 00:00:00", + "2019-05-11 00:00:00", + "2019-05-12 00:00:00", + "2019-05-18 00:00:00", + "2019-05-19 00:00:00", + "2019-05-25 00:00:00", + "2019-05-26 00:00:00", + "2019-06-01 00:00:00", + "2019-06-02 00:00:00", + "2019-06-08 00:00:00", + "2019-06-09 00:00:00", + "2019-06-15 00:00:00", + "2019-06-16 00:00:00", + "2019-06-22 00:00:00", + "2019-06-23 00:00:00", + "2019-06-29 00:00:00", + "2019-06-30 00:00:00", + "2019-07-06 00:00:00", + "2019-07-07 00:00:00", + "2019-07-13 00:00:00", + "2019-07-14 00:00:00", + "2019-07-20 00:00:00", + "2019-07-21 00:00:00", + "2019-07-27 00:00:00", + "2019-07-28 00:00:00", + "2019-08-03 00:00:00", + "2019-08-04 00:00:00", + "2019-08-10 00:00:00", + "2019-08-11 00:00:00", + "2019-08-17 00:00:00", + "2019-08-18 00:00:00", + "2019-08-24 00:00:00", + "2019-08-25 00:00:00", + "2019-08-31 00:00:00", + "2019-09-01 00:00:00", + "2019-09-07 00:00:00", + "2019-09-08 00:00:00", + "2019-09-14 00:00:00", + "2019-09-15 00:00:00", + "2019-09-21 00:00:00", + "2019-09-22 00:00:00", + "2019-09-28 00:00:00", + "2019-09-29 00:00:00", + "2019-10-05 00:00:00", + "2019-10-06 00:00:00", + "2019-10-12 00:00:00", + "2019-10-13 00:00:00", + "2019-10-19 00:00:00", + "2019-10-20 00:00:00", + "2019-10-26 00:00:00", + "2019-10-27 00:00:00", + "2019-11-02 00:00:00", + "2019-11-03 00:00:00", + "2019-11-09 00:00:00", + "2019-11-10 00:00:00", + "2019-11-16 00:00:00", + "2019-11-17 00:00:00", + "2019-11-23 00:00:00", + "2019-11-24 00:00:00", + "2019-11-30 00:00:00", + "2019-12-01 00:00:00", + "2019-12-07 00:00:00", + "2019-12-08 00:00:00", + "2019-12-14 00:00:00", + "2019-12-15 00:00:00", + "2019-12-21 00:00:00", + "2019-12-22 00:00:00", + "2019-12-28 00:00:00", + "2019-12-29 00:00:00", + "2020-01-04 00:00:00", + "2020-01-05 00:00:00", + "2020-01-11 00:00:00", + "2020-01-12 00:00:00", + "2020-01-18 00:00:00", + "2020-01-19 00:00:00", + "2020-01-25 00:00:00", + "2020-01-26 00:00:00", + "2020-02-01 00:00:00", + "2020-02-02 00:00:00", + "2020-02-08 00:00:00", + "2020-02-09 00:00:00", + "2020-02-15 00:00:00", + "2020-02-16 00:00:00", + "2020-02-22 00:00:00", + "2020-02-23 00:00:00", + "2020-02-29 00:00:00", + "2020-03-01 00:00:00", + "2020-03-07 00:00:00", + "2020-03-08 00:00:00", + "2020-03-14 00:00:00", + "2020-03-15 00:00:00", + "2020-03-21 00:00:00", + "2020-03-22 00:00:00", + "2020-03-28 00:00:00", + "2020-03-29 00:00:00", + "2020-04-04 00:00:00", + "2020-04-05 00:00:00", + "2020-04-11 00:00:00", + "2020-04-12 00:00:00", + "2020-04-18 00:00:00", + "2020-04-19 00:00:00", + "2020-04-25 00:00:00", + "2020-04-26 00:00:00", + "2020-05-02 00:00:00", + "2020-05-03 00:00:00", + "2020-05-09 00:00:00", + "2020-05-10 00:00:00", + "2020-05-16 00:00:00", + "2020-05-17 00:00:00", + "2020-05-23 00:00:00", + "2020-05-24 00:00:00", + "2020-05-30 00:00:00", + "2020-05-31 00:00:00", + "2020-06-06 00:00:00", + "2020-06-07 00:00:00", + "2020-06-13 00:00:00", + "2020-06-14 00:00:00", + "2020-06-20 00:00:00", + "2020-06-21 00:00:00", + "2020-06-27 00:00:00", + "2020-06-28 00:00:00", + "2020-07-04 00:00:00", + "2020-07-05 00:00:00", + "2020-07-11 00:00:00", + "2020-07-12 00:00:00", + "2020-07-18 00:00:00", + "2020-07-19 00:00:00", + "2020-07-25 00:00:00", + "2020-07-26 00:00:00", + "2020-08-01 00:00:00", + "2020-08-02 00:00:00", + "2020-08-08 00:00:00", + "2020-08-09 00:00:00", + "2020-08-15 00:00:00", + "2020-08-16 00:00:00", + "2020-08-22 00:00:00", + "2020-08-23 00:00:00", + "2020-08-29 00:00:00", + "2020-08-30 00:00:00", + "2020-09-05 00:00:00", + "2020-09-06 00:00:00", + "2020-09-12 00:00:00", + "2020-09-13 00:00:00", + "2020-09-19 00:00:00", + "2020-09-20 00:00:00", + "2020-09-26 00:00:00", + "2020-09-27 00:00:00", + "2020-10-03 00:00:00", + "2020-10-04 00:00:00", + "2020-10-10 00:00:00", + "2020-10-11 00:00:00", + "2020-10-17 00:00:00", + "2020-10-18 00:00:00", + "2020-10-24 00:00:00", + "2020-10-25 00:00:00", + "2020-10-31 00:00:00", + "2020-11-01 00:00:00", + "2020-11-07 00:00:00", + "2020-11-08 00:00:00", + "2020-11-14 00:00:00", + "2020-11-15 00:00:00", + "2020-11-21 00:00:00", + "2020-11-22 00:00:00", + "2020-11-28 00:00:00", + "2020-11-29 00:00:00", + "2020-12-05 00:00:00", + "2020-12-06 00:00:00", + "2020-12-12 00:00:00", + "2020-12-13 00:00:00", + "2020-12-19 00:00:00", + "2020-12-20 00:00:00", + "2020-12-26 00:00:00", + "2020-12-27 00:00:00", + "2021-01-02 00:00:00", + "2021-01-03 00:00:00", + "2021-01-09 00:00:00", + "2021-01-10 00:00:00", + "2021-01-16 00:00:00", + "2021-01-17 00:00:00", + "2021-01-23 00:00:00", + "2021-01-24 00:00:00", + "2021-01-30 00:00:00", + "2021-01-31 00:00:00", + "2021-02-06 00:00:00", + "2021-02-07 00:00:00", + "2021-02-13 00:00:00", + "2021-02-14 00:00:00", + "2021-02-20 00:00:00", + "2021-02-21 00:00:00", + "2021-02-27 00:00:00", + "2021-02-28 00:00:00", + "2021-03-06 00:00:00", + "2021-03-07 00:00:00", + "2021-03-13 00:00:00", + "2021-03-14 00:00:00", + "2021-03-20 00:00:00", + "2021-03-21 00:00:00", + "2021-03-27 00:00:00", + "2021-03-28 00:00:00", + "2021-04-03 00:00:00", + "2021-04-04 00:00:00", + "2021-04-10 00:00:00", + "2021-04-11 00:00:00", + "2021-04-17 00:00:00", + "2021-04-18 00:00:00", + "2021-04-24 00:00:00", + "2021-04-25 00:00:00", + "2021-05-01 00:00:00", + "2021-05-02 00:00:00", + "2021-05-08 00:00:00", + "2021-05-09 00:00:00", + "2021-05-15 00:00:00", + "2021-05-16 00:00:00", + "2021-05-22 00:00:00", + "2021-05-23 00:00:00", + "2021-05-29 00:00:00", + "2021-05-30 00:00:00", + "2021-06-05 00:00:00", + "2021-06-06 00:00:00", + "2021-06-12 00:00:00", + "2021-06-13 00:00:00", + "2021-06-19 00:00:00", + "2021-06-20 00:00:00", + "2021-06-26 00:00:00", + "2021-06-27 00:00:00", + "2021-07-03 00:00:00", + "2021-07-04 00:00:00", + "2021-07-10 00:00:00", + "2021-07-11 00:00:00", + "2021-07-17 00:00:00", + "2021-07-18 00:00:00", + "2021-07-24 00:00:00", + "2021-07-25 00:00:00", + "2021-07-31 00:00:00", + "2021-08-01 00:00:00", + "2021-08-07 00:00:00", + "2021-08-08 00:00:00", + "2021-08-14 00:00:00", + "2021-08-15 00:00:00", + "2021-08-21 00:00:00", + "2021-08-22 00:00:00", + "2021-08-28 00:00:00", + "2021-08-29 00:00:00", + "2021-09-04 00:00:00", + "2021-09-05 00:00:00", + "2021-09-11 00:00:00", + "2021-09-12 00:00:00", + "2021-09-18 00:00:00", + "2021-09-19 00:00:00", + "2021-09-25 00:00:00", + "2021-09-26 00:00:00", + "2021-10-02 00:00:00", + "2021-10-03 00:00:00", + "2021-10-09 00:00:00", + "2021-10-10 00:00:00", + "2021-10-16 00:00:00", + "2021-10-17 00:00:00", + "2021-10-23 00:00:00", + "2021-10-24 00:00:00", + "2021-10-30 00:00:00", + "2021-10-31 00:00:00", + "2021-11-06 00:00:00", + "2021-11-07 00:00:00", + "2021-11-13 00:00:00", + "2021-11-14 00:00:00", + "2021-11-20 00:00:00", + "2021-11-21 00:00:00", + "2021-11-27 00:00:00", + "2021-11-28 00:00:00", + "2021-12-04 00:00:00", + "2021-12-05 00:00:00", + "2021-12-11 00:00:00", + "2021-12-12 00:00:00", + "2021-12-18 00:00:00", + "2021-12-19 00:00:00", + "2021-12-25 00:00:00", + "2021-12-26 00:00:00", + "2022-01-01 00:00:00", + "2022-01-02 00:00:00", + "2022-01-08 00:00:00", + "2022-01-09 00:00:00", + "2022-01-15 00:00:00", + "2022-01-16 00:00:00", + "2022-01-22 00:00:00", + "2022-01-23 00:00:00", + "2022-01-29 00:00:00", + "2022-01-30 00:00:00", + "2022-02-05 00:00:00", + "2022-02-06 00:00:00", + "2022-02-12 00:00:00", + "2022-02-13 00:00:00", + "2022-02-19 00:00:00", + "2022-02-20 00:00:00", + "2022-02-26 00:00:00", + "2022-02-27 00:00:00", + "2022-03-05 00:00:00", + "2022-03-06 00:00:00", + "2022-03-12 00:00:00", + "2022-03-13 00:00:00", + "2022-03-19 00:00:00", + "2022-03-20 00:00:00", + "2022-03-26 00:00:00", + "2022-03-27 00:00:00", + "2022-04-02 00:00:00", + "2022-04-03 00:00:00", + "2022-04-09 00:00:00", + "2022-04-10 00:00:00", + "2022-04-16 00:00:00", + "2022-04-17 00:00:00", + "2022-04-23 00:00:00", + "2022-04-24 00:00:00", + "2022-04-30 00:00:00", + "2022-05-01 00:00:00", + "2022-05-07 00:00:00", + "2022-05-08 00:00:00", + "2022-05-14 00:00:00", + "2022-05-15 00:00:00", + "2022-05-21 00:00:00", + "2022-05-22 00:00:00", + "2022-05-28 00:00:00", + "2022-05-29 00:00:00", + "2022-06-04 00:00:00", + "2022-06-05 00:00:00", + "2022-06-11 00:00:00", + "2022-06-12 00:00:00", + "2022-06-18 00:00:00", + "2022-06-19 00:00:00", + "2022-06-25 00:00:00", + "2022-06-26 00:00:00", + "2022-07-02 00:00:00", + "2022-07-03 00:00:00", + "2022-07-09 00:00:00", + "2022-07-10 00:00:00", + "2022-07-16 00:00:00", + "2022-07-17 00:00:00", + "2022-07-23 00:00:00", + "2022-07-24 00:00:00", + "2022-07-30 00:00:00", + "2022-07-31 00:00:00", + "2022-08-06 00:00:00", + "2022-08-07 00:00:00", + "2022-08-13 00:00:00", + "2022-08-14 00:00:00", + "2022-08-20 00:00:00", + "2022-08-21 00:00:00", + "2022-08-27 00:00:00", + "2022-08-28 00:00:00", + "2022-09-03 00:00:00", + "2022-09-04 00:00:00", + "2022-09-10 00:00:00", + "2022-09-11 00:00:00", + "2022-09-17 00:00:00", + "2022-09-18 00:00:00", + "2022-09-24 00:00:00", + "2022-09-25 00:00:00", + "2022-10-01 00:00:00", + "2022-10-02 00:00:00", + "2022-10-08 00:00:00", + "2022-10-09 00:00:00", + "2022-10-15 00:00:00", + "2022-10-16 00:00:00", + "2022-10-22 00:00:00", + "2022-10-23 00:00:00", + "2022-10-29 00:00:00", + "2022-10-30 00:00:00", + "2022-11-05 00:00:00", + "2022-11-06 00:00:00", + "2022-11-12 00:00:00", + "2022-11-13 00:00:00", + "2022-11-19 00:00:00", + "2022-11-20 00:00:00", + "2022-11-26 00:00:00", + "2022-11-27 00:00:00", + "2022-12-03 00:00:00", + "2022-12-04 00:00:00", + "2022-12-10 00:00:00", + "2022-12-11 00:00:00", + "2022-12-17 00:00:00", + "2022-12-18 00:00:00", + "2022-12-24 00:00:00", + "2022-12-25 00:00:00", + "2022-12-31 00:00:00", + "2023-01-01 00:00:00", + "2023-01-07 00:00:00", + "2023-01-08 00:00:00", + "2023-01-14 00:00:00", + "2023-01-15 00:00:00", + "2023-01-21 00:00:00", + "2023-01-22 00:00:00", + "2023-01-28 00:00:00", + "2023-01-29 00:00:00", + "2023-02-04 00:00:00", + "2023-02-05 00:00:00", + "2023-02-11 00:00:00", + "2023-02-12 00:00:00", + "2023-02-18 00:00:00", + "2023-02-19 00:00:00", + "2023-02-25 00:00:00", + "2023-02-26 00:00:00", + "2023-03-04 00:00:00", + "2023-03-05 00:00:00", + "2023-03-11 00:00:00", + "2023-03-12 00:00:00", + "2023-03-18 00:00:00", + "2023-03-19 00:00:00", + "2023-03-25 00:00:00", + "2023-03-26 00:00:00", + "2023-04-01 00:00:00", + "2023-04-02 00:00:00", + "2023-04-08 00:00:00", + "2023-04-09 00:00:00", + "2023-04-15 00:00:00", + "2023-04-16 00:00:00", + "2023-04-22 00:00:00", + "2023-04-23 00:00:00", + "2023-04-29 00:00:00", + "2023-04-30 00:00:00", + "2023-05-06 00:00:00", + "2023-05-07 00:00:00", + "2023-05-13 00:00:00", + "2023-05-14 00:00:00", + "2023-05-20 00:00:00", + "2023-05-21 00:00:00", + "2023-05-27 00:00:00", + "2023-05-28 00:00:00", + "2023-06-03 00:00:00", + "2023-06-04 00:00:00", + "2023-06-10 00:00:00", + "2023-06-11 00:00:00", + "2023-06-17 00:00:00", + "2023-06-18 00:00:00", + "2023-06-24 00:00:00", + "2023-06-25 00:00:00", + "2023-07-01 00:00:00", + "2023-07-02 00:00:00", + "2023-07-08 00:00:00", + "2023-07-09 00:00:00", + "2023-07-15 00:00:00", + "2023-07-16 00:00:00", + "2023-07-22 00:00:00", + "2023-07-23 00:00:00", + "2023-07-29 00:00:00", + "2023-07-30 00:00:00", + "2023-08-05 00:00:00", + "2023-08-06 00:00:00", + "2023-08-12 00:00:00", + "2023-08-13 00:00:00", + "2023-08-19 00:00:00", + "2023-08-20 00:00:00", + "2023-08-26 00:00:00", + "2023-08-27 00:00:00", + "2023-09-02 00:00:00", + "2023-09-03 00:00:00", + "2023-09-09 00:00:00", + "2023-09-10 00:00:00", + "2023-09-16 00:00:00", + "2023-09-17 00:00:00", + "2023-09-23 00:00:00", + "2023-09-24 00:00:00", + "2023-09-30 00:00:00", + "2023-10-01 00:00:00", + "2023-10-07 00:00:00", + "2023-10-08 00:00:00", + "2023-10-14 00:00:00", + "2023-10-15 00:00:00", + "2023-10-21 00:00:00", + "2023-10-22 00:00:00", + "2023-10-28 00:00:00", + "2023-10-29 00:00:00", + "2023-11-04 00:00:00", + "2023-11-05 00:00:00", + "2023-11-11 00:00:00", + "2023-11-12 00:00:00", + "2023-11-18 00:00:00", + "2023-11-19 00:00:00", + "2023-11-25 00:00:00", + "2023-11-26 00:00:00", + "2023-12-02 00:00:00", + "2023-12-03 00:00:00", + "2023-12-09 00:00:00", + "2023-12-10 00:00:00", + "2023-12-16 00:00:00", + "2023-12-17 00:00:00", + "2023-12-23 00:00:00", + "2023-12-24 00:00:00", + "2023-12-30 00:00:00", + "2023-12-31 00:00:00", + "2024-01-06 00:00:00", + "2024-01-07 00:00:00", + "2024-01-13 00:00:00", + "2024-01-14 00:00:00", + "2024-01-20 00:00:00", + "2024-01-21 00:00:00", + "2024-01-27 00:00:00", + "2024-01-28 00:00:00", + "2024-02-03 00:00:00", + "2024-02-04 00:00:00", + "2024-02-10 00:00:00", + "2024-02-11 00:00:00", + "2024-02-17 00:00:00", + "2024-02-18 00:00:00", + "2024-02-24 00:00:00", + "2024-02-25 00:00:00", + "2024-03-02 00:00:00", + "2024-03-03 00:00:00", + "2024-03-09 00:00:00", + "2024-03-10 00:00:00", + "2024-03-16 00:00:00", + "2024-03-17 00:00:00", + "2024-03-23 00:00:00", + "2024-03-24 00:00:00", + "2024-03-30 00:00:00", + "2024-03-31 00:00:00", + "2024-04-06 00:00:00", + "2024-04-07 00:00:00", + "2024-04-13 00:00:00", + "2024-04-14 00:00:00", + "2024-04-20 00:00:00", + "2024-04-21 00:00:00", + "2024-04-27 00:00:00", + "2024-04-28 00:00:00", + "2024-05-04 00:00:00", + "2024-05-05 00:00:00", + "2024-05-11 00:00:00", + "2024-05-12 00:00:00", + "2024-05-18 00:00:00", + "2024-05-19 00:00:00", + "2024-05-25 00:00:00", + "2024-05-26 00:00:00", + "2024-06-01 00:00:00", + "2024-06-02 00:00:00", + "2024-06-08 00:00:00", + "2024-06-09 00:00:00", + "2024-06-15 00:00:00", + "2024-06-16 00:00:00", + "2024-06-22 00:00:00", + "2024-06-23 00:00:00", + "2024-06-29 00:00:00", + "2024-06-30 00:00:00", + "2024-07-06 00:00:00", + "2024-07-07 00:00:00", + "2024-07-13 00:00:00", + "2024-07-14 00:00:00", + "2024-07-20 00:00:00", + "2024-07-21 00:00:00", + "2024-07-27 00:00:00", + "2024-07-28 00:00:00", + "2024-08-03 00:00:00", + "2024-08-04 00:00:00", + "2024-08-10 00:00:00", + "2024-08-11 00:00:00", + "2024-08-17 00:00:00", + "2024-08-18 00:00:00", + "2024-08-24 00:00:00", + "2024-08-25 00:00:00", + "2024-08-31 00:00:00", + "2024-09-01 00:00:00", + "2024-09-07 00:00:00", + "2024-09-08 00:00:00", + "2024-09-14 00:00:00", + "2024-09-15 00:00:00", + "2024-09-21 00:00:00", + "2024-09-22 00:00:00", + "2024-09-28 00:00:00", + "2024-09-29 00:00:00", + "2024-10-05 00:00:00", + "2024-10-06 00:00:00", + "2024-10-12 00:00:00", + "2024-10-13 00:00:00", + "2024-10-19 00:00:00", + "2024-10-20 00:00:00", + "2024-10-26 00:00:00", + "2024-10-27 00:00:00", + "2024-11-02 00:00:00", + "2024-11-03 00:00:00", + "2024-11-09 00:00:00", + "2024-11-10 00:00:00", + "2024-11-16 00:00:00", + "2024-11-17 00:00:00", + "2024-11-23 00:00:00", + "2024-11-24 00:00:00", + "2024-11-30 00:00:00", + "2024-12-01 00:00:00", + "2024-12-07 00:00:00", + "2024-12-08 00:00:00", + "2024-12-14 00:00:00", + "2024-12-15 00:00:00", + "2024-12-21 00:00:00", + "2024-12-22 00:00:00", + "2024-12-28 00:00:00", + "2024-12-29 00:00:00", + "2025-01-01 00:00:00", + "2025-01-04 00:00:00", + "2025-01-05 00:00:00", + "2025-01-11 00:00:00", + "2025-01-12 00:00:00", + "2025-01-18 00:00:00", + "2025-01-19 00:00:00", + "2025-01-25 00:00:00", + "2025-01-28 00:00:00", + "2025-01-29 00:00:00", + "2025-01-30 00:00:00", + "2025-01-31 00:00:00", + "2025-02-01 00:00:00", + "2025-02-02 00:00:00", + "2025-02-03 00:00:00", + "2025-02-04 00:00:00", + "2025-02-09 00:00:00", + "2025-02-15 00:00:00", + "2025-02-16 00:00:00", + "2025-02-22 00:00:00", + "2025-02-23 00:00:00", + "2025-03-01 00:00:00", + "2025-03-02 00:00:00", + "2025-03-08 00:00:00", + "2025-03-09 00:00:00", + "2025-03-15 00:00:00", + "2025-03-16 00:00:00", + "2025-03-22 00:00:00", + "2025-03-23 00:00:00", + "2025-03-29 00:00:00", + "2025-03-30 00:00:00", + "2025-04-04 00:00:00", + "2025-04-05 00:00:00", + "2025-04-06 00:00:00", + "2025-04-12 00:00:00", + "2025-04-13 00:00:00", + "2025-04-19 00:00:00", + "2025-04-20 00:00:00", + "2025-04-26 00:00:00", + "2025-05-01 00:00:00", + "2025-05-02 00:00:00", + "2025-05-03 00:00:00", + "2025-05-04 00:00:00", + "2025-05-05 00:00:00", + "2025-05-10 00:00:00", + "2025-05-11 00:00:00", + "2025-05-17 00:00:00", + "2025-05-18 00:00:00", + "2025-05-24 00:00:00", + "2025-05-25 00:00:00", + "2025-05-31 00:00:00", + "2025-06-01 00:00:00", + "2025-06-02 00:00:00", + "2025-06-07 00:00:00", + "2025-06-08 00:00:00", + "2025-06-14 00:00:00", + "2025-06-15 00:00:00", + "2025-06-21 00:00:00", + "2025-06-22 00:00:00", + "2025-06-28 00:00:00", + "2025-06-29 00:00:00", + "2025-07-05 00:00:00", + "2025-07-06 00:00:00", + "2025-07-12 00:00:00", + "2025-07-13 00:00:00", + "2025-07-19 00:00:00", + "2025-07-20 00:00:00", + "2025-07-26 00:00:00", + "2025-07-27 00:00:00", + "2025-08-02 00:00:00", + "2025-08-03 00:00:00", + "2025-08-09 00:00:00", + "2025-08-10 00:00:00", + "2025-08-16 00:00:00", + "2025-08-17 00:00:00", + "2025-08-23 00:00:00", + "2025-08-24 00:00:00", + "2025-08-30 00:00:00", + "2025-08-31 00:00:00", + "2025-09-06 00:00:00", + "2025-09-07 00:00:00", + "2025-09-13 00:00:00", + "2025-09-14 00:00:00", + "2025-09-20 00:00:00", + "2025-09-21 00:00:00", + "2025-09-27 00:00:00", + "2025-10-01 00:00:00", + "2025-10-02 00:00:00", + "2025-10-03 00:00:00", + "2025-10-04 00:00:00", + "2025-10-05 00:00:00", + "2025-10-06 00:00:00", + "2025-10-07 00:00:00", + "2025-10-08 00:00:00", + "2025-10-12 00:00:00", + "2025-10-18 00:00:00", + "2025-10-19 00:00:00", + "2025-10-25 00:00:00", + "2025-10-26 00:00:00", + "2025-11-01 00:00:00", + "2025-11-02 00:00:00", + "2025-11-08 00:00:00", + "2025-11-09 00:00:00", + "2025-11-15 00:00:00", + "2025-11-16 00:00:00", + "2025-11-22 00:00:00", + "2025-11-23 00:00:00", + "2025-11-29 00:00:00", + "2025-11-30 00:00:00", + "2025-12-06 00:00:00", + "2025-12-07 00:00:00", + "2025-12-13 00:00:00", + "2025-12-14 00:00:00", + "2025-12-20 00:00:00", + "2025-12-21 00:00:00", + "2025-12-27 00:00:00", + "2025-12-28 00:00:00", + "2026-01-01 00:00:00", + "2026-01-02 00:00:00", + "2026-01-03 00:00:00", + "2026-01-10 00:00:00", + "2026-01-11 00:00:00", + "2026-01-17 00:00:00", + "2026-01-18 00:00:00", + "2026-01-24 00:00:00", + "2026-01-25 00:00:00", + "2026-01-31 00:00:00", + "2026-02-01 00:00:00", + "2026-02-07 00:00:00", + "2026-02-08 00:00:00", + "2026-02-15 00:00:00", + "2026-02-16 00:00:00", + "2026-02-17 00:00:00", + "2026-02-18 00:00:00", + "2026-02-19 00:00:00", + "2026-02-20 00:00:00", + "2026-02-21 00:00:00", + "2026-02-22 00:00:00", + "2026-02-23 00:00:00", + "2026-03-01 00:00:00", + "2026-03-07 00:00:00", + "2026-03-08 00:00:00", + "2026-03-14 00:00:00", + "2026-03-15 00:00:00", + "2026-03-21 00:00:00", + "2026-03-22 00:00:00", + "2026-03-28 00:00:00", + "2026-03-29 00:00:00", + "2026-04-04 00:00:00", + "2026-04-05 00:00:00", + "2026-04-06 00:00:00", + "2026-04-11 00:00:00", + "2026-04-12 00:00:00", + "2026-04-18 00:00:00", + "2026-04-19 00:00:00", + "2026-04-25 00:00:00", + "2026-04-26 00:00:00", + "2026-05-01 00:00:00", + "2026-05-02 00:00:00", + "2026-05-03 00:00:00", + "2026-05-04 00:00:00", + "2026-05-05 00:00:00", + "2026-05-10 00:00:00", + "2026-05-16 00:00:00", + "2026-05-17 00:00:00", + "2026-05-23 00:00:00", + "2026-05-24 00:00:00", + "2026-05-30 00:00:00", + "2026-05-31 00:00:00", + "2026-06-06 00:00:00", + "2026-06-07 00:00:00", + "2026-06-13 00:00:00", + "2026-06-14 00:00:00", + "2026-06-19 00:00:00", + "2026-06-20 00:00:00", + "2026-06-21 00:00:00", + "2026-06-27 00:00:00", + "2026-06-28 00:00:00", + "2026-07-04 00:00:00", + "2026-07-05 00:00:00", + "2026-07-11 00:00:00", + "2026-07-12 00:00:00", + "2026-07-18 00:00:00", + "2026-07-19 00:00:00", + "2026-07-25 00:00:00", + "2026-07-26 00:00:00", + "2026-08-01 00:00:00", + "2026-08-02 00:00:00", + "2026-08-08 00:00:00", + "2026-08-09 00:00:00", + "2026-08-15 00:00:00", + "2026-08-16 00:00:00", + "2026-08-22 00:00:00", + "2026-08-23 00:00:00", + "2026-08-29 00:00:00", + "2026-08-30 00:00:00", + "2026-09-05 00:00:00", + "2026-09-06 00:00:00", + "2026-09-12 00:00:00", + "2026-09-13 00:00:00", + "2026-09-19 00:00:00", + "2026-09-25 00:00:00", + "2026-09-26 00:00:00", + "2026-09-27 00:00:00", + "2026-10-01 00:00:00", + "2026-10-02 00:00:00", + "2026-10-03 00:00:00", + "2026-10-04 00:00:00", + "2026-10-05 00:00:00", + "2026-10-06 00:00:00", + "2026-10-07 00:00:00", + "2026-10-11 00:00:00", + "2026-10-17 00:00:00", + "2026-10-18 00:00:00", + "2026-10-24 00:00:00", + "2026-10-25 00:00:00", + "2026-10-31 00:00:00", + "2026-11-01 00:00:00", + "2026-11-07 00:00:00", + "2026-11-08 00:00:00", + "2026-11-14 00:00:00", + "2026-11-15 00:00:00", + "2026-11-21 00:00:00", + "2026-11-22 00:00:00", + "2026-11-28 00:00:00", + "2026-11-29 00:00:00", + "2026-12-05 00:00:00", + "2026-12-06 00:00:00", + "2026-12-12 00:00:00", + "2026-12-13 00:00:00", + "2026-12-19 00:00:00", + "2026-12-20 00:00:00", + "2026-12-26 00:00:00", + "2026-12-27 00:00:00", + "2027-01-01 00:00:00", + "2027-01-02 00:00:00", + "2027-01-03 00:00:00", + "2027-01-09 00:00:00", + "2027-01-10 00:00:00", + "2027-01-16 00:00:00", + "2027-01-17 00:00:00", + "2027-01-23 00:00:00", + "2027-01-24 00:00:00", + "2027-01-30 00:00:00", + "2027-02-05 00:00:00", + "2027-02-06 00:00:00", + "2027-02-07 00:00:00", + "2027-02-08 00:00:00", + "2027-02-09 00:00:00", + "2027-02-10 00:00:00", + "2027-02-11 00:00:00", + "2027-02-12 00:00:00", + "2027-02-14 00:00:00", + "2027-02-20 00:00:00", + "2027-02-21 00:00:00", + "2027-02-27 00:00:00", + "2027-02-28 00:00:00", + "2027-03-06 00:00:00", + "2027-03-07 00:00:00", + "2027-03-13 00:00:00", + "2027-03-14 00:00:00", + "2027-03-20 00:00:00", + "2027-03-21 00:00:00", + "2027-03-27 00:00:00", + "2027-03-28 00:00:00", + "2027-04-03 00:00:00", + "2027-04-04 00:00:00", + "2027-04-05 00:00:00", + "2027-04-10 00:00:00", + "2027-04-11 00:00:00", + "2027-04-17 00:00:00", + "2027-04-18 00:00:00", + "2027-04-24 00:00:00", + "2027-04-25 00:00:00", + "2027-05-01 00:00:00", + "2027-05-02 00:00:00", + "2027-05-03 00:00:00", + "2027-05-04 00:00:00", + "2027-05-05 00:00:00", + "2027-05-08 00:00:00", + "2027-05-15 00:00:00", + "2027-05-16 00:00:00", + "2027-05-22 00:00:00", + "2027-05-23 00:00:00", + "2027-05-29 00:00:00", + "2027-05-30 00:00:00", + "2027-06-05 00:00:00", + "2027-06-06 00:00:00", + "2027-06-09 00:00:00", + "2027-06-12 00:00:00", + "2027-06-13 00:00:00", + "2027-06-19 00:00:00", + "2027-06-20 00:00:00", + "2027-06-26 00:00:00", + "2027-06-27 00:00:00", + "2027-07-03 00:00:00", + "2027-07-04 00:00:00", + "2027-07-10 00:00:00", + "2027-07-11 00:00:00", + "2027-07-17 00:00:00", + "2027-07-18 00:00:00", + "2027-07-24 00:00:00", + "2027-07-25 00:00:00", + "2027-07-31 00:00:00", + "2027-08-01 00:00:00", + "2027-08-07 00:00:00", + "2027-08-08 00:00:00", + "2027-08-14 00:00:00", + "2027-08-15 00:00:00", + "2027-08-21 00:00:00", + "2027-08-22 00:00:00", + "2027-08-28 00:00:00", + "2027-08-29 00:00:00", + "2027-09-04 00:00:00", + "2027-09-05 00:00:00", + "2027-09-11 00:00:00", + "2027-09-12 00:00:00", + "2027-09-15 00:00:00", + "2027-09-18 00:00:00", + "2027-09-19 00:00:00", + "2027-09-25 00:00:00", + "2027-10-01 00:00:00", + "2027-10-02 00:00:00", + "2027-10-03 00:00:00", + "2027-10-04 00:00:00", + "2027-10-05 00:00:00", + "2027-10-06 00:00:00", + "2027-10-07 00:00:00", + "2027-10-10 00:00:00", + "2027-10-16 00:00:00", + "2027-10-17 00:00:00", + "2027-10-23 00:00:00", + "2027-10-24 00:00:00", + "2027-10-30 00:00:00", + "2027-10-31 00:00:00", + "2027-11-06 00:00:00", + "2027-11-07 00:00:00", + "2027-11-13 00:00:00", + "2027-11-14 00:00:00", + "2027-11-20 00:00:00", + "2027-11-21 00:00:00", + "2027-11-27 00:00:00", + "2027-11-28 00:00:00", + "2027-12-04 00:00:00", + "2027-12-05 00:00:00", + "2027-12-11 00:00:00", + "2027-12-12 00:00:00", + "2027-12-18 00:00:00", + "2027-12-19 00:00:00", + "2027-12-25 00:00:00", + "2027-12-26 00:00:00", + "2028-01-01 00:00:00", + "2028-01-02 00:00:00", + "2028-01-03 00:00:00", + "2028-01-08 00:00:00", + "2028-01-09 00:00:00", + "2028-01-15 00:00:00", + "2028-01-16 00:00:00", + "2028-01-22 00:00:00", + "2028-01-25 00:00:00", + "2028-01-26 00:00:00", + "2028-01-27 00:00:00", + "2028-01-28 00:00:00", + "2028-01-29 00:00:00", + "2028-01-30 00:00:00", + "2028-01-31 00:00:00", + "2028-02-01 00:00:00", + "2028-02-06 00:00:00", + "2028-02-12 00:00:00", + "2028-02-13 00:00:00", + "2028-02-19 00:00:00", + "2028-02-20 00:00:00", + "2028-02-26 00:00:00", + "2028-02-27 00:00:00", + "2028-03-04 00:00:00", + "2028-03-05 00:00:00", + "2028-03-11 00:00:00", + "2028-03-12 00:00:00", + "2028-03-18 00:00:00", + "2028-03-19 00:00:00", + "2028-03-25 00:00:00", + "2028-04-01 00:00:00", + "2028-04-02 00:00:00", + "2028-04-03 00:00:00", + "2028-04-04 00:00:00", + "2028-04-08 00:00:00", + "2028-04-09 00:00:00", + "2028-04-15 00:00:00", + "2028-04-16 00:00:00", + "2028-04-22 00:00:00", + "2028-04-23 00:00:00", + "2028-04-29 00:00:00", + "2028-04-30 00:00:00", + "2028-05-01 00:00:00", + "2028-05-02 00:00:00", + "2028-05-03 00:00:00", + "2028-05-06 00:00:00", + "2028-05-13 00:00:00", + "2028-05-14 00:00:00", + "2028-05-20 00:00:00", + "2028-05-21 00:00:00", + "2028-05-27 00:00:00", + "2028-05-28 00:00:00", + "2028-05-29 00:00:00", + "2028-06-03 00:00:00", + "2028-06-04 00:00:00", + "2028-06-10 00:00:00", + "2028-06-11 00:00:00", + "2028-06-17 00:00:00", + "2028-06-18 00:00:00", + "2028-06-24 00:00:00", + "2028-06-25 00:00:00", + "2028-07-01 00:00:00", + "2028-07-02 00:00:00", + "2028-07-08 00:00:00", + "2028-07-09 00:00:00", + "2028-07-15 00:00:00", + "2028-07-16 00:00:00", + "2028-07-22 00:00:00", + "2028-07-23 00:00:00", + "2028-07-29 00:00:00", + "2028-07-30 00:00:00", + "2028-08-05 00:00:00", + "2028-08-06 00:00:00", + "2028-08-12 00:00:00", + "2028-08-13 00:00:00", + "2028-08-19 00:00:00", + "2028-08-20 00:00:00", + "2028-08-26 00:00:00", + "2028-08-27 00:00:00", + "2028-09-02 00:00:00", + "2028-09-03 00:00:00", + "2028-09-09 00:00:00", + "2028-09-10 00:00:00", + "2028-09-16 00:00:00", + "2028-09-17 00:00:00", + "2028-09-23 00:00:00", + "2028-09-30 00:00:00", + "2028-10-01 00:00:00", + "2028-10-02 00:00:00", + "2028-10-03 00:00:00", + "2028-10-04 00:00:00", + "2028-10-05 00:00:00", + "2028-10-06 00:00:00", + "2028-10-07 00:00:00", + "2028-10-08 00:00:00", + "2028-10-14 00:00:00", + "2028-10-15 00:00:00", + "2028-10-21 00:00:00", + "2028-10-22 00:00:00", + "2028-10-28 00:00:00", + "2028-10-29 00:00:00", + "2028-11-04 00:00:00", + "2028-11-05 00:00:00", + "2028-11-11 00:00:00", + "2028-11-12 00:00:00", + "2028-11-18 00:00:00", + "2028-11-19 00:00:00", + "2028-11-25 00:00:00", + "2028-11-26 00:00:00", + "2028-12-02 00:00:00", + "2028-12-03 00:00:00", + "2028-12-09 00:00:00", + "2028-12-10 00:00:00", + "2028-12-16 00:00:00", + "2028-12-17 00:00:00", + "2028-12-23 00:00:00", + "2028-12-24 00:00:00", + "2028-12-30 00:00:00", + "2028-12-31 00:00:00", + "2029-01-01 00:00:00", + "2029-01-06 00:00:00", + "2029-01-07 00:00:00", + "2029-01-13 00:00:00", + "2029-01-14 00:00:00", + "2029-01-20 00:00:00", + "2029-01-21 00:00:00", + "2029-01-27 00:00:00", + "2029-01-28 00:00:00", + "2029-02-03 00:00:00", + "2029-02-04 00:00:00", + "2029-02-11 00:00:00", + "2029-02-12 00:00:00", + "2029-02-13 00:00:00", + "2029-02-14 00:00:00", + "2029-02-15 00:00:00", + "2029-02-16 00:00:00", + "2029-02-17 00:00:00", + "2029-02-18 00:00:00", + "2029-02-19 00:00:00", + "2029-02-25 00:00:00", + "2029-03-03 00:00:00", + "2029-03-04 00:00:00", + "2029-03-10 00:00:00", + "2029-03-11 00:00:00", + "2029-03-17 00:00:00", + "2029-03-18 00:00:00", + "2029-03-24 00:00:00", + "2029-03-25 00:00:00", + "2029-03-31 00:00:00", + "2029-04-01 00:00:00", + "2029-04-04 00:00:00", + "2029-04-07 00:00:00", + "2029-04-08 00:00:00", + "2029-04-14 00:00:00", + "2029-04-15 00:00:00", + "2029-04-21 00:00:00", + "2029-04-22 00:00:00", + "2029-04-28 00:00:00", + "2029-04-29 00:00:00", + "2029-04-30 00:00:00", + "2029-05-01 00:00:00", + "2029-05-02 00:00:00", + "2029-05-05 00:00:00", + "2029-05-06 00:00:00", + "2029-05-12 00:00:00", + "2029-05-13 00:00:00", + "2029-05-19 00:00:00", + "2029-05-20 00:00:00", + "2029-05-26 00:00:00", + "2029-05-27 00:00:00", + "2029-06-02 00:00:00", + "2029-06-03 00:00:00", + "2029-06-09 00:00:00", + "2029-06-10 00:00:00", + "2029-06-16 00:00:00", + "2029-06-17 00:00:00", + "2029-06-18 00:00:00", + "2029-06-23 00:00:00", + "2029-06-24 00:00:00", + "2029-06-30 00:00:00", + "2029-07-01 00:00:00", + "2029-07-07 00:00:00", + "2029-07-08 00:00:00", + "2029-07-14 00:00:00", + "2029-07-15 00:00:00", + "2029-07-21 00:00:00", + "2029-07-22 00:00:00", + "2029-07-28 00:00:00", + "2029-07-29 00:00:00", + "2029-08-04 00:00:00", + "2029-08-05 00:00:00", + "2029-08-11 00:00:00", + "2029-08-12 00:00:00", + "2029-08-18 00:00:00", + "2029-08-19 00:00:00", + "2029-08-25 00:00:00", + "2029-08-26 00:00:00", + "2029-09-01 00:00:00", + "2029-09-02 00:00:00", + "2029-09-08 00:00:00", + "2029-09-09 00:00:00", + "2029-09-15 00:00:00", + "2029-09-16 00:00:00", + "2029-09-22 00:00:00", + "2029-09-23 00:00:00", + "2029-09-24 00:00:00", + "2029-09-30 00:00:00", + "2029-10-01 00:00:00", + "2029-10-02 00:00:00", + "2029-10-03 00:00:00", + "2029-10-04 00:00:00", + "2029-10-05 00:00:00", + "2029-10-06 00:00:00", + "2029-10-07 00:00:00", + "2029-10-14 00:00:00", + "2029-10-20 00:00:00", + "2029-10-21 00:00:00", + "2029-10-27 00:00:00", + "2029-10-28 00:00:00", + "2029-11-03 00:00:00", + "2029-11-04 00:00:00", + "2029-11-10 00:00:00", + "2029-11-11 00:00:00", + "2029-11-17 00:00:00", + "2029-11-18 00:00:00", + "2029-11-24 00:00:00", + "2029-11-25 00:00:00", + "2029-12-01 00:00:00", + "2029-12-02 00:00:00", + "2029-12-08 00:00:00", + "2029-12-09 00:00:00", + "2029-12-15 00:00:00", + "2029-12-16 00:00:00", + "2029-12-22 00:00:00", + "2029-12-23 00:00:00", + "2029-12-30 00:00:00", + "2029-12-31 00:00:00", + "2030-01-01 00:00:00", + "2030-01-05 00:00:00", + "2030-01-06 00:00:00", + "2030-01-12 00:00:00", + "2030-01-13 00:00:00", + "2030-01-19 00:00:00", + "2030-01-20 00:00:00", + "2030-01-26 00:00:00", + "2030-02-01 00:00:00", + "2030-02-02 00:00:00", + "2030-02-03 00:00:00", + "2030-02-04 00:00:00", + "2030-02-05 00:00:00", + "2030-02-06 00:00:00", + "2030-02-07 00:00:00", + "2030-02-08 00:00:00", + "2030-02-10 00:00:00", + "2030-02-16 00:00:00", + "2030-02-17 00:00:00", + "2030-02-23 00:00:00", + "2030-02-24 00:00:00", + "2030-03-02 00:00:00", + "2030-03-03 00:00:00", + "2030-03-09 00:00:00", + "2030-03-10 00:00:00", + "2030-03-16 00:00:00", + "2030-03-17 00:00:00", + "2030-03-23 00:00:00", + "2030-03-24 00:00:00", + "2030-03-30 00:00:00", + "2030-03-31 00:00:00", + "2030-04-04 00:00:00", + "2030-04-05 00:00:00", + "2030-04-06 00:00:00", + "2030-04-07 00:00:00", + "2030-04-13 00:00:00", + "2030-04-20 00:00:00", + "2030-04-21 00:00:00", + "2030-04-27 00:00:00", + "2030-04-28 00:00:00", + "2030-05-01 00:00:00", + "2030-05-02 00:00:00", + "2030-05-04 00:00:00", + "2030-05-05 00:00:00", + "2030-05-11 00:00:00", + "2030-05-12 00:00:00", + "2030-05-18 00:00:00", + "2030-05-19 00:00:00", + "2030-05-25 00:00:00", + "2030-05-26 00:00:00", + "2030-06-01 00:00:00", + "2030-06-02 00:00:00", + "2030-06-05 00:00:00", + "2030-06-08 00:00:00", + "2030-06-09 00:00:00", + "2030-06-15 00:00:00", + "2030-06-16 00:00:00", + "2030-06-22 00:00:00", + "2030-06-23 00:00:00", + "2030-06-29 00:00:00", + "2030-06-30 00:00:00", + "2030-07-06 00:00:00", + "2030-07-07 00:00:00", + "2030-07-13 00:00:00", + "2030-07-14 00:00:00", + "2030-07-20 00:00:00", + "2030-07-21 00:00:00", + "2030-07-27 00:00:00", + "2030-07-28 00:00:00", + "2030-08-03 00:00:00", + "2030-08-04 00:00:00", + "2030-08-10 00:00:00", + "2030-08-11 00:00:00", + "2030-08-17 00:00:00", + "2030-08-18 00:00:00", + "2030-08-24 00:00:00", + "2030-08-25 00:00:00", + "2030-08-31 00:00:00", + "2030-09-01 00:00:00", + "2030-09-07 00:00:00", + "2030-09-08 00:00:00", + "2030-09-12 00:00:00", + "2030-09-13 00:00:00", + "2030-09-14 00:00:00", + "2030-09-15 00:00:00", + "2030-09-21 00:00:00", + "2030-09-28 00:00:00", + "2030-10-01 00:00:00", + "2030-10-02 00:00:00", + "2030-10-03 00:00:00", + "2030-10-04 00:00:00", + "2030-10-05 00:00:00", + "2030-10-06 00:00:00", + "2030-10-07 00:00:00", + "2030-10-13 00:00:00", + "2030-10-19 00:00:00", + "2030-10-20 00:00:00", + "2030-10-26 00:00:00", + "2030-10-27 00:00:00", + "2030-11-02 00:00:00", + "2030-11-03 00:00:00", + "2030-11-09 00:00:00", + "2030-11-10 00:00:00", + "2030-11-16 00:00:00", + "2030-11-17 00:00:00", + "2030-11-23 00:00:00", + "2030-11-24 00:00:00", + "2030-11-30 00:00:00", + "2030-12-01 00:00:00", + "2030-12-07 00:00:00", + "2030-12-08 00:00:00", + "2030-12-14 00:00:00", + "2030-12-15 00:00:00", + "2030-12-21 00:00:00", + "2030-12-22 00:00:00", + "2030-12-28 00:00:00", + "2030-12-29 00:00:00", + "2031-01-01 00:00:00", + "2031-01-04 00:00:00", + "2031-01-05 00:00:00", + "2031-01-11 00:00:00", + "2031-01-12 00:00:00", + "2031-01-18 00:00:00", + "2031-01-22 00:00:00", + "2031-01-23 00:00:00", + "2031-01-24 00:00:00", + "2031-01-25 00:00:00", + "2031-01-26 00:00:00", + "2031-01-27 00:00:00", + "2031-01-28 00:00:00", + "2031-01-29 00:00:00", + "2031-02-02 00:00:00", + "2031-02-08 00:00:00", + "2031-02-09 00:00:00", + "2031-02-15 00:00:00", + "2031-02-16 00:00:00", + "2031-02-22 00:00:00", + "2031-02-23 00:00:00", + "2031-03-01 00:00:00", + "2031-03-02 00:00:00", + "2031-03-08 00:00:00", + "2031-03-09 00:00:00", + "2031-03-15 00:00:00", + "2031-03-16 00:00:00", + "2031-03-22 00:00:00", + "2031-03-23 00:00:00", + "2031-03-29 00:00:00", + "2031-03-30 00:00:00", + "2031-04-04 00:00:00", + "2031-04-05 00:00:00", + "2031-04-06 00:00:00", + "2031-04-12 00:00:00", + "2031-04-13 00:00:00", + "2031-04-19 00:00:00", + "2031-04-20 00:00:00", + "2031-04-26 00:00:00", + "2031-05-01 00:00:00", + "2031-05-02 00:00:00", + "2031-05-03 00:00:00", + "2031-05-04 00:00:00", + "2031-05-05 00:00:00", + "2031-05-10 00:00:00", + "2031-05-11 00:00:00", + "2031-05-17 00:00:00", + "2031-05-18 00:00:00", + "2031-05-24 00:00:00", + "2031-05-25 00:00:00", + "2031-05-31 00:00:00", + "2031-06-01 00:00:00", + "2031-06-07 00:00:00", + "2031-06-08 00:00:00", + "2031-06-14 00:00:00", + "2031-06-21 00:00:00", + "2031-06-22 00:00:00", + "2031-06-23 00:00:00", + "2031-06-24 00:00:00", + "2031-06-28 00:00:00", + "2031-06-29 00:00:00", + "2031-07-05 00:00:00", + "2031-07-06 00:00:00", + "2031-07-12 00:00:00", + "2031-07-13 00:00:00", + "2031-07-19 00:00:00", + "2031-07-20 00:00:00", + "2031-07-26 00:00:00", + "2031-07-27 00:00:00", + "2031-08-02 00:00:00", + "2031-08-03 00:00:00", + "2031-08-09 00:00:00", + "2031-08-10 00:00:00", + "2031-08-16 00:00:00", + "2031-08-17 00:00:00", + "2031-08-23 00:00:00", + "2031-08-24 00:00:00", + "2031-08-30 00:00:00", + "2031-08-31 00:00:00", + "2031-09-06 00:00:00", + "2031-09-07 00:00:00", + "2031-09-13 00:00:00", + "2031-09-14 00:00:00", + "2031-09-20 00:00:00", + "2031-09-21 00:00:00", + "2031-09-27 00:00:00", + "2031-10-01 00:00:00", + "2031-10-02 00:00:00", + "2031-10-03 00:00:00", + "2031-10-04 00:00:00", + "2031-10-05 00:00:00", + "2031-10-06 00:00:00", + "2031-10-07 00:00:00", + "2031-10-08 00:00:00", + "2031-10-12 00:00:00", + "2031-10-18 00:00:00", + "2031-10-19 00:00:00", + "2031-10-25 00:00:00", + "2031-10-26 00:00:00", + "2031-11-01 00:00:00", + "2031-11-02 00:00:00", + "2031-11-08 00:00:00", + "2031-11-09 00:00:00", + "2031-11-15 00:00:00", + "2031-11-16 00:00:00", + "2031-11-22 00:00:00", + "2031-11-23 00:00:00", + "2031-11-29 00:00:00", + "2031-11-30 00:00:00", + "2031-12-06 00:00:00", + "2031-12-07 00:00:00", + "2031-12-13 00:00:00", + "2031-12-14 00:00:00", + "2031-12-20 00:00:00", + "2031-12-21 00:00:00", + "2031-12-27 00:00:00", + "2031-12-28 00:00:00", + "2032-01-01 00:00:00", + "2032-01-02 00:00:00", + "2032-01-03 00:00:00", + "2032-01-10 00:00:00", + "2032-01-11 00:00:00", + "2032-01-17 00:00:00", + "2032-01-18 00:00:00", + "2032-01-24 00:00:00", + "2032-01-25 00:00:00", + "2032-01-31 00:00:00", + "2032-02-01 00:00:00", + "2032-02-07 00:00:00", + "2032-02-10 00:00:00", + "2032-02-11 00:00:00", + "2032-02-12 00:00:00", + "2032-02-13 00:00:00", + "2032-02-14 00:00:00", + "2032-02-15 00:00:00", + "2032-02-16 00:00:00", + "2032-02-17 00:00:00", + "2032-02-22 00:00:00", + "2032-02-28 00:00:00", + "2032-02-29 00:00:00", + "2032-03-06 00:00:00", + "2032-03-07 00:00:00", + "2032-03-13 00:00:00", + "2032-03-14 00:00:00", + "2032-03-20 00:00:00", + "2032-03-21 00:00:00", + "2032-03-27 00:00:00", + "2032-03-28 00:00:00", + "2032-04-03 00:00:00", + "2032-04-04 00:00:00", + "2032-04-05 00:00:00", + "2032-04-10 00:00:00", + "2032-04-11 00:00:00", + "2032-04-17 00:00:00", + "2032-04-18 00:00:00", + "2032-04-24 00:00:00", + "2032-04-25 00:00:00", + "2032-05-01 00:00:00", + "2032-05-02 00:00:00", + "2032-05-03 00:00:00", + "2032-05-04 00:00:00", + "2032-05-05 00:00:00", + "2032-05-08 00:00:00", + "2032-05-15 00:00:00", + "2032-05-16 00:00:00", + "2032-05-22 00:00:00", + "2032-05-23 00:00:00", + "2032-05-29 00:00:00", + "2032-05-30 00:00:00", + "2032-06-05 00:00:00", + "2032-06-06 00:00:00", + "2032-06-12 00:00:00", + "2032-06-13 00:00:00", + "2032-06-14 00:00:00", + "2032-06-19 00:00:00", + "2032-06-20 00:00:00", + "2032-06-26 00:00:00", + "2032-06-27 00:00:00", + "2032-07-03 00:00:00", + "2032-07-04 00:00:00", + "2032-07-10 00:00:00", + "2032-07-11 00:00:00", + "2032-07-17 00:00:00", + "2032-07-18 00:00:00", + "2032-07-24 00:00:00", + "2032-07-25 00:00:00", + "2032-07-31 00:00:00", + "2032-08-01 00:00:00", + "2032-08-07 00:00:00", + "2032-08-08 00:00:00", + "2032-08-14 00:00:00", + "2032-08-15 00:00:00", + "2032-08-21 00:00:00", + "2032-08-22 00:00:00", + "2032-08-28 00:00:00", + "2032-08-29 00:00:00", + "2032-09-04 00:00:00", + "2032-09-05 00:00:00", + "2032-09-11 00:00:00", + "2032-09-12 00:00:00", + "2032-09-18 00:00:00", + "2032-09-19 00:00:00", + "2032-09-20 00:00:00", + "2032-09-25 00:00:00", + "2032-10-01 00:00:00", + "2032-10-02 00:00:00", + "2032-10-03 00:00:00", + "2032-10-04 00:00:00", + "2032-10-05 00:00:00", + "2032-10-06 00:00:00", + "2032-10-07 00:00:00", + "2032-10-10 00:00:00", + "2032-10-16 00:00:00", + "2032-10-17 00:00:00", + "2032-10-23 00:00:00", + "2032-10-24 00:00:00", + "2032-10-30 00:00:00", + "2032-10-31 00:00:00", + "2032-11-06 00:00:00", + "2032-11-07 00:00:00", + "2032-11-13 00:00:00", + "2032-11-14 00:00:00", + "2032-11-20 00:00:00", + "2032-11-21 00:00:00", + "2032-11-27 00:00:00", + "2032-11-28 00:00:00", + "2032-12-04 00:00:00", + "2032-12-05 00:00:00", + "2032-12-11 00:00:00", + "2032-12-12 00:00:00", + "2032-12-18 00:00:00", + "2032-12-19 00:00:00", + "2032-12-25 00:00:00", + "2032-12-26 00:00:00", + "2033-01-01 00:00:00", + "2033-01-02 00:00:00", + "2033-01-03 00:00:00", + "2033-01-08 00:00:00", + "2033-01-09 00:00:00", + "2033-01-15 00:00:00", + "2033-01-16 00:00:00", + "2033-01-22 00:00:00", + "2033-01-23 00:00:00", + "2033-01-30 00:00:00", + "2033-01-31 00:00:00", + "2033-02-01 00:00:00", + "2033-02-02 00:00:00", + "2033-02-03 00:00:00", + "2033-02-04 00:00:00", + "2033-02-05 00:00:00", + "2033-02-06 00:00:00", + "2033-02-13 00:00:00", + "2033-02-19 00:00:00", + "2033-02-20 00:00:00", + "2033-02-26 00:00:00", + "2033-02-27 00:00:00", + "2033-03-05 00:00:00", + "2033-03-06 00:00:00", + "2033-03-12 00:00:00", + "2033-03-13 00:00:00", + "2033-03-19 00:00:00", + "2033-03-20 00:00:00", + "2033-03-26 00:00:00", + "2033-03-27 00:00:00", + "2033-04-02 00:00:00", + "2033-04-03 00:00:00", + "2033-04-04 00:00:00", + "2033-04-09 00:00:00", + "2033-04-10 00:00:00", + "2033-04-16 00:00:00", + "2033-04-17 00:00:00", + "2033-04-23 00:00:00", + "2033-04-24 00:00:00", + "2033-04-30 00:00:00", + "2033-05-01 00:00:00", + "2033-05-02 00:00:00", + "2033-05-03 00:00:00", + "2033-05-04 00:00:00", + "2033-05-07 00:00:00", + "2033-05-14 00:00:00", + "2033-05-15 00:00:00", + "2033-05-21 00:00:00", + "2033-05-22 00:00:00", + "2033-05-28 00:00:00", + "2033-05-29 00:00:00", + "2033-06-01 00:00:00", + "2033-06-04 00:00:00", + "2033-06-05 00:00:00", + "2033-06-11 00:00:00", + "2033-06-12 00:00:00", + "2033-06-18 00:00:00", + "2033-06-19 00:00:00", + "2033-06-25 00:00:00", + "2033-06-26 00:00:00", + "2033-07-02 00:00:00", + "2033-07-03 00:00:00", + "2033-07-09 00:00:00", + "2033-07-10 00:00:00", + "2033-07-16 00:00:00", + "2033-07-17 00:00:00", + "2033-07-23 00:00:00", + "2033-07-24 00:00:00", + "2033-07-30 00:00:00", + "2033-07-31 00:00:00", + "2033-08-06 00:00:00", + "2033-08-07 00:00:00", + "2033-08-13 00:00:00", + "2033-08-14 00:00:00", + "2033-08-20 00:00:00", + "2033-08-21 00:00:00", + "2033-08-27 00:00:00", + "2033-08-28 00:00:00", + "2033-09-03 00:00:00", + "2033-09-04 00:00:00", + "2033-09-08 00:00:00", + "2033-09-09 00:00:00", + "2033-09-10 00:00:00", + "2033-09-11 00:00:00", + "2033-09-17 00:00:00", + "2033-09-24 00:00:00", + "2033-10-01 00:00:00", + "2033-10-02 00:00:00", + "2033-10-03 00:00:00", + "2033-10-04 00:00:00", + "2033-10-05 00:00:00", + "2033-10-06 00:00:00", + "2033-10-07 00:00:00", + "2033-10-08 00:00:00", + "2033-10-15 00:00:00", + "2033-10-16 00:00:00", + "2033-10-22 00:00:00", + "2033-10-23 00:00:00", + "2033-10-29 00:00:00", + "2033-10-30 00:00:00", + "2033-11-05 00:00:00", + "2033-11-06 00:00:00", + "2033-11-12 00:00:00", + "2033-11-13 00:00:00", + "2033-11-19 00:00:00", + "2033-11-20 00:00:00", + "2033-11-26 00:00:00", + "2033-11-27 00:00:00", + "2033-12-03 00:00:00", + "2033-12-04 00:00:00", + "2033-12-10 00:00:00", + "2033-12-11 00:00:00", + "2033-12-17 00:00:00", + "2033-12-18 00:00:00", + "2033-12-24 00:00:00", + "2033-12-25 00:00:00", + "2033-12-31 00:00:00", + "2034-01-01 00:00:00", + "2034-01-02 00:00:00", + "2034-01-07 00:00:00", + "2034-01-08 00:00:00", + "2034-01-14 00:00:00", + "2034-01-15 00:00:00", + "2034-01-21 00:00:00", + "2034-01-22 00:00:00", + "2034-01-28 00:00:00", + "2034-01-29 00:00:00", + "2034-02-04 00:00:00", + "2034-02-05 00:00:00", + "2034-02-11 00:00:00", + "2034-02-18 00:00:00", + "2034-02-19 00:00:00", + "2034-02-20 00:00:00", + "2034-02-21 00:00:00", + "2034-02-22 00:00:00", + "2034-02-23 00:00:00", + "2034-02-24 00:00:00", + "2034-02-25 00:00:00", + "2034-03-04 00:00:00", + "2034-03-05 00:00:00", + "2034-03-11 00:00:00", + "2034-03-12 00:00:00", + "2034-03-18 00:00:00", + "2034-03-19 00:00:00", + "2034-03-25 00:00:00", + "2034-04-01 00:00:00", + "2034-04-02 00:00:00", + "2034-04-03 00:00:00", + "2034-04-04 00:00:00", + "2034-04-08 00:00:00", + "2034-04-09 00:00:00", + "2034-04-15 00:00:00", + "2034-04-16 00:00:00", + "2034-04-22 00:00:00", + "2034-04-23 00:00:00", + "2034-04-29 00:00:00", + "2034-04-30 00:00:00", + "2034-05-01 00:00:00", + "2034-05-02 00:00:00", + "2034-05-03 00:00:00", + "2034-05-06 00:00:00", + "2034-05-13 00:00:00", + "2034-05-14 00:00:00", + "2034-05-20 00:00:00", + "2034-05-21 00:00:00", + "2034-05-27 00:00:00", + "2034-05-28 00:00:00", + "2034-06-03 00:00:00", + "2034-06-04 00:00:00", + "2034-06-10 00:00:00", + "2034-06-17 00:00:00", + "2034-06-18 00:00:00", + "2034-06-19 00:00:00", + "2034-06-20 00:00:00", + "2034-06-24 00:00:00", + "2034-06-25 00:00:00", + "2034-07-01 00:00:00", + "2034-07-02 00:00:00", + "2034-07-08 00:00:00", + "2034-07-09 00:00:00", + "2034-07-15 00:00:00", + "2034-07-16 00:00:00", + "2034-07-22 00:00:00", + "2034-07-23 00:00:00", + "2034-07-29 00:00:00", + "2034-07-30 00:00:00", + "2034-08-05 00:00:00", + "2034-08-06 00:00:00", + "2034-08-12 00:00:00", + "2034-08-13 00:00:00", + "2034-08-19 00:00:00", + "2034-08-20 00:00:00", + "2034-08-26 00:00:00", + "2034-08-27 00:00:00", + "2034-09-02 00:00:00", + "2034-09-03 00:00:00", + "2034-09-09 00:00:00", + "2034-09-10 00:00:00", + "2034-09-16 00:00:00", + "2034-09-17 00:00:00", + "2034-09-23 00:00:00", + "2034-09-27 00:00:00", + "2034-09-30 00:00:00", + "2034-10-01 00:00:00", + "2034-10-02 00:00:00", + "2034-10-03 00:00:00", + "2034-10-04 00:00:00", + "2034-10-05 00:00:00", + "2034-10-06 00:00:00", + "2034-10-07 00:00:00", + "2034-10-14 00:00:00", + "2034-10-15 00:00:00", + "2034-10-21 00:00:00", + "2034-10-22 00:00:00", + "2034-10-28 00:00:00", + "2034-10-29 00:00:00", + "2034-11-04 00:00:00", + "2034-11-05 00:00:00", + "2034-11-11 00:00:00", + "2034-11-12 00:00:00", + "2034-11-18 00:00:00", + "2034-11-19 00:00:00", + "2034-11-25 00:00:00", + "2034-11-26 00:00:00", + "2034-12-02 00:00:00", + "2034-12-03 00:00:00", + "2034-12-09 00:00:00", + "2034-12-10 00:00:00", + "2034-12-16 00:00:00", + "2034-12-17 00:00:00", + "2034-12-23 00:00:00", + "2034-12-24 00:00:00", + "2034-12-30 00:00:00", + "2034-12-31 00:00:00", + "2035-01-01 00:00:00", + "2035-01-06 00:00:00", + "2035-01-07 00:00:00", + "2035-01-13 00:00:00", + "2035-01-14 00:00:00", + "2035-01-20 00:00:00", + "2035-01-21 00:00:00", + "2035-01-27 00:00:00", + "2035-01-28 00:00:00", + "2035-02-03 00:00:00", + "2035-02-07 00:00:00", + "2035-02-08 00:00:00", + "2035-02-09 00:00:00", + "2035-02-10 00:00:00", + "2035-02-11 00:00:00", + "2035-02-12 00:00:00", + "2035-02-13 00:00:00", + "2035-02-14 00:00:00", + "2035-02-18 00:00:00", + "2035-02-24 00:00:00", + "2035-02-25 00:00:00", + "2035-03-03 00:00:00", + "2035-03-04 00:00:00", + "2035-03-10 00:00:00", + "2035-03-11 00:00:00", + "2035-03-17 00:00:00", + "2035-03-18 00:00:00", + "2035-03-24 00:00:00", + "2035-03-25 00:00:00", + "2035-03-31 00:00:00", + "2035-04-01 00:00:00", + "2035-04-04 00:00:00", + "2035-04-07 00:00:00", + "2035-04-08 00:00:00", + "2035-04-14 00:00:00", + "2035-04-15 00:00:00", + "2035-04-21 00:00:00", + "2035-04-22 00:00:00", + "2035-04-28 00:00:00", + "2035-04-29 00:00:00", + "2035-04-30 00:00:00", + "2035-05-01 00:00:00", + "2035-05-02 00:00:00", + "2035-05-05 00:00:00", + "2035-05-06 00:00:00", + "2035-05-12 00:00:00", + "2035-05-13 00:00:00", + "2035-05-19 00:00:00", + "2035-05-20 00:00:00", + "2035-05-26 00:00:00", + "2035-05-27 00:00:00", + "2035-06-02 00:00:00", + "2035-06-03 00:00:00", + "2035-06-09 00:00:00", + "2035-06-10 00:00:00", + "2035-06-11 00:00:00", + "2035-06-16 00:00:00", + "2035-06-17 00:00:00", + "2035-06-23 00:00:00", + "2035-06-24 00:00:00", + "2035-06-30 00:00:00", + "2035-07-01 00:00:00", + "2035-07-07 00:00:00", + "2035-07-08 00:00:00", + "2035-07-14 00:00:00", + "2035-07-15 00:00:00", + "2035-07-21 00:00:00", + "2035-07-22 00:00:00", + "2035-07-28 00:00:00", + "2035-07-29 00:00:00", + "2035-08-04 00:00:00", + "2035-08-05 00:00:00", + "2035-08-11 00:00:00", + "2035-08-12 00:00:00", + "2035-08-18 00:00:00", + "2035-08-19 00:00:00", + "2035-08-25 00:00:00", + "2035-08-26 00:00:00", + "2035-09-01 00:00:00", + "2035-09-02 00:00:00", + "2035-09-08 00:00:00", + "2035-09-09 00:00:00", + "2035-09-15 00:00:00", + "2035-09-16 00:00:00", + "2035-09-17 00:00:00", + "2035-09-22 00:00:00", + "2035-09-23 00:00:00", + "2035-09-30 00:00:00", + "2035-10-01 00:00:00", + "2035-10-02 00:00:00", + "2035-10-03 00:00:00", + "2035-10-04 00:00:00", + "2035-10-05 00:00:00", + "2035-10-06 00:00:00", + "2035-10-07 00:00:00", + "2035-10-14 00:00:00", + "2035-10-20 00:00:00", + "2035-10-21 00:00:00", + "2035-10-27 00:00:00", + "2035-10-28 00:00:00", + "2035-11-03 00:00:00", + "2035-11-04 00:00:00", + "2035-11-10 00:00:00", + "2035-11-11 00:00:00", + "2035-11-17 00:00:00", + "2035-11-18 00:00:00", + "2035-11-24 00:00:00", + "2035-11-25 00:00:00", + "2035-12-01 00:00:00", + "2035-12-02 00:00:00", + "2035-12-08 00:00:00", + "2035-12-09 00:00:00", + "2035-12-15 00:00:00", + "2035-12-16 00:00:00", + "2035-12-22 00:00:00", + "2035-12-23 00:00:00", + "2035-12-30 00:00:00", + "2035-12-31 00:00:00", + "2036-01-01 00:00:00", + "2036-01-05 00:00:00", + "2036-01-06 00:00:00", + "2036-01-12 00:00:00", + "2036-01-13 00:00:00", + "2036-01-19 00:00:00", + "2036-01-20 00:00:00", + "2036-01-27 00:00:00", + "2036-01-28 00:00:00", + "2036-01-29 00:00:00", + "2036-01-30 00:00:00", + "2036-01-31 00:00:00", + "2036-02-01 00:00:00", + "2036-02-02 00:00:00", + "2036-02-03 00:00:00", + "2036-02-10 00:00:00", + "2036-02-16 00:00:00", + "2036-02-17 00:00:00", + "2036-02-23 00:00:00", + "2036-02-24 00:00:00", + "2036-03-01 00:00:00", + "2036-03-02 00:00:00", + "2036-03-08 00:00:00", + "2036-03-09 00:00:00", + "2036-03-15 00:00:00", + "2036-03-16 00:00:00", + "2036-03-22 00:00:00", + "2036-03-23 00:00:00", + "2036-03-29 00:00:00", + "2036-03-30 00:00:00", + "2036-04-04 00:00:00", + "2036-04-05 00:00:00", + "2036-04-06 00:00:00", + "2036-04-12 00:00:00", + "2036-04-13 00:00:00", + "2036-04-19 00:00:00", + "2036-04-20 00:00:00", + "2036-04-26 00:00:00", + "2036-05-01 00:00:00", + "2036-05-02 00:00:00", + "2036-05-03 00:00:00", + "2036-05-04 00:00:00", + "2036-05-05 00:00:00", + "2036-05-10 00:00:00", + "2036-05-11 00:00:00", + "2036-05-17 00:00:00", + "2036-05-18 00:00:00", + "2036-05-24 00:00:00", + "2036-05-25 00:00:00", + "2036-05-30 00:00:00", + "2036-05-31 00:00:00", + "2036-06-01 00:00:00", + "2036-06-07 00:00:00", + "2036-06-08 00:00:00", + "2036-06-14 00:00:00", + "2036-06-15 00:00:00", + "2036-06-21 00:00:00", + "2036-06-22 00:00:00", + "2036-06-28 00:00:00", + "2036-06-29 00:00:00", + "2036-07-05 00:00:00", + "2036-07-06 00:00:00", + "2036-07-12 00:00:00", + "2036-07-13 00:00:00", + "2036-07-19 00:00:00", + "2036-07-20 00:00:00", + "2036-07-26 00:00:00", + "2036-07-27 00:00:00", + "2036-08-02 00:00:00", + "2036-08-03 00:00:00", + "2036-08-09 00:00:00", + "2036-08-10 00:00:00", + "2036-08-16 00:00:00", + "2036-08-17 00:00:00", + "2036-08-23 00:00:00", + "2036-08-24 00:00:00", + "2036-08-30 00:00:00", + "2036-08-31 00:00:00", + "2036-09-06 00:00:00", + "2036-09-07 00:00:00", + "2036-09-13 00:00:00", + "2036-09-14 00:00:00", + "2036-09-20 00:00:00", + "2036-09-21 00:00:00", + "2036-09-27 00:00:00", + "2036-10-01 00:00:00", + "2036-10-02 00:00:00", + "2036-10-03 00:00:00", + "2036-10-04 00:00:00", + "2036-10-05 00:00:00", + "2036-10-06 00:00:00", + "2036-10-07 00:00:00", + "2036-10-08 00:00:00", + "2036-10-12 00:00:00", + "2036-10-18 00:00:00", + "2036-10-19 00:00:00", + "2036-10-25 00:00:00", + "2036-10-26 00:00:00", + "2036-11-01 00:00:00", + "2036-11-02 00:00:00", + "2036-11-08 00:00:00", + "2036-11-09 00:00:00", + "2036-11-15 00:00:00", + "2036-11-16 00:00:00", + "2036-11-22 00:00:00", + "2036-11-23 00:00:00", + "2036-11-29 00:00:00", + "2036-11-30 00:00:00", + "2036-12-06 00:00:00", + "2036-12-07 00:00:00", + "2036-12-13 00:00:00", + "2036-12-14 00:00:00", + "2036-12-20 00:00:00", + "2036-12-21 00:00:00", + "2036-12-27 00:00:00", + "2036-12-28 00:00:00", + "2037-01-01 00:00:00", + "2037-01-02 00:00:00", + "2037-01-03 00:00:00", + "2037-01-10 00:00:00", + "2037-01-11 00:00:00", + "2037-01-17 00:00:00", + "2037-01-18 00:00:00", + "2037-01-24 00:00:00", + "2037-01-25 00:00:00", + "2037-01-31 00:00:00", + "2037-02-01 00:00:00", + "2037-02-07 00:00:00", + "2037-02-14 00:00:00", + "2037-02-15 00:00:00", + "2037-02-16 00:00:00", + "2037-02-17 00:00:00", + "2037-02-18 00:00:00", + "2037-02-19 00:00:00", + "2037-02-20 00:00:00", + "2037-02-21 00:00:00", + "2037-02-28 00:00:00", + "2037-03-01 00:00:00", + "2037-03-07 00:00:00", + "2037-03-08 00:00:00", + "2037-03-14 00:00:00", + "2037-03-15 00:00:00", + "2037-03-21 00:00:00", + "2037-03-22 00:00:00", + "2037-03-28 00:00:00", + "2037-03-29 00:00:00", + "2037-04-04 00:00:00", + "2037-04-05 00:00:00", + "2037-04-06 00:00:00", + "2037-04-11 00:00:00", + "2037-04-12 00:00:00", + "2037-04-18 00:00:00", + "2037-04-19 00:00:00", + "2037-04-25 00:00:00", + "2037-04-26 00:00:00", + "2037-05-01 00:00:00", + "2037-05-02 00:00:00", + "2037-05-03 00:00:00", + "2037-05-04 00:00:00", + "2037-05-05 00:00:00", + "2037-05-10 00:00:00", + "2037-05-16 00:00:00", + "2037-05-17 00:00:00", + "2037-05-23 00:00:00", + "2037-05-24 00:00:00", + "2037-05-30 00:00:00", + "2037-05-31 00:00:00", + "2037-06-06 00:00:00", + "2037-06-07 00:00:00", + "2037-06-13 00:00:00", + "2037-06-14 00:00:00", + "2037-06-18 00:00:00", + "2037-06-19 00:00:00", + "2037-06-20 00:00:00", + "2037-06-21 00:00:00", + "2037-06-27 00:00:00", + "2037-07-04 00:00:00", + "2037-07-05 00:00:00", + "2037-07-11 00:00:00", + "2037-07-12 00:00:00", + "2037-07-18 00:00:00", + "2037-07-19 00:00:00", + "2037-07-25 00:00:00", + "2037-07-26 00:00:00", + "2037-08-01 00:00:00", + "2037-08-02 00:00:00", + "2037-08-08 00:00:00", + "2037-08-09 00:00:00", + "2037-08-15 00:00:00", + "2037-08-16 00:00:00", + "2037-08-22 00:00:00", + "2037-08-23 00:00:00", + "2037-08-29 00:00:00", + "2037-08-30 00:00:00", + "2037-09-05 00:00:00", + "2037-09-06 00:00:00", + "2037-09-12 00:00:00", + "2037-09-13 00:00:00", + "2037-09-19 00:00:00", + "2037-09-20 00:00:00", + "2037-09-24 00:00:00", + "2037-09-25 00:00:00", + "2037-09-26 00:00:00", + "2037-10-01 00:00:00", + "2037-10-02 00:00:00", + "2037-10-03 00:00:00", + "2037-10-04 00:00:00", + "2037-10-05 00:00:00", + "2037-10-06 00:00:00", + "2037-10-07 00:00:00", + "2037-10-11 00:00:00", + "2037-10-17 00:00:00", + "2037-10-18 00:00:00", + "2037-10-24 00:00:00", + "2037-10-25 00:00:00", + "2037-10-31 00:00:00", + "2037-11-01 00:00:00", + "2037-11-07 00:00:00", + "2037-11-08 00:00:00", + "2037-11-14 00:00:00", + "2037-11-15 00:00:00", + "2037-11-21 00:00:00", + "2037-11-22 00:00:00", + "2037-11-28 00:00:00", + "2037-11-29 00:00:00", + "2037-12-05 00:00:00", + "2037-12-06 00:00:00", + "2037-12-12 00:00:00", + "2037-12-13 00:00:00", + "2037-12-19 00:00:00", + "2037-12-20 00:00:00", + "2037-12-26 00:00:00", + "2037-12-27 00:00:00", + "2038-01-01 00:00:00", + "2038-01-02 00:00:00", + "2038-01-03 00:00:00", + "2038-01-09 00:00:00", + "2038-01-10 00:00:00", + "2038-01-16 00:00:00", + "2038-01-17 00:00:00", + "2038-01-23 00:00:00", + "2038-01-24 00:00:00", + "2038-01-30 00:00:00", + "2038-02-03 00:00:00", + "2038-02-04 00:00:00", + "2038-02-05 00:00:00", + "2038-02-06 00:00:00", + "2038-02-07 00:00:00", + "2038-02-08 00:00:00", + "2038-02-09 00:00:00", + "2038-02-10 00:00:00", + "2038-02-14 00:00:00", + "2038-02-20 00:00:00", + "2038-02-21 00:00:00", + "2038-02-27 00:00:00", + "2038-02-28 00:00:00", + "2038-03-06 00:00:00", + "2038-03-07 00:00:00", + "2038-03-13 00:00:00", + "2038-03-14 00:00:00", + "2038-03-20 00:00:00", + "2038-03-21 00:00:00", + "2038-03-27 00:00:00", + "2038-03-28 00:00:00", + "2038-04-03 00:00:00", + "2038-04-04 00:00:00", + "2038-04-05 00:00:00", + "2038-04-10 00:00:00", + "2038-04-11 00:00:00", + "2038-04-17 00:00:00", + "2038-04-18 00:00:00", + "2038-04-24 00:00:00", + "2038-04-25 00:00:00", + "2038-05-01 00:00:00", + "2038-05-02 00:00:00", + "2038-05-03 00:00:00", + "2038-05-04 00:00:00", + "2038-05-05 00:00:00", + "2038-05-08 00:00:00", + "2038-05-15 00:00:00", + "2038-05-16 00:00:00", + "2038-05-22 00:00:00", + "2038-05-23 00:00:00", + "2038-05-29 00:00:00", + "2038-05-30 00:00:00", + "2038-06-05 00:00:00", + "2038-06-06 00:00:00", + "2038-06-07 00:00:00", + "2038-06-12 00:00:00", + "2038-06-13 00:00:00", + "2038-06-19 00:00:00", + "2038-06-20 00:00:00", + "2038-06-26 00:00:00", + "2038-06-27 00:00:00", + "2038-07-03 00:00:00", + "2038-07-04 00:00:00", + "2038-07-10 00:00:00", + "2038-07-11 00:00:00", + "2038-07-17 00:00:00", + "2038-07-18 00:00:00", + "2038-07-24 00:00:00", + "2038-07-25 00:00:00", + "2038-07-31 00:00:00", + "2038-08-01 00:00:00", + "2038-08-07 00:00:00", + "2038-08-08 00:00:00", + "2038-08-14 00:00:00", + "2038-08-15 00:00:00", + "2038-08-21 00:00:00", + "2038-08-22 00:00:00", + "2038-08-28 00:00:00", + "2038-08-29 00:00:00", + "2038-09-04 00:00:00", + "2038-09-05 00:00:00", + "2038-09-11 00:00:00", + "2038-09-12 00:00:00", + "2038-09-13 00:00:00", + "2038-09-18 00:00:00", + "2038-09-19 00:00:00", + "2038-09-25 00:00:00", + "2038-10-01 00:00:00", + "2038-10-02 00:00:00", + "2038-10-03 00:00:00", + "2038-10-04 00:00:00", + "2038-10-05 00:00:00", + "2038-10-06 00:00:00", + "2038-10-07 00:00:00", + "2038-10-10 00:00:00", + "2038-10-16 00:00:00", + "2038-10-17 00:00:00", + "2038-10-23 00:00:00", + "2038-10-24 00:00:00", + "2038-10-30 00:00:00", + "2038-10-31 00:00:00", + "2038-11-06 00:00:00", + "2038-11-07 00:00:00", + "2038-11-13 00:00:00", + "2038-11-14 00:00:00", + "2038-11-20 00:00:00", + "2038-11-21 00:00:00", + "2038-11-27 00:00:00", + "2038-11-28 00:00:00", + "2038-12-04 00:00:00", + "2038-12-05 00:00:00", + "2038-12-11 00:00:00", + "2038-12-12 00:00:00", + "2038-12-18 00:00:00", + "2038-12-19 00:00:00", + "2038-12-25 00:00:00", + "2038-12-26 00:00:00", + "2039-01-01 00:00:00", + "2039-01-02 00:00:00", + "2039-01-03 00:00:00", + "2039-01-08 00:00:00", + "2039-01-09 00:00:00", + "2039-01-15 00:00:00", + "2039-01-16 00:00:00", + "2039-01-23 00:00:00", + "2039-01-24 00:00:00", + "2039-01-25 00:00:00", + "2039-01-26 00:00:00", + "2039-01-27 00:00:00", + "2039-01-28 00:00:00", + "2039-01-29 00:00:00", + "2039-01-30 00:00:00", + "2039-02-06 00:00:00", + "2039-02-12 00:00:00", + "2039-02-13 00:00:00", + "2039-02-19 00:00:00", + "2039-02-20 00:00:00", + "2039-02-26 00:00:00", + "2039-02-27 00:00:00", + "2039-03-05 00:00:00", + "2039-03-06 00:00:00", + "2039-03-12 00:00:00", + "2039-03-13 00:00:00", + "2039-03-19 00:00:00", + "2039-03-20 00:00:00", + "2039-03-26 00:00:00", + "2039-03-27 00:00:00", + "2039-04-02 00:00:00", + "2039-04-03 00:00:00", + "2039-04-04 00:00:00", + "2039-04-09 00:00:00", + "2039-04-10 00:00:00", + "2039-04-16 00:00:00", + "2039-04-17 00:00:00", + "2039-04-23 00:00:00", + "2039-04-24 00:00:00", + "2039-04-30 00:00:00", + "2039-05-01 00:00:00", + "2039-05-02 00:00:00", + "2039-05-03 00:00:00", + "2039-05-04 00:00:00", + "2039-05-07 00:00:00", + "2039-05-14 00:00:00", + "2039-05-15 00:00:00", + "2039-05-21 00:00:00", + "2039-05-22 00:00:00", + "2039-05-27 00:00:00", + "2039-05-28 00:00:00", + "2039-05-29 00:00:00", + "2039-06-04 00:00:00", + "2039-06-05 00:00:00", + "2039-06-11 00:00:00", + "2039-06-12 00:00:00", + "2039-06-18 00:00:00", + "2039-06-19 00:00:00", + "2039-06-25 00:00:00", + "2039-06-26 00:00:00", + "2039-07-02 00:00:00", + "2039-07-03 00:00:00", + "2039-07-09 00:00:00", + "2039-07-10 00:00:00", + "2039-07-16 00:00:00", + "2039-07-17 00:00:00", + "2039-07-23 00:00:00", + "2039-07-24 00:00:00", + "2039-07-30 00:00:00", + "2039-07-31 00:00:00", + "2039-08-06 00:00:00", + "2039-08-07 00:00:00", + "2039-08-13 00:00:00", + "2039-08-14 00:00:00", + "2039-08-20 00:00:00", + "2039-08-21 00:00:00", + "2039-08-27 00:00:00", + "2039-08-28 00:00:00", + "2039-09-03 00:00:00", + "2039-09-04 00:00:00", + "2039-09-10 00:00:00", + "2039-09-11 00:00:00", + "2039-09-17 00:00:00", + "2039-09-18 00:00:00", + "2039-09-24 00:00:00", + "2039-10-01 00:00:00", + "2039-10-02 00:00:00", + "2039-10-03 00:00:00", + "2039-10-04 00:00:00", + "2039-10-05 00:00:00", + "2039-10-06 00:00:00", + "2039-10-07 00:00:00", + "2039-10-08 00:00:00", + "2039-10-15 00:00:00", + "2039-10-16 00:00:00", + "2039-10-22 00:00:00", + "2039-10-23 00:00:00", + "2039-10-29 00:00:00", + "2039-10-30 00:00:00", + "2039-11-05 00:00:00", + "2039-11-06 00:00:00", + "2039-11-12 00:00:00", + "2039-11-13 00:00:00", + "2039-11-19 00:00:00", + "2039-11-20 00:00:00", + "2039-11-26 00:00:00", + "2039-11-27 00:00:00", + "2039-12-03 00:00:00", + "2039-12-04 00:00:00", + "2039-12-10 00:00:00", + "2039-12-11 00:00:00", + "2039-12-17 00:00:00", + "2039-12-18 00:00:00", + "2039-12-24 00:00:00", + "2039-12-25 00:00:00", + "2039-12-31 00:00:00", + "2040-01-01 00:00:00", + "2040-01-02 00:00:00", + "2040-01-07 00:00:00", + "2040-01-08 00:00:00", + "2040-01-14 00:00:00", + "2040-01-15 00:00:00", + "2040-01-21 00:00:00", + "2040-01-22 00:00:00", + "2040-01-28 00:00:00", + "2040-01-29 00:00:00", + "2040-02-04 00:00:00", + "2040-02-11 00:00:00", + "2040-02-12 00:00:00", + "2040-02-13 00:00:00", + "2040-02-14 00:00:00", + "2040-02-15 00:00:00", + "2040-02-16 00:00:00", + "2040-02-17 00:00:00", + "2040-02-18 00:00:00", + "2040-02-25 00:00:00", + "2040-02-26 00:00:00", + "2040-03-03 00:00:00", + "2040-03-04 00:00:00", + "2040-03-10 00:00:00", + "2040-03-11 00:00:00", + "2040-03-17 00:00:00", + "2040-03-18 00:00:00", + "2040-03-24 00:00:00", + "2040-03-25 00:00:00", + "2040-03-31 00:00:00", + "2040-04-01 00:00:00", + "2040-04-04 00:00:00", + "2040-04-07 00:00:00", + "2040-04-08 00:00:00", + "2040-04-14 00:00:00", + "2040-04-15 00:00:00", + "2040-04-21 00:00:00", + "2040-04-22 00:00:00", + "2040-04-28 00:00:00", + "2040-04-29 00:00:00", + "2040-04-30 00:00:00", + "2040-05-01 00:00:00", + "2040-05-02 00:00:00", + "2040-05-05 00:00:00", + "2040-05-06 00:00:00", + "2040-05-12 00:00:00", + "2040-05-13 00:00:00", + "2040-05-19 00:00:00", + "2040-05-20 00:00:00", + "2040-05-26 00:00:00", + "2040-05-27 00:00:00", + "2040-06-02 00:00:00", + "2040-06-03 00:00:00", + "2040-06-09 00:00:00", + "2040-06-10 00:00:00", + "2040-06-14 00:00:00", + "2040-06-15 00:00:00", + "2040-06-16 00:00:00", + "2040-06-17 00:00:00", + "2040-06-23 00:00:00", + "2040-06-30 00:00:00", + "2040-07-01 00:00:00", + "2040-07-07 00:00:00", + "2040-07-08 00:00:00", + "2040-07-14 00:00:00", + "2040-07-15 00:00:00", + "2040-07-21 00:00:00", + "2040-07-22 00:00:00", + "2040-07-28 00:00:00", + "2040-07-29 00:00:00", + "2040-08-04 00:00:00", + "2040-08-05 00:00:00", + "2040-08-11 00:00:00", + "2040-08-12 00:00:00", + "2040-08-18 00:00:00", + "2040-08-19 00:00:00", + "2040-08-25 00:00:00", + "2040-08-26 00:00:00", + "2040-09-01 00:00:00", + "2040-09-02 00:00:00", + "2040-09-08 00:00:00", + "2040-09-09 00:00:00", + "2040-09-15 00:00:00", + "2040-09-16 00:00:00", + "2040-09-20 00:00:00", + "2040-09-21 00:00:00", + "2040-09-22 00:00:00", + "2040-09-23 00:00:00", + "2040-10-01 00:00:00", + "2040-10-02 00:00:00", + "2040-10-03 00:00:00", + "2040-10-04 00:00:00", + "2040-10-05 00:00:00", + "2040-10-06 00:00:00", + "2040-10-07 00:00:00", + "2040-10-14 00:00:00", + "2040-10-20 00:00:00", + "2040-10-21 00:00:00", + "2040-10-27 00:00:00", + "2040-10-28 00:00:00", + "2040-11-03 00:00:00", + "2040-11-04 00:00:00", + "2040-11-10 00:00:00", + "2040-11-11 00:00:00", + "2040-11-17 00:00:00", + "2040-11-18 00:00:00", + "2040-11-24 00:00:00", + "2040-11-25 00:00:00", + "2040-12-01 00:00:00", + "2040-12-02 00:00:00", + "2040-12-08 00:00:00", + "2040-12-09 00:00:00", + "2040-12-15 00:00:00", + "2040-12-16 00:00:00", + "2040-12-22 00:00:00", + "2040-12-23 00:00:00", + "2040-12-30 00:00:00", + "2040-12-31 00:00:00", + "2041-01-01 00:00:00", + "2041-01-05 00:00:00", + "2041-01-06 00:00:00", + "2041-01-12 00:00:00", + "2041-01-13 00:00:00", + "2041-01-19 00:00:00", + "2041-01-20 00:00:00", + "2041-01-26 00:00:00", + "2041-01-31 00:00:00", + "2041-02-01 00:00:00", + "2041-02-02 00:00:00", + "2041-02-03 00:00:00", + "2041-02-04 00:00:00", + "2041-02-05 00:00:00", + "2041-02-06 00:00:00", + "2041-02-07 00:00:00", + "2041-02-10 00:00:00", + "2041-02-16 00:00:00", + "2041-02-17 00:00:00", + "2041-02-23 00:00:00", + "2041-02-24 00:00:00", + "2041-03-02 00:00:00", + "2041-03-03 00:00:00", + "2041-03-09 00:00:00", + "2041-03-10 00:00:00", + "2041-03-16 00:00:00", + "2041-03-17 00:00:00", + "2041-03-23 00:00:00", + "2041-03-24 00:00:00", + "2041-03-30 00:00:00", + "2041-03-31 00:00:00", + "2041-04-04 00:00:00", + "2041-04-05 00:00:00", + "2041-04-06 00:00:00", + "2041-04-07 00:00:00", + "2041-04-13 00:00:00", + "2041-04-20 00:00:00", + "2041-04-21 00:00:00", + "2041-04-27 00:00:00", + "2041-04-28 00:00:00", + "2041-05-01 00:00:00", + "2041-05-02 00:00:00", + "2041-05-04 00:00:00", + "2041-05-05 00:00:00", + "2041-05-11 00:00:00", + "2041-05-12 00:00:00", + "2041-05-18 00:00:00", + "2041-05-19 00:00:00", + "2041-05-25 00:00:00", + "2041-05-26 00:00:00", + "2041-06-01 00:00:00", + "2041-06-02 00:00:00", + "2041-06-03 00:00:00", + "2041-06-08 00:00:00", + "2041-06-09 00:00:00", + "2041-06-15 00:00:00", + "2041-06-16 00:00:00", + "2041-06-22 00:00:00", + "2041-06-23 00:00:00", + "2041-06-29 00:00:00", + "2041-06-30 00:00:00", + "2041-07-06 00:00:00", + "2041-07-07 00:00:00", + "2041-07-13 00:00:00", + "2041-07-14 00:00:00", + "2041-07-20 00:00:00", + "2041-07-21 00:00:00", + "2041-07-27 00:00:00", + "2041-07-28 00:00:00", + "2041-08-03 00:00:00", + "2041-08-04 00:00:00", + "2041-08-10 00:00:00", + "2041-08-11 00:00:00", + "2041-08-17 00:00:00", + "2041-08-18 00:00:00", + "2041-08-24 00:00:00", + "2041-08-25 00:00:00", + "2041-08-31 00:00:00", + "2041-09-07 00:00:00", + "2041-09-08 00:00:00", + "2041-09-09 00:00:00", + "2041-09-10 00:00:00", + "2041-09-14 00:00:00", + "2041-09-15 00:00:00", + "2041-09-21 00:00:00", + "2041-09-22 00:00:00", + "2041-09-28 00:00:00", + "2041-10-01 00:00:00", + "2041-10-02 00:00:00", + "2041-10-03 00:00:00", + "2041-10-04 00:00:00", + "2041-10-05 00:00:00", + "2041-10-06 00:00:00", + "2041-10-07 00:00:00", + "2041-10-13 00:00:00", + "2041-10-19 00:00:00", + "2041-10-20 00:00:00", + "2041-10-26 00:00:00", + "2041-10-27 00:00:00", + "2041-11-02 00:00:00", + "2041-11-03 00:00:00", + "2041-11-09 00:00:00", + "2041-11-10 00:00:00", + "2041-11-16 00:00:00", + "2041-11-17 00:00:00", + "2041-11-23 00:00:00", + "2041-11-24 00:00:00", + "2041-11-30 00:00:00", + "2041-12-01 00:00:00", + "2041-12-07 00:00:00", + "2041-12-08 00:00:00", + "2041-12-14 00:00:00", + "2041-12-15 00:00:00", + "2041-12-21 00:00:00", + "2041-12-22 00:00:00", + "2041-12-28 00:00:00", + "2041-12-29 00:00:00", + "2042-01-01 00:00:00", + "2042-01-04 00:00:00", + "2042-01-05 00:00:00", + "2042-01-11 00:00:00", + "2042-01-12 00:00:00", + "2042-01-18 00:00:00", + "2042-01-21 00:00:00", + "2042-01-22 00:00:00", + "2042-01-23 00:00:00", + "2042-01-24 00:00:00", + "2042-01-25 00:00:00", + "2042-01-26 00:00:00", + "2042-01-27 00:00:00", + "2042-01-28 00:00:00", + "2042-02-02 00:00:00", + "2042-02-08 00:00:00", + "2042-02-09 00:00:00", + "2042-02-15 00:00:00", + "2042-02-16 00:00:00", + "2042-02-22 00:00:00", + "2042-02-23 00:00:00", + "2042-03-01 00:00:00", + "2042-03-02 00:00:00", + "2042-03-08 00:00:00", + "2042-03-09 00:00:00", + "2042-03-15 00:00:00", + "2042-03-16 00:00:00", + "2042-03-22 00:00:00", + "2042-03-23 00:00:00", + "2042-03-29 00:00:00", + "2042-03-30 00:00:00", + "2042-04-04 00:00:00", + "2042-04-05 00:00:00", + "2042-04-06 00:00:00", + "2042-04-12 00:00:00", + "2042-04-13 00:00:00", + "2042-04-19 00:00:00", + "2042-04-20 00:00:00", + "2042-04-26 00:00:00", + "2042-05-01 00:00:00", + "2042-05-02 00:00:00", + "2042-05-03 00:00:00", + "2042-05-04 00:00:00", + "2042-05-05 00:00:00", + "2042-05-10 00:00:00", + "2042-05-11 00:00:00", + "2042-05-17 00:00:00", + "2042-05-18 00:00:00", + "2042-05-24 00:00:00", + "2042-05-25 00:00:00", + "2042-05-31 00:00:00", + "2042-06-01 00:00:00", + "2042-06-07 00:00:00", + "2042-06-08 00:00:00", + "2042-06-14 00:00:00", + "2042-06-15 00:00:00", + "2042-06-21 00:00:00", + "2042-06-22 00:00:00", + "2042-06-23 00:00:00", + "2042-06-28 00:00:00", + "2042-06-29 00:00:00", + "2042-07-05 00:00:00", + "2042-07-06 00:00:00", + "2042-07-12 00:00:00", + "2042-07-13 00:00:00", + "2042-07-19 00:00:00", + "2042-07-20 00:00:00", + "2042-07-26 00:00:00", + "2042-07-27 00:00:00", + "2042-08-02 00:00:00", + "2042-08-03 00:00:00", + "2042-08-09 00:00:00", + "2042-08-10 00:00:00", + "2042-08-16 00:00:00", + "2042-08-17 00:00:00", + "2042-08-23 00:00:00", + "2042-08-24 00:00:00", + "2042-08-30 00:00:00", + "2042-08-31 00:00:00", + "2042-09-06 00:00:00", + "2042-09-07 00:00:00", + "2042-09-13 00:00:00", + "2042-09-14 00:00:00", + "2042-09-20 00:00:00", + "2042-09-27 00:00:00", + "2042-09-28 00:00:00", + "2042-09-29 00:00:00", + "2042-10-01 00:00:00", + "2042-10-02 00:00:00", + "2042-10-03 00:00:00", + "2042-10-04 00:00:00", + "2042-10-05 00:00:00", + "2042-10-06 00:00:00", + "2042-10-07 00:00:00", + "2042-10-12 00:00:00", + "2042-10-18 00:00:00", + "2042-10-19 00:00:00", + "2042-10-25 00:00:00", + "2042-10-26 00:00:00", + "2042-11-01 00:00:00", + "2042-11-02 00:00:00", + "2042-11-08 00:00:00", + "2042-11-09 00:00:00", + "2042-11-15 00:00:00", + "2042-11-16 00:00:00", + "2042-11-22 00:00:00", + "2042-11-23 00:00:00", + "2042-11-29 00:00:00", + "2042-11-30 00:00:00", + "2042-12-06 00:00:00", + "2042-12-07 00:00:00", + "2042-12-13 00:00:00", + "2042-12-14 00:00:00", + "2042-12-20 00:00:00", + "2042-12-21 00:00:00", + "2042-12-27 00:00:00", + "2042-12-28 00:00:00", + "2043-01-01 00:00:00", + "2043-01-02 00:00:00", + "2043-01-03 00:00:00", + "2043-01-10 00:00:00", + "2043-01-11 00:00:00", + "2043-01-17 00:00:00", + "2043-01-18 00:00:00", + "2043-01-24 00:00:00", + "2043-01-25 00:00:00", + "2043-01-31 00:00:00", + "2043-02-01 00:00:00", + "2043-02-08 00:00:00", + "2043-02-09 00:00:00", + "2043-02-10 00:00:00", + "2043-02-11 00:00:00", + "2043-02-12 00:00:00", + "2043-02-13 00:00:00", + "2043-02-14 00:00:00", + "2043-02-15 00:00:00", + "2043-02-16 00:00:00", + "2043-02-22 00:00:00", + "2043-02-28 00:00:00", + "2043-03-01 00:00:00", + "2043-03-07 00:00:00", + "2043-03-08 00:00:00", + "2043-03-14 00:00:00", + "2043-03-15 00:00:00", + "2043-03-21 00:00:00", + "2043-03-22 00:00:00", + "2043-03-28 00:00:00", + "2043-03-29 00:00:00", + "2043-04-04 00:00:00", + "2043-04-05 00:00:00", + "2043-04-06 00:00:00", + "2043-04-11 00:00:00", + "2043-04-12 00:00:00", + "2043-04-18 00:00:00", + "2043-04-19 00:00:00", + "2043-04-25 00:00:00", + "2043-04-26 00:00:00", + "2043-05-01 00:00:00", + "2043-05-02 00:00:00", + "2043-05-03 00:00:00", + "2043-05-04 00:00:00", + "2043-05-05 00:00:00", + "2043-05-10 00:00:00", + "2043-05-16 00:00:00", + "2043-05-17 00:00:00", + "2043-05-23 00:00:00", + "2043-05-24 00:00:00", + "2043-05-30 00:00:00", + "2043-05-31 00:00:00", + "2043-06-06 00:00:00", + "2043-06-07 00:00:00", + "2043-06-11 00:00:00", + "2043-06-12 00:00:00", + "2043-06-13 00:00:00", + "2043-06-14 00:00:00", + "2043-06-20 00:00:00", + "2043-06-27 00:00:00", + "2043-06-28 00:00:00", + "2043-07-04 00:00:00", + "2043-07-05 00:00:00", + "2043-07-11 00:00:00", + "2043-07-12 00:00:00", + "2043-07-18 00:00:00", + "2043-07-19 00:00:00", + "2043-07-25 00:00:00", + "2043-07-26 00:00:00", + "2043-08-01 00:00:00", + "2043-08-02 00:00:00", + "2043-08-08 00:00:00", + "2043-08-09 00:00:00", + "2043-08-15 00:00:00", + "2043-08-16 00:00:00", + "2043-08-22 00:00:00", + "2043-08-23 00:00:00", + "2043-08-29 00:00:00", + "2043-08-30 00:00:00", + "2043-09-05 00:00:00", + "2043-09-06 00:00:00", + "2043-09-12 00:00:00", + "2043-09-13 00:00:00", + "2043-09-17 00:00:00", + "2043-09-18 00:00:00", + "2043-09-19 00:00:00", + "2043-09-20 00:00:00", + "2043-09-26 00:00:00", + "2043-10-01 00:00:00", + "2043-10-02 00:00:00", + "2043-10-03 00:00:00", + "2043-10-04 00:00:00", + "2043-10-05 00:00:00", + "2043-10-06 00:00:00", + "2043-10-07 00:00:00", + "2043-10-11 00:00:00", + "2043-10-17 00:00:00", + "2043-10-18 00:00:00", + "2043-10-24 00:00:00", + "2043-10-25 00:00:00", + "2043-10-31 00:00:00", + "2043-11-01 00:00:00", + "2043-11-07 00:00:00", + "2043-11-08 00:00:00", + "2043-11-14 00:00:00", + "2043-11-15 00:00:00", + "2043-11-21 00:00:00", + "2043-11-22 00:00:00", + "2043-11-28 00:00:00", + "2043-11-29 00:00:00", + "2043-12-05 00:00:00", + "2043-12-06 00:00:00", + "2043-12-12 00:00:00", + "2043-12-13 00:00:00", + "2043-12-19 00:00:00", + "2043-12-20 00:00:00", + "2043-12-26 00:00:00", + "2043-12-27 00:00:00", + "2044-01-01 00:00:00", + "2044-01-02 00:00:00", + "2044-01-03 00:00:00", + "2044-01-09 00:00:00", + "2044-01-10 00:00:00", + "2044-01-16 00:00:00", + "2044-01-17 00:00:00", + "2044-01-23 00:00:00", + "2044-01-29 00:00:00", + "2044-01-30 00:00:00", + "2044-01-31 00:00:00", + "2044-02-01 00:00:00", + "2044-02-02 00:00:00", + "2044-02-03 00:00:00", + "2044-02-04 00:00:00", + "2044-02-05 00:00:00", + "2044-02-07 00:00:00", + "2044-02-13 00:00:00", + "2044-02-14 00:00:00", + "2044-02-20 00:00:00", + "2044-02-21 00:00:00", + "2044-02-27 00:00:00", + "2044-02-28 00:00:00", + "2044-03-05 00:00:00", + "2044-03-06 00:00:00", + "2044-03-12 00:00:00", + "2044-03-13 00:00:00", + "2044-03-19 00:00:00", + "2044-03-20 00:00:00", + "2044-03-26 00:00:00", + "2044-03-27 00:00:00", + "2044-04-02 00:00:00", + "2044-04-03 00:00:00", + "2044-04-04 00:00:00", + "2044-04-09 00:00:00", + "2044-04-10 00:00:00", + "2044-04-16 00:00:00", + "2044-04-17 00:00:00", + "2044-04-23 00:00:00", + "2044-04-24 00:00:00", + "2044-04-30 00:00:00", + "2044-05-01 00:00:00", + "2044-05-02 00:00:00", + "2044-05-03 00:00:00", + "2044-05-04 00:00:00", + "2044-05-07 00:00:00", + "2044-05-14 00:00:00", + "2044-05-15 00:00:00", + "2044-05-21 00:00:00", + "2044-05-28 00:00:00", + "2044-05-29 00:00:00", + "2044-05-30 00:00:00", + "2044-05-31 00:00:00", + "2044-06-04 00:00:00", + "2044-06-05 00:00:00", + "2044-06-11 00:00:00", + "2044-06-12 00:00:00", + "2044-06-18 00:00:00", + "2044-06-19 00:00:00", + "2044-06-25 00:00:00", + "2044-06-26 00:00:00", + "2044-07-02 00:00:00", + "2044-07-03 00:00:00", + "2044-07-09 00:00:00", + "2044-07-10 00:00:00", + "2044-07-16 00:00:00", + "2044-07-17 00:00:00", + "2044-07-23 00:00:00", + "2044-07-24 00:00:00", + "2044-07-30 00:00:00", + "2044-07-31 00:00:00", + "2044-08-06 00:00:00", + "2044-08-07 00:00:00", + "2044-08-13 00:00:00", + "2044-08-14 00:00:00", + "2044-08-20 00:00:00", + "2044-08-21 00:00:00", + "2044-08-27 00:00:00", + "2044-08-28 00:00:00", + "2044-09-03 00:00:00", + "2044-09-04 00:00:00", + "2044-09-10 00:00:00", + "2044-09-11 00:00:00", + "2044-09-17 00:00:00", + "2044-09-18 00:00:00", + "2044-09-24 00:00:00", + "2044-10-01 00:00:00", + "2044-10-02 00:00:00", + "2044-10-03 00:00:00", + "2044-10-04 00:00:00", + "2044-10-05 00:00:00", + "2044-10-06 00:00:00", + "2044-10-07 00:00:00", + "2044-10-08 00:00:00", + "2044-10-15 00:00:00", + "2044-10-16 00:00:00", + "2044-10-22 00:00:00", + "2044-10-23 00:00:00", + "2044-10-29 00:00:00", + "2044-10-30 00:00:00", + "2044-11-05 00:00:00", + "2044-11-06 00:00:00", + "2044-11-12 00:00:00", + "2044-11-13 00:00:00", + "2044-11-19 00:00:00", + "2044-11-20 00:00:00", + "2044-11-26 00:00:00", + "2044-11-27 00:00:00", + "2044-12-03 00:00:00", + "2044-12-04 00:00:00", + "2044-12-10 00:00:00", + "2044-12-11 00:00:00", + "2044-12-17 00:00:00", + "2044-12-18 00:00:00", + "2044-12-24 00:00:00", + "2044-12-25 00:00:00", + "2044-12-31 00:00:00", + "2045-01-01 00:00:00", + "2045-01-02 00:00:00", + "2045-01-07 00:00:00", + "2045-01-08 00:00:00", + "2045-01-14 00:00:00", + "2045-01-15 00:00:00", + "2045-01-21 00:00:00", + "2045-01-22 00:00:00", + "2045-01-28 00:00:00", + "2045-01-29 00:00:00", + "2045-02-04 00:00:00", + "2045-02-05 00:00:00", + "2045-02-11 00:00:00", + "2045-02-16 00:00:00", + "2045-02-17 00:00:00", + "2045-02-18 00:00:00", + "2045-02-19 00:00:00", + "2045-02-20 00:00:00", + "2045-02-21 00:00:00", + "2045-02-22 00:00:00", + "2045-02-23 00:00:00", + "2045-02-26 00:00:00", + "2045-03-04 00:00:00", + "2045-03-05 00:00:00", + "2045-03-11 00:00:00", + "2045-03-12 00:00:00", + "2045-03-18 00:00:00", + "2045-03-19 00:00:00", + "2045-03-25 00:00:00", + "2045-04-01 00:00:00", + "2045-04-02 00:00:00", + "2045-04-03 00:00:00", + "2045-04-04 00:00:00", + "2045-04-08 00:00:00", + "2045-04-09 00:00:00", + "2045-04-15 00:00:00", + "2045-04-16 00:00:00", + "2045-04-22 00:00:00", + "2045-04-23 00:00:00", + "2045-04-29 00:00:00", + "2045-04-30 00:00:00", + "2045-05-01 00:00:00", + "2045-05-02 00:00:00", + "2045-05-03 00:00:00", + "2045-05-06 00:00:00", + "2045-05-13 00:00:00", + "2045-05-14 00:00:00", + "2045-05-20 00:00:00", + "2045-05-21 00:00:00", + "2045-05-27 00:00:00", + "2045-05-28 00:00:00", + "2045-06-03 00:00:00", + "2045-06-04 00:00:00", + "2045-06-10 00:00:00", + "2045-06-11 00:00:00", + "2045-06-17 00:00:00", + "2045-06-18 00:00:00", + "2045-06-19 00:00:00", + "2045-06-24 00:00:00", + "2045-06-25 00:00:00", + "2045-07-01 00:00:00", + "2045-07-02 00:00:00", + "2045-07-08 00:00:00", + "2045-07-09 00:00:00", + "2045-07-15 00:00:00", + "2045-07-16 00:00:00", + "2045-07-22 00:00:00", + "2045-07-23 00:00:00", + "2045-07-29 00:00:00", + "2045-07-30 00:00:00", + "2045-08-05 00:00:00", + "2045-08-06 00:00:00", + "2045-08-12 00:00:00", + "2045-08-13 00:00:00", + "2045-08-19 00:00:00", + "2045-08-20 00:00:00", + "2045-08-26 00:00:00", + "2045-08-27 00:00:00", + "2045-09-02 00:00:00", + "2045-09-03 00:00:00", + "2045-09-09 00:00:00", + "2045-09-10 00:00:00", + "2045-09-16 00:00:00", + "2045-09-23 00:00:00", + "2045-09-24 00:00:00", + "2045-09-25 00:00:00", + "2045-09-30 00:00:00", + "2045-10-01 00:00:00", + "2045-10-02 00:00:00", + "2045-10-03 00:00:00", + "2045-10-04 00:00:00", + "2045-10-05 00:00:00", + "2045-10-06 00:00:00", + "2045-10-07 00:00:00", + "2045-10-14 00:00:00", + "2045-10-15 00:00:00", + "2045-10-21 00:00:00", + "2045-10-22 00:00:00", + "2045-10-28 00:00:00", + "2045-10-29 00:00:00", + "2045-11-04 00:00:00", + "2045-11-05 00:00:00", + "2045-11-11 00:00:00", + "2045-11-12 00:00:00", + "2045-11-18 00:00:00", + "2045-11-19 00:00:00", + "2045-11-25 00:00:00", + "2045-11-26 00:00:00", + "2045-12-02 00:00:00", + "2045-12-03 00:00:00", + "2045-12-09 00:00:00", + "2045-12-10 00:00:00", + "2045-12-16 00:00:00", + "2045-12-17 00:00:00", + "2045-12-23 00:00:00", + "2045-12-24 00:00:00", + "2045-12-30 00:00:00", + "2045-12-31 00:00:00", + "2046-01-01 00:00:00", + "2046-01-06 00:00:00", + "2046-01-07 00:00:00", + "2046-01-13 00:00:00", + "2046-01-14 00:00:00", + "2046-01-20 00:00:00", + "2046-01-21 00:00:00", + "2046-01-27 00:00:00", + "2046-01-28 00:00:00", + "2046-02-04 00:00:00", + "2046-02-05 00:00:00", + "2046-02-06 00:00:00", + "2046-02-07 00:00:00", + "2046-02-08 00:00:00", + "2046-02-09 00:00:00", + "2046-02-10 00:00:00", + "2046-02-11 00:00:00", + "2046-02-12 00:00:00", + "2046-02-18 00:00:00", + "2046-02-24 00:00:00", + "2046-02-25 00:00:00", + "2046-03-03 00:00:00", + "2046-03-04 00:00:00", + "2046-03-10 00:00:00", + "2046-03-11 00:00:00", + "2046-03-17 00:00:00", + "2046-03-18 00:00:00", + "2046-03-24 00:00:00", + "2046-03-25 00:00:00", + "2046-03-31 00:00:00", + "2046-04-01 00:00:00", + "2046-04-04 00:00:00", + "2046-04-07 00:00:00", + "2046-04-08 00:00:00", + "2046-04-14 00:00:00", + "2046-04-15 00:00:00", + "2046-04-21 00:00:00", + "2046-04-22 00:00:00", + "2046-04-28 00:00:00", + "2046-04-29 00:00:00", + "2046-04-30 00:00:00", + "2046-05-01 00:00:00", + "2046-05-02 00:00:00", + "2046-05-05 00:00:00", + "2046-05-06 00:00:00", + "2046-05-12 00:00:00", + "2046-05-13 00:00:00", + "2046-05-19 00:00:00", + "2046-05-20 00:00:00", + "2046-05-26 00:00:00", + "2046-05-27 00:00:00", + "2046-06-02 00:00:00", + "2046-06-03 00:00:00", + "2046-06-08 00:00:00", + "2046-06-09 00:00:00", + "2046-06-10 00:00:00", + "2046-06-16 00:00:00", + "2046-06-17 00:00:00", + "2046-06-23 00:00:00", + "2046-06-24 00:00:00", + "2046-06-30 00:00:00", + "2046-07-01 00:00:00", + "2046-07-07 00:00:00", + "2046-07-08 00:00:00", + "2046-07-14 00:00:00", + "2046-07-15 00:00:00", + "2046-07-21 00:00:00", + "2046-07-22 00:00:00", + "2046-07-28 00:00:00", + "2046-07-29 00:00:00", + "2046-08-04 00:00:00", + "2046-08-05 00:00:00", + "2046-08-11 00:00:00", + "2046-08-12 00:00:00", + "2046-08-18 00:00:00", + "2046-08-19 00:00:00", + "2046-08-25 00:00:00", + "2046-08-26 00:00:00", + "2046-09-01 00:00:00", + "2046-09-02 00:00:00", + "2046-09-08 00:00:00", + "2046-09-09 00:00:00", + "2046-09-15 00:00:00", + "2046-09-16 00:00:00", + "2046-09-17 00:00:00", + "2046-09-22 00:00:00", + "2046-09-23 00:00:00", + "2046-09-30 00:00:00", + "2046-10-01 00:00:00", + "2046-10-02 00:00:00", + "2046-10-03 00:00:00", + "2046-10-04 00:00:00", + "2046-10-05 00:00:00", + "2046-10-06 00:00:00", + "2046-10-07 00:00:00", + "2046-10-14 00:00:00", + "2046-10-20 00:00:00", + "2046-10-21 00:00:00", + "2046-10-27 00:00:00", + "2046-10-28 00:00:00", + "2046-11-03 00:00:00", + "2046-11-04 00:00:00", + "2046-11-10 00:00:00", + "2046-11-11 00:00:00", + "2046-11-17 00:00:00", + "2046-11-18 00:00:00", + "2046-11-24 00:00:00", + "2046-11-25 00:00:00", + "2046-12-01 00:00:00", + "2046-12-02 00:00:00", + "2046-12-08 00:00:00", + "2046-12-09 00:00:00", + "2046-12-15 00:00:00", + "2046-12-16 00:00:00", + "2046-12-22 00:00:00", + "2046-12-23 00:00:00", + "2046-12-30 00:00:00", + "2046-12-31 00:00:00", + "2047-01-01 00:00:00", + "2047-01-05 00:00:00", + "2047-01-06 00:00:00", + "2047-01-12 00:00:00", + "2047-01-13 00:00:00", + "2047-01-19 00:00:00", + "2047-01-25 00:00:00", + "2047-01-26 00:00:00", + "2047-01-27 00:00:00", + "2047-01-28 00:00:00", + "2047-01-29 00:00:00", + "2047-01-30 00:00:00", + "2047-01-31 00:00:00", + "2047-02-01 00:00:00", + "2047-02-03 00:00:00", + "2047-02-09 00:00:00", + "2047-02-10 00:00:00", + "2047-02-16 00:00:00", + "2047-02-17 00:00:00", + "2047-02-23 00:00:00", + "2047-02-24 00:00:00", + "2047-03-02 00:00:00", + "2047-03-03 00:00:00", + "2047-03-09 00:00:00", + "2047-03-10 00:00:00", + "2047-03-16 00:00:00", + "2047-03-17 00:00:00", + "2047-03-23 00:00:00", + "2047-03-24 00:00:00", + "2047-03-30 00:00:00", + "2047-03-31 00:00:00", + "2047-04-04 00:00:00", + "2047-04-05 00:00:00", + "2047-04-06 00:00:00", + "2047-04-07 00:00:00", + "2047-04-13 00:00:00", + "2047-04-20 00:00:00", + "2047-04-21 00:00:00", + "2047-04-27 00:00:00", + "2047-04-28 00:00:00", + "2047-05-01 00:00:00", + "2047-05-02 00:00:00", + "2047-05-04 00:00:00", + "2047-05-05 00:00:00", + "2047-05-11 00:00:00", + "2047-05-12 00:00:00", + "2047-05-18 00:00:00", + "2047-05-19 00:00:00", + "2047-05-25 00:00:00", + "2047-05-26 00:00:00", + "2047-05-29 00:00:00", + "2047-06-01 00:00:00", + "2047-06-02 00:00:00", + "2047-06-08 00:00:00", + "2047-06-09 00:00:00", + "2047-06-15 00:00:00", + "2047-06-16 00:00:00", + "2047-06-22 00:00:00", + "2047-06-23 00:00:00", + "2047-06-29 00:00:00", + "2047-06-30 00:00:00", + "2047-07-06 00:00:00", + "2047-07-07 00:00:00", + "2047-07-13 00:00:00", + "2047-07-14 00:00:00", + "2047-07-20 00:00:00", + "2047-07-21 00:00:00", + "2047-07-27 00:00:00", + "2047-07-28 00:00:00", + "2047-08-03 00:00:00", + "2047-08-04 00:00:00", + "2047-08-10 00:00:00", + "2047-08-11 00:00:00", + "2047-08-17 00:00:00", + "2047-08-18 00:00:00", + "2047-08-24 00:00:00", + "2047-08-25 00:00:00", + "2047-08-31 00:00:00", + "2047-09-01 00:00:00", + "2047-09-07 00:00:00", + "2047-09-08 00:00:00", + "2047-09-14 00:00:00", + "2047-09-15 00:00:00", + "2047-09-21 00:00:00", + "2047-09-22 00:00:00", + "2047-09-28 00:00:00", + "2047-10-01 00:00:00", + "2047-10-02 00:00:00", + "2047-10-03 00:00:00", + "2047-10-04 00:00:00", + "2047-10-05 00:00:00", + "2047-10-06 00:00:00", + "2047-10-07 00:00:00", + "2047-10-08 00:00:00", + "2047-10-13 00:00:00", + "2047-10-19 00:00:00", + "2047-10-20 00:00:00", + "2047-10-26 00:00:00", + "2047-10-27 00:00:00", + "2047-11-02 00:00:00", + "2047-11-03 00:00:00", + "2047-11-09 00:00:00", + "2047-11-10 00:00:00", + "2047-11-16 00:00:00", + "2047-11-17 00:00:00", + "2047-11-23 00:00:00", + "2047-11-24 00:00:00", + "2047-11-30 00:00:00", + "2047-12-01 00:00:00", + "2047-12-07 00:00:00", + "2047-12-08 00:00:00", + "2047-12-14 00:00:00", + "2047-12-15 00:00:00", + "2047-12-21 00:00:00", + "2047-12-22 00:00:00", + "2047-12-28 00:00:00", + "2047-12-29 00:00:00", + "2048-01-01 00:00:00", + "2048-01-04 00:00:00", + "2048-01-05 00:00:00", + "2048-01-11 00:00:00", + "2048-01-12 00:00:00", + "2048-01-18 00:00:00", + "2048-01-19 00:00:00", + "2048-01-25 00:00:00", + "2048-01-26 00:00:00", + "2048-02-01 00:00:00", + "2048-02-02 00:00:00", + "2048-02-08 00:00:00", + "2048-02-13 00:00:00", + "2048-02-14 00:00:00", + "2048-02-15 00:00:00", + "2048-02-16 00:00:00", + "2048-02-17 00:00:00", + "2048-02-18 00:00:00", + "2048-02-19 00:00:00", + "2048-02-20 00:00:00", + "2048-02-23 00:00:00", + "2048-02-29 00:00:00", + "2048-03-01 00:00:00", + "2048-03-07 00:00:00", + "2048-03-08 00:00:00", + "2048-03-14 00:00:00", + "2048-03-15 00:00:00", + "2048-03-21 00:00:00", + "2048-03-22 00:00:00", + "2048-03-28 00:00:00", + "2048-03-29 00:00:00", + "2048-04-03 00:00:00", + "2048-04-04 00:00:00", + "2048-04-05 00:00:00", + "2048-04-11 00:00:00", + "2048-04-12 00:00:00", + "2048-04-18 00:00:00", + "2048-04-19 00:00:00", + "2048-04-25 00:00:00", + "2048-04-26 00:00:00", + "2048-05-01 00:00:00", + "2048-05-02 00:00:00", + "2048-05-03 00:00:00", + "2048-05-04 00:00:00", + "2048-05-05 00:00:00", + "2048-05-10 00:00:00", + "2048-05-16 00:00:00", + "2048-05-17 00:00:00", + "2048-05-23 00:00:00", + "2048-05-24 00:00:00", + "2048-05-30 00:00:00", + "2048-05-31 00:00:00", + "2048-06-06 00:00:00", + "2048-06-07 00:00:00", + "2048-06-13 00:00:00", + "2048-06-14 00:00:00", + "2048-06-15 00:00:00", + "2048-06-20 00:00:00", + "2048-06-21 00:00:00", + "2048-06-27 00:00:00", + "2048-06-28 00:00:00", + "2048-07-04 00:00:00", + "2048-07-05 00:00:00", + "2048-07-11 00:00:00", + "2048-07-12 00:00:00", + "2048-07-18 00:00:00", + "2048-07-19 00:00:00", + "2048-07-25 00:00:00", + "2048-07-26 00:00:00", + "2048-08-01 00:00:00", + "2048-08-02 00:00:00", + "2048-08-08 00:00:00", + "2048-08-09 00:00:00", + "2048-08-15 00:00:00", + "2048-08-16 00:00:00", + "2048-08-22 00:00:00", + "2048-08-23 00:00:00", + "2048-08-29 00:00:00", + "2048-08-30 00:00:00", + "2048-09-05 00:00:00", + "2048-09-06 00:00:00", + "2048-09-12 00:00:00", + "2048-09-19 00:00:00", + "2048-09-20 00:00:00", + "2048-09-21 00:00:00", + "2048-09-22 00:00:00", + "2048-09-26 00:00:00", + "2048-10-01 00:00:00", + "2048-10-02 00:00:00", + "2048-10-03 00:00:00", + "2048-10-04 00:00:00", + "2048-10-05 00:00:00", + "2048-10-06 00:00:00", + "2048-10-07 00:00:00", + "2048-10-11 00:00:00", + "2048-10-17 00:00:00", + "2048-10-18 00:00:00", + "2048-10-24 00:00:00", + "2048-10-25 00:00:00", + "2048-10-31 00:00:00", + "2048-11-01 00:00:00", + "2048-11-07 00:00:00", + "2048-11-08 00:00:00", + "2048-11-14 00:00:00", + "2048-11-15 00:00:00", + "2048-11-21 00:00:00", + "2048-11-22 00:00:00", + "2048-11-28 00:00:00", + "2048-11-29 00:00:00", + "2048-12-05 00:00:00", + "2048-12-06 00:00:00", + "2048-12-12 00:00:00", + "2048-12-13 00:00:00", + "2048-12-19 00:00:00", + "2048-12-20 00:00:00", + "2048-12-26 00:00:00", + "2048-12-27 00:00:00", + "2049-01-01 00:00:00", + "2049-01-02 00:00:00", + "2049-01-03 00:00:00", + "2049-01-09 00:00:00", + "2049-01-10 00:00:00", + "2049-01-16 00:00:00", + "2049-01-17 00:00:00", + "2049-01-23 00:00:00", + "2049-01-24 00:00:00", + "2049-01-31 00:00:00", + "2049-02-01 00:00:00", + "2049-02-02 00:00:00", + "2049-02-03 00:00:00", + "2049-02-04 00:00:00", + "2049-02-05 00:00:00", + "2049-02-06 00:00:00", + "2049-02-07 00:00:00", + "2049-02-08 00:00:00", + "2049-02-14 00:00:00", + "2049-02-20 00:00:00", + "2049-02-21 00:00:00", + "2049-02-27 00:00:00", + "2049-02-28 00:00:00", + "2049-03-06 00:00:00", + "2049-03-07 00:00:00", + "2049-03-13 00:00:00", + "2049-03-14 00:00:00", + "2049-03-20 00:00:00", + "2049-03-21 00:00:00", + "2049-03-27 00:00:00", + "2049-03-28 00:00:00", + "2049-04-03 00:00:00", + "2049-04-04 00:00:00", + "2049-04-05 00:00:00", + "2049-04-10 00:00:00", + "2049-04-11 00:00:00", + "2049-04-17 00:00:00", + "2049-04-18 00:00:00", + "2049-04-24 00:00:00", + "2049-04-25 00:00:00", + "2049-05-01 00:00:00", + "2049-05-02 00:00:00", + "2049-05-03 00:00:00", + "2049-05-04 00:00:00", + "2049-05-05 00:00:00", + "2049-05-08 00:00:00", + "2049-05-15 00:00:00", + "2049-05-16 00:00:00", + "2049-05-22 00:00:00", + "2049-05-23 00:00:00", + "2049-05-29 00:00:00", + "2049-05-30 00:00:00", + "2049-06-04 00:00:00", + "2049-06-05 00:00:00", + "2049-06-06 00:00:00", + "2049-06-12 00:00:00", + "2049-06-13 00:00:00", + "2049-06-19 00:00:00", + "2049-06-20 00:00:00", + "2049-06-26 00:00:00", + "2049-06-27 00:00:00", + "2049-07-03 00:00:00", + "2049-07-04 00:00:00", + "2049-07-10 00:00:00", + "2049-07-11 00:00:00", + "2049-07-17 00:00:00", + "2049-07-18 00:00:00", + "2049-07-24 00:00:00", + "2049-07-25 00:00:00", + "2049-07-31 00:00:00", + "2049-08-01 00:00:00", + "2049-08-07 00:00:00", + "2049-08-08 00:00:00", + "2049-08-14 00:00:00", + "2049-08-15 00:00:00", + "2049-08-21 00:00:00", + "2049-08-22 00:00:00", + "2049-08-28 00:00:00", + "2049-08-29 00:00:00", + "2049-09-04 00:00:00", + "2049-09-05 00:00:00", + "2049-09-11 00:00:00", + "2049-09-12 00:00:00", + "2049-09-13 00:00:00", + "2049-09-18 00:00:00", + "2049-09-19 00:00:00", + "2049-09-25 00:00:00", + "2049-10-01 00:00:00", + "2049-10-02 00:00:00", + "2049-10-03 00:00:00", + "2049-10-04 00:00:00", + "2049-10-05 00:00:00", + "2049-10-06 00:00:00", + "2049-10-07 00:00:00", + "2049-10-10 00:00:00", + "2049-10-16 00:00:00", + "2049-10-17 00:00:00", + "2049-10-23 00:00:00", + "2049-10-24 00:00:00", + "2049-10-30 00:00:00", + "2049-10-31 00:00:00", + "2049-11-06 00:00:00", + "2049-11-07 00:00:00", + "2049-11-13 00:00:00", + "2049-11-14 00:00:00", + "2049-11-20 00:00:00", + "2049-11-21 00:00:00", + "2049-11-27 00:00:00", + "2049-11-28 00:00:00", + "2049-12-04 00:00:00", + "2049-12-05 00:00:00", + "2049-12-11 00:00:00", + "2049-12-12 00:00:00", + "2049-12-18 00:00:00", + "2049-12-19 00:00:00", + "2049-12-25 00:00:00", + "2049-12-26 00:00:00", + "2050-01-01 00:00:00", + "2050-01-02 00:00:00", + "2050-01-03 00:00:00", + "2050-01-08 00:00:00", + "2050-01-09 00:00:00", + "2050-01-15 00:00:00", + "2050-01-22 00:00:00", + "2050-01-23 00:00:00", + "2050-01-24 00:00:00", + "2050-01-25 00:00:00", + "2050-01-26 00:00:00", + "2050-01-27 00:00:00", + "2050-01-28 00:00:00", + "2050-01-29 00:00:00", + "2050-02-05 00:00:00", + "2050-02-06 00:00:00", + "2050-02-12 00:00:00", + "2050-02-13 00:00:00", + "2050-02-19 00:00:00", + "2050-02-20 00:00:00", + "2050-02-26 00:00:00", + "2050-02-27 00:00:00", + "2050-03-05 00:00:00", + "2050-03-06 00:00:00", + "2050-03-12 00:00:00", + "2050-03-13 00:00:00", + "2050-03-19 00:00:00", + "2050-03-20 00:00:00", + "2050-03-26 00:00:00", + "2050-03-27 00:00:00", + "2050-04-02 00:00:00", + "2050-04-03 00:00:00", + "2050-04-04 00:00:00", + "2050-04-09 00:00:00", + "2050-04-10 00:00:00", + "2050-04-16 00:00:00", + "2050-04-17 00:00:00", + "2050-04-23 00:00:00", + "2050-04-24 00:00:00", + "2050-04-30 00:00:00", + "2050-05-01 00:00:00", + "2050-05-02 00:00:00", + "2050-05-03 00:00:00", + "2050-05-04 00:00:00", + "2050-05-07 00:00:00", + "2050-05-14 00:00:00", + "2050-05-15 00:00:00", + "2050-05-21 00:00:00", + "2050-05-22 00:00:00", + "2050-05-28 00:00:00", + "2050-05-29 00:00:00", + "2050-06-04 00:00:00", + "2050-06-05 00:00:00", + "2050-06-11 00:00:00", + "2050-06-12 00:00:00", + "2050-06-18 00:00:00", + "2050-06-19 00:00:00", + "2050-06-23 00:00:00", + "2050-06-24 00:00:00", + "2050-06-25 00:00:00", + "2050-06-26 00:00:00", + "2050-07-02 00:00:00", + "2050-07-09 00:00:00", + "2050-07-10 00:00:00", + "2050-07-16 00:00:00", + "2050-07-17 00:00:00", + "2050-07-23 00:00:00", + "2050-07-24 00:00:00", + "2050-07-30 00:00:00", + "2050-07-31 00:00:00", + "2050-08-06 00:00:00", + "2050-08-07 00:00:00", + "2050-08-13 00:00:00", + "2050-08-14 00:00:00", + "2050-08-20 00:00:00", + "2050-08-21 00:00:00", + "2050-08-27 00:00:00", + "2050-08-28 00:00:00", + "2050-09-03 00:00:00", + "2050-09-04 00:00:00", + "2050-09-10 00:00:00", + "2050-09-11 00:00:00", + "2050-09-17 00:00:00", + "2050-09-18 00:00:00", + "2050-09-24 00:00:00", + "2050-09-30 00:00:00", + "2050-10-01 00:00:00", + "2050-10-02 00:00:00", + "2050-10-03 00:00:00", + "2050-10-04 00:00:00", + "2050-10-05 00:00:00", + "2050-10-06 00:00:00", + "2050-10-07 00:00:00", + "2050-10-08 00:00:00", + "2050-10-15 00:00:00", + "2050-10-16 00:00:00", + "2050-10-22 00:00:00", + "2050-10-23 00:00:00", + "2050-10-29 00:00:00", + "2050-10-30 00:00:00", + "2050-11-05 00:00:00", + "2050-11-06 00:00:00", + "2050-11-12 00:00:00", + "2050-11-13 00:00:00", + "2050-11-19 00:00:00", + "2050-11-20 00:00:00", + "2050-11-26 00:00:00", + "2050-11-27 00:00:00", + "2050-12-03 00:00:00", + "2050-12-04 00:00:00", + "2050-12-10 00:00:00", + "2050-12-11 00:00:00", + "2050-12-17 00:00:00", + "2050-12-18 00:00:00", + "2050-12-24 00:00:00", + "2050-12-25 00:00:00", + "2050-12-31 00:00:00", + "2051-01-01 00:00:00", + "2051-01-02 00:00:00", + "2051-01-07 00:00:00", + "2051-01-08 00:00:00", + "2051-01-14 00:00:00", + "2051-01-15 00:00:00", + "2051-01-21 00:00:00", + "2051-01-22 00:00:00", + "2051-01-28 00:00:00", + "2051-01-29 00:00:00", + "2051-02-04 00:00:00", + "2051-02-10 00:00:00", + "2051-02-11 00:00:00", + "2051-02-12 00:00:00", + "2051-02-13 00:00:00", + "2051-02-14 00:00:00", + "2051-02-15 00:00:00", + "2051-02-16 00:00:00", + "2051-02-17 00:00:00", + "2051-02-19 00:00:00", + "2051-02-25 00:00:00", + "2051-02-26 00:00:00", + "2051-03-04 00:00:00", + "2051-03-05 00:00:00", + "2051-03-11 00:00:00", + "2051-03-12 00:00:00", + "2051-03-18 00:00:00", + "2051-03-19 00:00:00", + "2051-03-25 00:00:00", + "2051-04-01 00:00:00", + "2051-04-02 00:00:00", + "2051-04-03 00:00:00", + "2051-04-04 00:00:00", + "2051-04-08 00:00:00", + "2051-04-09 00:00:00", + "2051-04-15 00:00:00", + "2051-04-16 00:00:00", + "2051-04-22 00:00:00", + "2051-04-23 00:00:00", + "2051-04-29 00:00:00", + "2051-04-30 00:00:00", + "2051-05-01 00:00:00", + "2051-05-02 00:00:00", + "2051-05-03 00:00:00", + "2051-05-06 00:00:00", + "2051-05-13 00:00:00", + "2051-05-14 00:00:00", + "2051-05-20 00:00:00", + "2051-05-21 00:00:00", + "2051-05-27 00:00:00", + "2051-05-28 00:00:00", + "2051-06-03 00:00:00", + "2051-06-10 00:00:00", + "2051-06-11 00:00:00", + "2051-06-12 00:00:00", + "2051-06-13 00:00:00", + "2051-06-17 00:00:00", + "2051-06-18 00:00:00", + "2051-06-24 00:00:00", + "2051-06-25 00:00:00", + "2051-07-01 00:00:00", + "2051-07-02 00:00:00", + "2051-07-08 00:00:00", + "2051-07-09 00:00:00", + "2051-07-15 00:00:00", + "2051-07-16 00:00:00", + "2051-07-22 00:00:00", + "2051-07-23 00:00:00", + "2051-07-29 00:00:00", + "2051-07-30 00:00:00", + "2051-08-05 00:00:00", + "2051-08-06 00:00:00", + "2051-08-12 00:00:00", + "2051-08-13 00:00:00", + "2051-08-19 00:00:00", + "2051-08-20 00:00:00", + "2051-08-26 00:00:00", + "2051-08-27 00:00:00", + "2051-09-02 00:00:00", + "2051-09-03 00:00:00", + "2051-09-09 00:00:00", + "2051-09-16 00:00:00", + "2051-09-17 00:00:00", + "2051-09-18 00:00:00", + "2051-09-19 00:00:00", + "2051-09-23 00:00:00", + "2051-09-30 00:00:00", + "2051-10-01 00:00:00", + "2051-10-02 00:00:00", + "2051-10-03 00:00:00", + "2051-10-04 00:00:00", + "2051-10-05 00:00:00", + "2051-10-06 00:00:00", + "2051-10-07 00:00:00", + "2051-10-14 00:00:00", + "2051-10-15 00:00:00", + "2051-10-21 00:00:00", + "2051-10-22 00:00:00", + "2051-10-28 00:00:00", + "2051-10-29 00:00:00", + "2051-11-04 00:00:00", + "2051-11-05 00:00:00", + "2051-11-11 00:00:00", + "2051-11-12 00:00:00", + "2051-11-18 00:00:00", + "2051-11-19 00:00:00", + "2051-11-25 00:00:00", + "2051-11-26 00:00:00", + "2051-12-02 00:00:00", + "2051-12-03 00:00:00", + "2051-12-09 00:00:00", + "2051-12-10 00:00:00", + "2051-12-16 00:00:00", + "2051-12-17 00:00:00", + "2051-12-23 00:00:00", + "2051-12-24 00:00:00", + "2051-12-30 00:00:00", + "2051-12-31 00:00:00", + "2052-01-01 00:00:00", + "2052-01-06 00:00:00", + "2052-01-07 00:00:00", + "2052-01-13 00:00:00", + "2052-01-14 00:00:00", + "2052-01-20 00:00:00", + "2052-01-21 00:00:00", + "2052-01-27 00:00:00", + "2052-01-31 00:00:00", + "2052-02-01 00:00:00", + "2052-02-02 00:00:00", + "2052-02-03 00:00:00", + "2052-02-04 00:00:00", + "2052-02-05 00:00:00", + "2052-02-06 00:00:00", + "2052-02-07 00:00:00", + "2052-02-11 00:00:00", + "2052-02-17 00:00:00", + "2052-02-18 00:00:00", + "2052-02-24 00:00:00", + "2052-02-25 00:00:00", + "2052-03-02 00:00:00", + "2052-03-03 00:00:00", + "2052-03-09 00:00:00", + "2052-03-10 00:00:00", + "2052-03-16 00:00:00", + "2052-03-17 00:00:00", + "2052-03-23 00:00:00", + "2052-03-24 00:00:00", + "2052-03-30 00:00:00", + "2052-03-31 00:00:00", + "2052-04-03 00:00:00", + "2052-04-06 00:00:00", + "2052-04-07 00:00:00", + "2052-04-13 00:00:00", + "2052-04-14 00:00:00", + "2052-04-20 00:00:00", + "2052-04-21 00:00:00", + "2052-04-27 00:00:00", + "2052-04-28 00:00:00", + "2052-05-01 00:00:00", + "2052-05-02 00:00:00", + "2052-05-04 00:00:00", + "2052-05-05 00:00:00", + "2052-05-11 00:00:00", + "2052-05-12 00:00:00", + "2052-05-18 00:00:00", + "2052-05-19 00:00:00", + "2052-05-25 00:00:00", + "2052-05-26 00:00:00", + "2052-06-01 00:00:00", + "2052-06-02 00:00:00", + "2052-06-03 00:00:00", + "2052-06-08 00:00:00", + "2052-06-09 00:00:00", + "2052-06-15 00:00:00", + "2052-06-16 00:00:00", + "2052-06-22 00:00:00", + "2052-06-23 00:00:00", + "2052-06-29 00:00:00", + "2052-06-30 00:00:00", + "2052-07-06 00:00:00", + "2052-07-07 00:00:00", + "2052-07-13 00:00:00", + "2052-07-14 00:00:00", + "2052-07-20 00:00:00", + "2052-07-21 00:00:00", + "2052-07-27 00:00:00", + "2052-07-28 00:00:00", + "2052-08-03 00:00:00", + "2052-08-04 00:00:00", + "2052-08-10 00:00:00", + "2052-08-11 00:00:00", + "2052-08-17 00:00:00", + "2052-08-18 00:00:00", + "2052-08-24 00:00:00", + "2052-08-25 00:00:00", + "2052-08-31 00:00:00", + "2052-09-01 00:00:00", + "2052-09-07 00:00:00", + "2052-09-08 00:00:00", + "2052-09-09 00:00:00", + "2052-09-14 00:00:00", + "2052-09-15 00:00:00", + "2052-09-21 00:00:00", + "2052-09-22 00:00:00", + "2052-09-28 00:00:00", + "2052-10-01 00:00:00", + "2052-10-02 00:00:00", + "2052-10-03 00:00:00", + "2052-10-04 00:00:00", + "2052-10-05 00:00:00", + "2052-10-06 00:00:00", + "2052-10-07 00:00:00", + "2052-10-13 00:00:00", + "2052-10-19 00:00:00", + "2052-10-20 00:00:00", + "2052-10-26 00:00:00", + "2052-10-27 00:00:00", + "2052-11-02 00:00:00", + "2052-11-03 00:00:00", + "2052-11-09 00:00:00", + "2052-11-10 00:00:00", + "2052-11-16 00:00:00", + "2052-11-17 00:00:00", + "2052-11-23 00:00:00", + "2052-11-24 00:00:00", + "2052-11-30 00:00:00", + "2052-12-01 00:00:00", + "2052-12-07 00:00:00", + "2052-12-08 00:00:00", + "2052-12-14 00:00:00", + "2052-12-15 00:00:00", + "2052-12-21 00:00:00", + "2052-12-22 00:00:00", + "2052-12-28 00:00:00", + "2052-12-29 00:00:00", + "2053-01-01 00:00:00", + "2053-01-04 00:00:00", + "2053-01-05 00:00:00", + "2053-01-11 00:00:00", + "2053-01-12 00:00:00", + "2053-01-18 00:00:00", + "2053-01-19 00:00:00", + "2053-01-25 00:00:00", + "2053-01-26 00:00:00", + "2053-02-01 00:00:00", + "2053-02-02 00:00:00", + "2053-02-08 00:00:00", + "2053-02-09 00:00:00", + "2053-02-15 00:00:00", + "2053-02-18 00:00:00", + "2053-02-19 00:00:00", + "2053-02-20 00:00:00", + "2053-02-21 00:00:00", + "2053-02-22 00:00:00", + "2053-02-23 00:00:00", + "2053-02-24 00:00:00", + "2053-02-25 00:00:00", + "2053-03-02 00:00:00", + "2053-03-08 00:00:00", + "2053-03-09 00:00:00", + "2053-03-15 00:00:00", + "2053-03-16 00:00:00", + "2053-03-22 00:00:00", + "2053-03-23 00:00:00", + "2053-03-29 00:00:00", + "2053-03-30 00:00:00", + "2053-04-04 00:00:00", + "2053-04-05 00:00:00", + "2053-04-06 00:00:00", + "2053-04-12 00:00:00", + "2053-04-13 00:00:00", + "2053-04-19 00:00:00", + "2053-04-20 00:00:00", + "2053-04-26 00:00:00", + "2053-05-01 00:00:00", + "2053-05-02 00:00:00", + "2053-05-03 00:00:00", + "2053-05-04 00:00:00", + "2053-05-05 00:00:00", + "2053-05-10 00:00:00", + "2053-05-11 00:00:00", + "2053-05-17 00:00:00", + "2053-05-18 00:00:00", + "2053-05-24 00:00:00", + "2053-05-25 00:00:00", + "2053-05-31 00:00:00", + "2053-06-01 00:00:00", + "2053-06-07 00:00:00", + "2053-06-08 00:00:00", + "2053-06-14 00:00:00", + "2053-06-15 00:00:00", + "2053-06-20 00:00:00", + "2053-06-21 00:00:00", + "2053-06-22 00:00:00", + "2053-06-28 00:00:00", + "2053-06-29 00:00:00", + "2053-07-05 00:00:00", + "2053-07-06 00:00:00", + "2053-07-12 00:00:00", + "2053-07-13 00:00:00", + "2053-07-19 00:00:00", + "2053-07-20 00:00:00", + "2053-07-26 00:00:00", + "2053-07-27 00:00:00", + "2053-08-02 00:00:00", + "2053-08-03 00:00:00", + "2053-08-09 00:00:00", + "2053-08-10 00:00:00", + "2053-08-16 00:00:00", + "2053-08-17 00:00:00", + "2053-08-23 00:00:00", + "2053-08-24 00:00:00", + "2053-08-30 00:00:00", + "2053-08-31 00:00:00", + "2053-09-06 00:00:00", + "2053-09-07 00:00:00", + "2053-09-13 00:00:00", + "2053-09-14 00:00:00", + "2053-09-20 00:00:00", + "2053-09-26 00:00:00", + "2053-09-27 00:00:00", + "2053-09-28 00:00:00", + "2053-10-01 00:00:00", + "2053-10-02 00:00:00", + "2053-10-03 00:00:00", + "2053-10-04 00:00:00", + "2053-10-05 00:00:00", + "2053-10-06 00:00:00", + "2053-10-07 00:00:00", + "2053-10-12 00:00:00", + "2053-10-18 00:00:00", + "2053-10-19 00:00:00", + "2053-10-25 00:00:00", + "2053-10-26 00:00:00", + "2053-11-01 00:00:00", + "2053-11-02 00:00:00", + "2053-11-08 00:00:00", + "2053-11-09 00:00:00", + "2053-11-15 00:00:00", + "2053-11-16 00:00:00", + "2053-11-22 00:00:00", + "2053-11-23 00:00:00", + "2053-11-29 00:00:00", + "2053-11-30 00:00:00", + "2053-12-06 00:00:00", + "2053-12-07 00:00:00", + "2053-12-13 00:00:00", + "2053-12-14 00:00:00", + "2053-12-20 00:00:00", + "2053-12-21 00:00:00", + "2053-12-27 00:00:00", + "2053-12-28 00:00:00", + "2054-01-01 00:00:00", + "2054-01-02 00:00:00", + "2054-01-03 00:00:00", + "2054-01-10 00:00:00", + "2054-01-11 00:00:00", + "2054-01-17 00:00:00", + "2054-01-18 00:00:00", + "2054-01-24 00:00:00", + "2054-01-25 00:00:00", + "2054-01-31 00:00:00", + "2054-02-07 00:00:00", + "2054-02-08 00:00:00", + "2054-02-09 00:00:00", + "2054-02-10 00:00:00", + "2054-02-11 00:00:00", + "2054-02-12 00:00:00", + "2054-02-13 00:00:00", + "2054-02-14 00:00:00", + "2054-02-21 00:00:00", + "2054-02-22 00:00:00", + "2054-02-28 00:00:00", + "2054-03-01 00:00:00", + "2054-03-07 00:00:00", + "2054-03-08 00:00:00", + "2054-03-14 00:00:00", + "2054-03-15 00:00:00", + "2054-03-21 00:00:00", + "2054-03-22 00:00:00", + "2054-03-28 00:00:00", + "2054-03-29 00:00:00", + "2054-04-04 00:00:00", + "2054-04-05 00:00:00", + "2054-04-06 00:00:00", + "2054-04-11 00:00:00", + "2054-04-12 00:00:00", + "2054-04-18 00:00:00", + "2054-04-19 00:00:00", + "2054-04-25 00:00:00", + "2054-04-26 00:00:00", + "2054-05-01 00:00:00", + "2054-05-02 00:00:00", + "2054-05-03 00:00:00", + "2054-05-04 00:00:00", + "2054-05-05 00:00:00", + "2054-05-10 00:00:00", + "2054-05-16 00:00:00", + "2054-05-17 00:00:00", + "2054-05-23 00:00:00", + "2054-05-24 00:00:00", + "2054-05-30 00:00:00", + "2054-05-31 00:00:00", + "2054-06-06 00:00:00", + "2054-06-07 00:00:00", + "2054-06-10 00:00:00", + "2054-06-13 00:00:00", + "2054-06-14 00:00:00", + "2054-06-20 00:00:00", + "2054-06-21 00:00:00", + "2054-06-27 00:00:00", + "2054-06-28 00:00:00", + "2054-07-04 00:00:00", + "2054-07-05 00:00:00", + "2054-07-11 00:00:00", + "2054-07-12 00:00:00", + "2054-07-18 00:00:00", + "2054-07-19 00:00:00", + "2054-07-25 00:00:00", + "2054-07-26 00:00:00", + "2054-08-01 00:00:00", + "2054-08-02 00:00:00", + "2054-08-08 00:00:00", + "2054-08-09 00:00:00", + "2054-08-15 00:00:00", + "2054-08-16 00:00:00", + "2054-08-22 00:00:00", + "2054-08-23 00:00:00", + "2054-08-29 00:00:00", + "2054-08-30 00:00:00", + "2054-09-05 00:00:00", + "2054-09-06 00:00:00", + "2054-09-12 00:00:00", + "2054-09-13 00:00:00", + "2054-09-16 00:00:00", + "2054-09-19 00:00:00", + "2054-09-20 00:00:00", + "2054-09-26 00:00:00", + "2054-10-01 00:00:00", + "2054-10-02 00:00:00", + "2054-10-03 00:00:00", + "2054-10-04 00:00:00", + "2054-10-05 00:00:00", + "2054-10-06 00:00:00", + "2054-10-07 00:00:00", + "2054-10-11 00:00:00", + "2054-10-17 00:00:00", + "2054-10-18 00:00:00", + "2054-10-24 00:00:00", + "2054-10-25 00:00:00", + "2054-10-31 00:00:00", + "2054-11-01 00:00:00", + "2054-11-07 00:00:00", + "2054-11-08 00:00:00", + "2054-11-14 00:00:00", + "2054-11-15 00:00:00", + "2054-11-21 00:00:00", + "2054-11-22 00:00:00", + "2054-11-28 00:00:00", + "2054-11-29 00:00:00", + "2054-12-05 00:00:00", + "2054-12-06 00:00:00", + "2054-12-12 00:00:00", + "2054-12-13 00:00:00", + "2054-12-19 00:00:00", + "2054-12-20 00:00:00", + "2054-12-26 00:00:00", + "2054-12-27 00:00:00", + "2055-01-01 00:00:00", + "2055-01-02 00:00:00", + "2055-01-03 00:00:00", + "2055-01-09 00:00:00", + "2055-01-10 00:00:00", + "2055-01-16 00:00:00", + "2055-01-17 00:00:00", + "2055-01-23 00:00:00", + "2055-01-27 00:00:00", + "2055-01-28 00:00:00", + "2055-01-29 00:00:00", + "2055-01-30 00:00:00", + "2055-01-31 00:00:00", + "2055-02-01 00:00:00", + "2055-02-02 00:00:00", + "2055-02-03 00:00:00", + "2055-02-07 00:00:00", + "2055-02-13 00:00:00", + "2055-02-14 00:00:00", + "2055-02-20 00:00:00", + "2055-02-21 00:00:00", + "2055-02-27 00:00:00", + "2055-02-28 00:00:00", + "2055-03-06 00:00:00", + "2055-03-07 00:00:00", + "2055-03-13 00:00:00", + "2055-03-14 00:00:00", + "2055-03-20 00:00:00", + "2055-03-21 00:00:00", + "2055-03-27 00:00:00", + "2055-03-28 00:00:00", + "2055-04-03 00:00:00", + "2055-04-04 00:00:00", + "2055-04-05 00:00:00", + "2055-04-10 00:00:00", + "2055-04-11 00:00:00", + "2055-04-17 00:00:00", + "2055-04-18 00:00:00", + "2055-04-24 00:00:00", + "2055-04-25 00:00:00", + "2055-05-01 00:00:00", + "2055-05-02 00:00:00", + "2055-05-03 00:00:00", + "2055-05-04 00:00:00", + "2055-05-05 00:00:00", + "2055-05-08 00:00:00", + "2055-05-15 00:00:00", + "2055-05-16 00:00:00", + "2055-05-22 00:00:00", + "2055-05-23 00:00:00", + "2055-05-29 00:00:00", + "2055-05-30 00:00:00", + "2055-05-31 00:00:00", + "2055-06-05 00:00:00", + "2055-06-06 00:00:00", + "2055-06-12 00:00:00", + "2055-06-13 00:00:00", + "2055-06-19 00:00:00", + "2055-06-20 00:00:00", + "2055-06-26 00:00:00", + "2055-06-27 00:00:00", + "2055-07-03 00:00:00", + "2055-07-04 00:00:00", + "2055-07-10 00:00:00", + "2055-07-11 00:00:00", + "2055-07-17 00:00:00", + "2055-07-18 00:00:00", + "2055-07-24 00:00:00", + "2055-07-25 00:00:00", + "2055-07-31 00:00:00", + "2055-08-01 00:00:00", + "2055-08-07 00:00:00", + "2055-08-08 00:00:00", + "2055-08-14 00:00:00", + "2055-08-15 00:00:00", + "2055-08-21 00:00:00", + "2055-08-22 00:00:00", + "2055-08-28 00:00:00", + "2055-08-29 00:00:00", + "2055-09-04 00:00:00", + "2055-09-05 00:00:00", + "2055-09-11 00:00:00", + "2055-09-12 00:00:00", + "2055-09-18 00:00:00", + "2055-09-19 00:00:00", + "2055-09-25 00:00:00", + "2055-10-01 00:00:00", + "2055-10-02 00:00:00", + "2055-10-03 00:00:00", + "2055-10-04 00:00:00", + "2055-10-05 00:00:00", + "2055-10-06 00:00:00", + "2055-10-07 00:00:00", + "2055-10-08 00:00:00", + "2055-10-10 00:00:00", + "2055-10-16 00:00:00", + "2055-10-17 00:00:00", + "2055-10-23 00:00:00", + "2055-10-24 00:00:00", + "2055-10-30 00:00:00", + "2055-10-31 00:00:00", + "2055-11-06 00:00:00", + "2055-11-07 00:00:00", + "2055-11-13 00:00:00", + "2055-11-14 00:00:00", + "2055-11-20 00:00:00", + "2055-11-21 00:00:00", + "2055-11-27 00:00:00", + "2055-11-28 00:00:00", + "2055-12-04 00:00:00", + "2055-12-05 00:00:00", + "2055-12-11 00:00:00", + "2055-12-12 00:00:00", + "2055-12-18 00:00:00", + "2055-12-19 00:00:00", + "2055-12-25 00:00:00", + "2055-12-26 00:00:00", + "2056-01-01 00:00:00", + "2056-01-02 00:00:00", + "2056-01-03 00:00:00", + "2056-01-08 00:00:00", + "2056-01-09 00:00:00", + "2056-01-15 00:00:00", + "2056-01-16 00:00:00", + "2056-01-22 00:00:00", + "2056-01-23 00:00:00", + "2056-01-29 00:00:00", + "2056-01-30 00:00:00", + "2056-02-05 00:00:00", + "2056-02-06 00:00:00", + "2056-02-13 00:00:00", + "2056-02-14 00:00:00", + "2056-02-15 00:00:00", + "2056-02-16 00:00:00", + "2056-02-17 00:00:00", + "2056-02-18 00:00:00", + "2056-02-19 00:00:00", + "2056-02-20 00:00:00", + "2056-02-21 00:00:00", + "2056-02-27 00:00:00", + "2056-03-04 00:00:00", + "2056-03-05 00:00:00", + "2056-03-11 00:00:00", + "2056-03-12 00:00:00", + "2056-03-18 00:00:00", + "2056-03-19 00:00:00", + "2056-03-25 00:00:00", + "2056-03-26 00:00:00", + "2056-04-01 00:00:00", + "2056-04-02 00:00:00", + "2056-04-03 00:00:00", + "2056-04-08 00:00:00", + "2056-04-09 00:00:00", + "2056-04-15 00:00:00", + "2056-04-16 00:00:00", + "2056-04-22 00:00:00", + "2056-04-23 00:00:00", + "2056-04-29 00:00:00", + "2056-04-30 00:00:00", + "2056-05-01 00:00:00", + "2056-05-02 00:00:00", + "2056-05-03 00:00:00", + "2056-05-06 00:00:00", + "2056-05-13 00:00:00", + "2056-05-14 00:00:00", + "2056-05-20 00:00:00", + "2056-05-21 00:00:00", + "2056-05-27 00:00:00", + "2056-05-28 00:00:00", + "2056-06-03 00:00:00", + "2056-06-04 00:00:00", + "2056-06-10 00:00:00", + "2056-06-11 00:00:00", + "2056-06-17 00:00:00", + "2056-06-18 00:00:00", + "2056-06-19 00:00:00", + "2056-06-24 00:00:00", + "2056-06-25 00:00:00", + "2056-07-01 00:00:00", + "2056-07-02 00:00:00", + "2056-07-08 00:00:00", + "2056-07-09 00:00:00", + "2056-07-15 00:00:00", + "2056-07-16 00:00:00", + "2056-07-22 00:00:00", + "2056-07-23 00:00:00", + "2056-07-29 00:00:00", + "2056-07-30 00:00:00", + "2056-08-05 00:00:00", + "2056-08-06 00:00:00", + "2056-08-12 00:00:00", + "2056-08-13 00:00:00", + "2056-08-19 00:00:00", + "2056-08-20 00:00:00", + "2056-08-26 00:00:00", + "2056-08-27 00:00:00", + "2056-09-02 00:00:00", + "2056-09-03 00:00:00", + "2056-09-09 00:00:00", + "2056-09-10 00:00:00", + "2056-09-16 00:00:00", + "2056-09-23 00:00:00", + "2056-09-24 00:00:00", + "2056-09-25 00:00:00", + "2056-09-30 00:00:00", + "2056-10-01 00:00:00", + "2056-10-02 00:00:00", + "2056-10-03 00:00:00", + "2056-10-04 00:00:00", + "2056-10-05 00:00:00", + "2056-10-06 00:00:00", + "2056-10-07 00:00:00", + "2056-10-14 00:00:00", + "2056-10-15 00:00:00", + "2056-10-21 00:00:00", + "2056-10-22 00:00:00", + "2056-10-28 00:00:00", + "2056-10-29 00:00:00", + "2056-11-04 00:00:00", + "2056-11-05 00:00:00", + "2056-11-11 00:00:00", + "2056-11-12 00:00:00", + "2056-11-18 00:00:00", + "2056-11-19 00:00:00", + "2056-11-25 00:00:00", + "2056-11-26 00:00:00", + "2056-12-02 00:00:00", + "2056-12-03 00:00:00", + "2056-12-09 00:00:00", + "2056-12-10 00:00:00", + "2056-12-16 00:00:00", + "2056-12-17 00:00:00", + "2056-12-23 00:00:00", + "2056-12-24 00:00:00", + "2056-12-30 00:00:00", + "2056-12-31 00:00:00", + "2057-01-01 00:00:00", + "2057-01-06 00:00:00", + "2057-01-07 00:00:00", + "2057-01-13 00:00:00", + "2057-01-14 00:00:00", + "2057-01-20 00:00:00", + "2057-01-21 00:00:00", + "2057-01-27 00:00:00", + "2057-02-03 00:00:00", + "2057-02-04 00:00:00", + "2057-02-05 00:00:00", + "2057-02-06 00:00:00", + "2057-02-07 00:00:00", + "2057-02-08 00:00:00", + "2057-02-09 00:00:00", + "2057-02-10 00:00:00", + "2057-02-17 00:00:00", + "2057-02-18 00:00:00", + "2057-02-24 00:00:00", + "2057-02-25 00:00:00", + "2057-03-03 00:00:00", + "2057-03-04 00:00:00", + "2057-03-10 00:00:00", + "2057-03-11 00:00:00", + "2057-03-17 00:00:00", + "2057-03-18 00:00:00", + "2057-03-24 00:00:00", + "2057-03-25 00:00:00", + "2057-03-31 00:00:00", + "2057-04-01 00:00:00", + "2057-04-04 00:00:00", + "2057-04-07 00:00:00", + "2057-04-08 00:00:00", + "2057-04-14 00:00:00", + "2057-04-15 00:00:00", + "2057-04-21 00:00:00", + "2057-04-22 00:00:00", + "2057-04-28 00:00:00", + "2057-04-29 00:00:00", + "2057-04-30 00:00:00", + "2057-05-01 00:00:00", + "2057-05-02 00:00:00", + "2057-05-05 00:00:00", + "2057-05-06 00:00:00", + "2057-05-12 00:00:00", + "2057-05-13 00:00:00", + "2057-05-19 00:00:00", + "2057-05-20 00:00:00", + "2057-05-26 00:00:00", + "2057-05-27 00:00:00", + "2057-06-02 00:00:00", + "2057-06-03 00:00:00", + "2057-06-06 00:00:00", + "2057-06-09 00:00:00", + "2057-06-10 00:00:00", + "2057-06-16 00:00:00", + "2057-06-17 00:00:00", + "2057-06-23 00:00:00", + "2057-06-24 00:00:00", + "2057-06-30 00:00:00", + "2057-07-01 00:00:00", + "2057-07-07 00:00:00", + "2057-07-08 00:00:00", + "2057-07-14 00:00:00", + "2057-07-15 00:00:00", + "2057-07-21 00:00:00", + "2057-07-22 00:00:00", + "2057-07-28 00:00:00", + "2057-07-29 00:00:00", + "2057-08-04 00:00:00", + "2057-08-05 00:00:00", + "2057-08-11 00:00:00", + "2057-08-12 00:00:00", + "2057-08-18 00:00:00", + "2057-08-19 00:00:00", + "2057-08-25 00:00:00", + "2057-08-26 00:00:00", + "2057-09-01 00:00:00", + "2057-09-02 00:00:00", + "2057-09-08 00:00:00", + "2057-09-09 00:00:00", + "2057-09-13 00:00:00", + "2057-09-14 00:00:00", + "2057-09-15 00:00:00", + "2057-09-16 00:00:00", + "2057-09-22 00:00:00", + "2057-09-30 00:00:00", + "2057-10-01 00:00:00", + "2057-10-02 00:00:00", + "2057-10-03 00:00:00", + "2057-10-04 00:00:00", + "2057-10-05 00:00:00", + "2057-10-06 00:00:00", + "2057-10-07 00:00:00", + "2057-10-14 00:00:00", + "2057-10-20 00:00:00", + "2057-10-21 00:00:00", + "2057-10-27 00:00:00", + "2057-10-28 00:00:00", + "2057-11-03 00:00:00", + "2057-11-04 00:00:00", + "2057-11-10 00:00:00", + "2057-11-11 00:00:00", + "2057-11-17 00:00:00", + "2057-11-18 00:00:00", + "2057-11-24 00:00:00", + "2057-11-25 00:00:00", + "2057-12-01 00:00:00", + "2057-12-02 00:00:00", + "2057-12-08 00:00:00", + "2057-12-09 00:00:00", + "2057-12-15 00:00:00", + "2057-12-16 00:00:00", + "2057-12-22 00:00:00", + "2057-12-23 00:00:00", + "2057-12-30 00:00:00", + "2057-12-31 00:00:00", + "2058-01-01 00:00:00", + "2058-01-05 00:00:00", + "2058-01-06 00:00:00", + "2058-01-12 00:00:00", + "2058-01-13 00:00:00", + "2058-01-19 00:00:00", + "2058-01-23 00:00:00", + "2058-01-24 00:00:00", + "2058-01-25 00:00:00", + "2058-01-26 00:00:00", + "2058-01-27 00:00:00", + "2058-01-28 00:00:00", + "2058-01-29 00:00:00", + "2058-01-30 00:00:00", + "2058-02-03 00:00:00", + "2058-02-09 00:00:00", + "2058-02-10 00:00:00", + "2058-02-16 00:00:00", + "2058-02-17 00:00:00", + "2058-02-23 00:00:00", + "2058-02-24 00:00:00", + "2058-03-02 00:00:00", + "2058-03-03 00:00:00", + "2058-03-09 00:00:00", + "2058-03-10 00:00:00", + "2058-03-16 00:00:00", + "2058-03-17 00:00:00", + "2058-03-23 00:00:00", + "2058-03-24 00:00:00", + "2058-03-30 00:00:00", + "2058-03-31 00:00:00", + "2058-04-04 00:00:00", + "2058-04-05 00:00:00", + "2058-04-06 00:00:00", + "2058-04-07 00:00:00", + "2058-04-13 00:00:00", + "2058-04-20 00:00:00", + "2058-04-21 00:00:00", + "2058-04-27 00:00:00", + "2058-04-28 00:00:00", + "2058-05-01 00:00:00", + "2058-05-02 00:00:00", + "2058-05-04 00:00:00", + "2058-05-05 00:00:00", + "2058-05-11 00:00:00", + "2058-05-12 00:00:00", + "2058-05-18 00:00:00", + "2058-05-19 00:00:00", + "2058-05-25 00:00:00", + "2058-05-26 00:00:00", + "2058-06-01 00:00:00", + "2058-06-02 00:00:00", + "2058-06-08 00:00:00", + "2058-06-09 00:00:00", + "2058-06-15 00:00:00", + "2058-06-22 00:00:00", + "2058-06-23 00:00:00", + "2058-06-24 00:00:00", + "2058-06-25 00:00:00", + "2058-06-29 00:00:00", + "2058-06-30 00:00:00", + "2058-07-06 00:00:00", + "2058-07-07 00:00:00", + "2058-07-13 00:00:00", + "2058-07-14 00:00:00", + "2058-07-20 00:00:00", + "2058-07-21 00:00:00", + "2058-07-27 00:00:00", + "2058-07-28 00:00:00", + "2058-08-03 00:00:00", + "2058-08-04 00:00:00", + "2058-08-10 00:00:00", + "2058-08-11 00:00:00", + "2058-08-17 00:00:00", + "2058-08-18 00:00:00", + "2058-08-24 00:00:00", + "2058-08-25 00:00:00", + "2058-08-31 00:00:00", + "2058-09-01 00:00:00", + "2058-09-07 00:00:00", + "2058-09-08 00:00:00", + "2058-09-14 00:00:00", + "2058-09-15 00:00:00", + "2058-09-21 00:00:00", + "2058-09-22 00:00:00", + "2058-09-28 00:00:00", + "2058-10-01 00:00:00", + "2058-10-02 00:00:00", + "2058-10-03 00:00:00", + "2058-10-04 00:00:00", + "2058-10-05 00:00:00", + "2058-10-06 00:00:00", + "2058-10-07 00:00:00", + "2058-10-08 00:00:00", + "2058-10-13 00:00:00", + "2058-10-19 00:00:00", + "2058-10-20 00:00:00", + "2058-10-26 00:00:00", + "2058-10-27 00:00:00", + "2058-11-02 00:00:00", + "2058-11-03 00:00:00", + "2058-11-09 00:00:00", + "2058-11-10 00:00:00", + "2058-11-16 00:00:00", + "2058-11-17 00:00:00", + "2058-11-23 00:00:00", + "2058-11-24 00:00:00", + "2058-11-30 00:00:00", + "2058-12-01 00:00:00", + "2058-12-07 00:00:00", + "2058-12-08 00:00:00", + "2058-12-14 00:00:00", + "2058-12-15 00:00:00", + "2058-12-21 00:00:00", + "2058-12-22 00:00:00", + "2058-12-28 00:00:00", + "2058-12-29 00:00:00", + "2059-01-01 00:00:00", + "2059-01-04 00:00:00", + "2059-01-05 00:00:00", + "2059-01-11 00:00:00", + "2059-01-12 00:00:00", + "2059-01-18 00:00:00", + "2059-01-19 00:00:00", + "2059-01-25 00:00:00", + "2059-01-26 00:00:00", + "2059-02-01 00:00:00", + "2059-02-02 00:00:00", + "2059-02-08 00:00:00", + "2059-02-11 00:00:00", + "2059-02-12 00:00:00", + "2059-02-13 00:00:00", + "2059-02-14 00:00:00", + "2059-02-15 00:00:00", + "2059-02-16 00:00:00", + "2059-02-17 00:00:00", + "2059-02-18 00:00:00", + "2059-02-23 00:00:00", + "2059-03-01 00:00:00", + "2059-03-02 00:00:00", + "2059-03-08 00:00:00", + "2059-03-09 00:00:00", + "2059-03-15 00:00:00", + "2059-03-16 00:00:00", + "2059-03-22 00:00:00", + "2059-03-23 00:00:00", + "2059-03-29 00:00:00", + "2059-03-30 00:00:00", + "2059-04-04 00:00:00", + "2059-04-05 00:00:00", + "2059-04-06 00:00:00", + "2059-04-12 00:00:00", + "2059-04-13 00:00:00", + "2059-04-19 00:00:00", + "2059-04-20 00:00:00", + "2059-04-26 00:00:00", + "2059-05-01 00:00:00", + "2059-05-02 00:00:00", + "2059-05-03 00:00:00", + "2059-05-04 00:00:00", + "2059-05-05 00:00:00", + "2059-05-10 00:00:00", + "2059-05-11 00:00:00", + "2059-05-17 00:00:00", + "2059-05-18 00:00:00", + "2059-05-24 00:00:00", + "2059-05-25 00:00:00", + "2059-05-31 00:00:00", + "2059-06-01 00:00:00", + "2059-06-07 00:00:00", + "2059-06-08 00:00:00", + "2059-06-14 00:00:00", + "2059-06-15 00:00:00", + "2059-06-16 00:00:00", + "2059-06-21 00:00:00", + "2059-06-22 00:00:00", + "2059-06-28 00:00:00", + "2059-06-29 00:00:00", + "2059-07-05 00:00:00", + "2059-07-06 00:00:00", + "2059-07-12 00:00:00", + "2059-07-13 00:00:00", + "2059-07-19 00:00:00", + "2059-07-20 00:00:00", + "2059-07-26 00:00:00", + "2059-07-27 00:00:00", + "2059-08-02 00:00:00", + "2059-08-03 00:00:00", + "2059-08-09 00:00:00", + "2059-08-10 00:00:00", + "2059-08-16 00:00:00", + "2059-08-17 00:00:00", + "2059-08-23 00:00:00", + "2059-08-24 00:00:00", + "2059-08-30 00:00:00", + "2059-08-31 00:00:00", + "2059-09-06 00:00:00", + "2059-09-07 00:00:00", + "2059-09-13 00:00:00", + "2059-09-14 00:00:00", + "2059-09-20 00:00:00", + "2059-09-21 00:00:00", + "2059-09-22 00:00:00", + "2059-09-27 00:00:00", + "2059-10-01 00:00:00", + "2059-10-02 00:00:00", + "2059-10-03 00:00:00", + "2059-10-04 00:00:00", + "2059-10-05 00:00:00", + "2059-10-06 00:00:00", + "2059-10-07 00:00:00", + "2059-10-12 00:00:00", + "2059-10-18 00:00:00", + "2059-10-19 00:00:00", + "2059-10-25 00:00:00", + "2059-10-26 00:00:00", + "2059-11-01 00:00:00", + "2059-11-02 00:00:00", + "2059-11-08 00:00:00", + "2059-11-09 00:00:00", + "2059-11-15 00:00:00", + "2059-11-16 00:00:00", + "2059-11-22 00:00:00", + "2059-11-23 00:00:00", + "2059-11-29 00:00:00", + "2059-11-30 00:00:00", + "2059-12-06 00:00:00", + "2059-12-07 00:00:00", + "2059-12-13 00:00:00", + "2059-12-14 00:00:00", + "2059-12-20 00:00:00", + "2059-12-21 00:00:00", + "2059-12-27 00:00:00", + "2059-12-28 00:00:00", + "2060-01-01 00:00:00", + "2060-01-02 00:00:00", + "2060-01-03 00:00:00", + "2060-01-10 00:00:00", + "2060-01-11 00:00:00", + "2060-01-17 00:00:00", + "2060-01-18 00:00:00", + "2060-01-24 00:00:00", + "2060-01-25 00:00:00", + "2060-02-01 00:00:00", + "2060-02-02 00:00:00", + "2060-02-03 00:00:00", + "2060-02-04 00:00:00", + "2060-02-05 00:00:00", + "2060-02-06 00:00:00", + "2060-02-07 00:00:00", + "2060-02-08 00:00:00", + "2060-02-15 00:00:00", + "2060-02-21 00:00:00", + "2060-02-22 00:00:00", + "2060-02-28 00:00:00", + "2060-02-29 00:00:00", + "2060-03-06 00:00:00", + "2060-03-07 00:00:00", + "2060-03-13 00:00:00", + "2060-03-14 00:00:00", + "2060-03-20 00:00:00", + "2060-03-21 00:00:00", + "2060-03-27 00:00:00", + "2060-03-28 00:00:00", + "2060-04-03 00:00:00", + "2060-04-04 00:00:00", + "2060-04-05 00:00:00", + "2060-04-10 00:00:00", + "2060-04-11 00:00:00", + "2060-04-17 00:00:00", + "2060-04-18 00:00:00", + "2060-04-24 00:00:00", + "2060-04-25 00:00:00", + "2060-05-01 00:00:00", + "2060-05-02 00:00:00", + "2060-05-03 00:00:00", + "2060-05-04 00:00:00", + "2060-05-05 00:00:00", + "2060-05-08 00:00:00", + "2060-05-15 00:00:00", + "2060-05-16 00:00:00", + "2060-05-22 00:00:00", + "2060-05-23 00:00:00", + "2060-05-29 00:00:00", + "2060-05-30 00:00:00", + "2060-06-03 00:00:00", + "2060-06-04 00:00:00", + "2060-06-05 00:00:00", + "2060-06-06 00:00:00", + "2060-06-12 00:00:00", + "2060-06-19 00:00:00", + "2060-06-20 00:00:00", + "2060-06-26 00:00:00", + "2060-06-27 00:00:00", + "2060-07-03 00:00:00", + "2060-07-04 00:00:00", + "2060-07-10 00:00:00", + "2060-07-11 00:00:00", + "2060-07-17 00:00:00", + "2060-07-18 00:00:00", + "2060-07-24 00:00:00", + "2060-07-25 00:00:00", + "2060-07-31 00:00:00", + "2060-08-01 00:00:00", + "2060-08-07 00:00:00", + "2060-08-08 00:00:00", + "2060-08-14 00:00:00", + "2060-08-15 00:00:00", + "2060-08-21 00:00:00", + "2060-08-22 00:00:00", + "2060-08-28 00:00:00", + "2060-08-29 00:00:00", + "2060-09-04 00:00:00", + "2060-09-05 00:00:00", + "2060-09-09 00:00:00", + "2060-09-10 00:00:00", + "2060-09-11 00:00:00", + "2060-09-12 00:00:00", + "2060-09-18 00:00:00", + "2060-09-25 00:00:00", + "2060-10-01 00:00:00", + "2060-10-02 00:00:00", + "2060-10-03 00:00:00", + "2060-10-04 00:00:00", + "2060-10-05 00:00:00", + "2060-10-06 00:00:00", + "2060-10-07 00:00:00", + "2060-10-10 00:00:00", + "2060-10-16 00:00:00", + "2060-10-17 00:00:00", + "2060-10-23 00:00:00", + "2060-10-24 00:00:00", + "2060-10-30 00:00:00", + "2060-10-31 00:00:00", + "2060-11-06 00:00:00", + "2060-11-07 00:00:00", + "2060-11-13 00:00:00", + "2060-11-14 00:00:00", + "2060-11-20 00:00:00", + "2060-11-21 00:00:00", + "2060-11-27 00:00:00", + "2060-11-28 00:00:00", + "2060-12-04 00:00:00", + "2060-12-05 00:00:00", + "2060-12-11 00:00:00", + "2060-12-12 00:00:00", + "2060-12-18 00:00:00", + "2060-12-19 00:00:00", + "2060-12-25 00:00:00", + "2060-12-26 00:00:00", + "2061-01-01 00:00:00", + "2061-01-02 00:00:00", + "2061-01-03 00:00:00", + "2061-01-08 00:00:00", + "2061-01-09 00:00:00", + "2061-01-15 00:00:00", + "2061-01-20 00:00:00", + "2061-01-21 00:00:00", + "2061-01-22 00:00:00", + "2061-01-23 00:00:00", + "2061-01-24 00:00:00", + "2061-01-25 00:00:00", + "2061-01-26 00:00:00", + "2061-01-27 00:00:00", + "2061-01-30 00:00:00", + "2061-02-05 00:00:00", + "2061-02-06 00:00:00", + "2061-02-12 00:00:00", + "2061-02-13 00:00:00", + "2061-02-19 00:00:00", + "2061-02-20 00:00:00", + "2061-02-26 00:00:00", + "2061-02-27 00:00:00", + "2061-03-05 00:00:00", + "2061-03-06 00:00:00", + "2061-03-12 00:00:00", + "2061-03-13 00:00:00", + "2061-03-19 00:00:00", + "2061-03-20 00:00:00", + "2061-03-26 00:00:00", + "2061-03-27 00:00:00", + "2061-04-02 00:00:00", + "2061-04-03 00:00:00", + "2061-04-04 00:00:00", + "2061-04-09 00:00:00", + "2061-04-10 00:00:00", + "2061-04-16 00:00:00", + "2061-04-17 00:00:00", + "2061-04-23 00:00:00", + "2061-04-24 00:00:00", + "2061-04-30 00:00:00", + "2061-05-01 00:00:00", + "2061-05-02 00:00:00", + "2061-05-03 00:00:00", + "2061-05-04 00:00:00", + "2061-05-07 00:00:00", + "2061-05-14 00:00:00", + "2061-05-15 00:00:00", + "2061-05-21 00:00:00", + "2061-05-22 00:00:00", + "2061-05-28 00:00:00", + "2061-05-29 00:00:00", + "2061-06-04 00:00:00", + "2061-06-05 00:00:00", + "2061-06-11 00:00:00", + "2061-06-12 00:00:00", + "2061-06-18 00:00:00", + "2061-06-19 00:00:00", + "2061-06-22 00:00:00", + "2061-06-25 00:00:00", + "2061-06-26 00:00:00", + "2061-07-02 00:00:00", + "2061-07-03 00:00:00", + "2061-07-09 00:00:00", + "2061-07-10 00:00:00", + "2061-07-16 00:00:00", + "2061-07-17 00:00:00", + "2061-07-23 00:00:00", + "2061-07-24 00:00:00", + "2061-07-30 00:00:00", + "2061-07-31 00:00:00", + "2061-08-06 00:00:00", + "2061-08-07 00:00:00", + "2061-08-13 00:00:00", + "2061-08-14 00:00:00", + "2061-08-20 00:00:00", + "2061-08-21 00:00:00", + "2061-08-27 00:00:00", + "2061-08-28 00:00:00", + "2061-09-03 00:00:00", + "2061-09-04 00:00:00", + "2061-09-10 00:00:00", + "2061-09-11 00:00:00", + "2061-09-17 00:00:00", + "2061-09-18 00:00:00", + "2061-09-24 00:00:00", + "2061-09-28 00:00:00", + "2061-10-01 00:00:00", + "2061-10-02 00:00:00", + "2061-10-03 00:00:00", + "2061-10-04 00:00:00", + "2061-10-05 00:00:00", + "2061-10-06 00:00:00", + "2061-10-07 00:00:00", + "2061-10-08 00:00:00", + "2061-10-15 00:00:00", + "2061-10-16 00:00:00", + "2061-10-22 00:00:00", + "2061-10-23 00:00:00", + "2061-10-29 00:00:00", + "2061-10-30 00:00:00", + "2061-11-05 00:00:00", + "2061-11-06 00:00:00", + "2061-11-12 00:00:00", + "2061-11-13 00:00:00", + "2061-11-19 00:00:00", + "2061-11-20 00:00:00", + "2061-11-26 00:00:00", + "2061-11-27 00:00:00", + "2061-12-03 00:00:00", + "2061-12-04 00:00:00", + "2061-12-10 00:00:00", + "2061-12-11 00:00:00", + "2061-12-17 00:00:00", + "2061-12-18 00:00:00", + "2061-12-24 00:00:00", + "2061-12-25 00:00:00", + "2061-12-31 00:00:00", + "2062-01-01 00:00:00", + "2062-01-02 00:00:00", + "2062-01-07 00:00:00", + "2062-01-08 00:00:00", + "2062-01-14 00:00:00", + "2062-01-15 00:00:00", + "2062-01-21 00:00:00", + "2062-01-22 00:00:00", + "2062-01-28 00:00:00", + "2062-01-29 00:00:00", + "2062-02-04 00:00:00", + "2062-02-08 00:00:00", + "2062-02-09 00:00:00", + "2062-02-10 00:00:00", + "2062-02-11 00:00:00", + "2062-02-12 00:00:00", + "2062-02-13 00:00:00", + "2062-02-14 00:00:00", + "2062-02-15 00:00:00", + "2062-02-19 00:00:00", + "2062-02-25 00:00:00", + "2062-02-26 00:00:00", + "2062-03-04 00:00:00", + "2062-03-05 00:00:00", + "2062-03-11 00:00:00", + "2062-03-12 00:00:00", + "2062-03-18 00:00:00", + "2062-03-19 00:00:00", + "2062-03-25 00:00:00", + "2062-04-01 00:00:00", + "2062-04-02 00:00:00", + "2062-04-03 00:00:00", + "2062-04-04 00:00:00", + "2062-04-08 00:00:00", + "2062-04-09 00:00:00", + "2062-04-15 00:00:00", + "2062-04-16 00:00:00", + "2062-04-22 00:00:00", + "2062-04-23 00:00:00", + "2062-04-29 00:00:00", + "2062-04-30 00:00:00", + "2062-05-01 00:00:00", + "2062-05-02 00:00:00", + "2062-05-03 00:00:00", + "2062-05-06 00:00:00", + "2062-05-13 00:00:00", + "2062-05-14 00:00:00", + "2062-05-20 00:00:00", + "2062-05-21 00:00:00", + "2062-05-27 00:00:00", + "2062-05-28 00:00:00", + "2062-06-03 00:00:00", + "2062-06-04 00:00:00", + "2062-06-10 00:00:00", + "2062-06-11 00:00:00", + "2062-06-12 00:00:00", + "2062-06-17 00:00:00", + "2062-06-18 00:00:00", + "2062-06-24 00:00:00", + "2062-06-25 00:00:00", + "2062-07-01 00:00:00", + "2062-07-02 00:00:00", + "2062-07-08 00:00:00", + "2062-07-09 00:00:00", + "2062-07-15 00:00:00", + "2062-07-16 00:00:00", + "2062-07-22 00:00:00", + "2062-07-23 00:00:00", + "2062-07-29 00:00:00", + "2062-07-30 00:00:00", + "2062-08-05 00:00:00", + "2062-08-06 00:00:00", + "2062-08-12 00:00:00", + "2062-08-13 00:00:00", + "2062-08-19 00:00:00", + "2062-08-20 00:00:00", + "2062-08-26 00:00:00", + "2062-08-27 00:00:00", + "2062-09-02 00:00:00", + "2062-09-03 00:00:00", + "2062-09-09 00:00:00", + "2062-09-10 00:00:00", + "2062-09-16 00:00:00", + "2062-09-17 00:00:00", + "2062-09-18 00:00:00", + "2062-09-23 00:00:00", + "2062-09-30 00:00:00", + "2062-10-01 00:00:00", + "2062-10-02 00:00:00", + "2062-10-03 00:00:00", + "2062-10-04 00:00:00", + "2062-10-05 00:00:00", + "2062-10-06 00:00:00", + "2062-10-07 00:00:00", + "2062-10-14 00:00:00", + "2062-10-15 00:00:00", + "2062-10-21 00:00:00", + "2062-10-22 00:00:00", + "2062-10-28 00:00:00", + "2062-10-29 00:00:00", + "2062-11-04 00:00:00", + "2062-11-05 00:00:00", + "2062-11-11 00:00:00", + "2062-11-12 00:00:00", + "2062-11-18 00:00:00", + "2062-11-19 00:00:00", + "2062-11-25 00:00:00", + "2062-11-26 00:00:00", + "2062-12-02 00:00:00", + "2062-12-03 00:00:00", + "2062-12-09 00:00:00", + "2062-12-10 00:00:00", + "2062-12-16 00:00:00", + "2062-12-17 00:00:00", + "2062-12-23 00:00:00", + "2062-12-24 00:00:00", + "2062-12-30 00:00:00", + "2062-12-31 00:00:00", + "2063-01-01 00:00:00", + "2063-01-06 00:00:00", + "2063-01-07 00:00:00", + "2063-01-13 00:00:00", + "2063-01-14 00:00:00", + "2063-01-20 00:00:00", + "2063-01-21 00:00:00", + "2063-01-28 00:00:00", + "2063-01-29 00:00:00", + "2063-01-30 00:00:00", + "2063-01-31 00:00:00", + "2063-02-01 00:00:00", + "2063-02-02 00:00:00", + "2063-02-03 00:00:00", + "2063-02-04 00:00:00", + "2063-02-11 00:00:00", + "2063-02-17 00:00:00", + "2063-02-18 00:00:00", + "2063-02-24 00:00:00", + "2063-02-25 00:00:00", + "2063-03-03 00:00:00", + "2063-03-04 00:00:00", + "2063-03-10 00:00:00", + "2063-03-11 00:00:00", + "2063-03-17 00:00:00", + "2063-03-18 00:00:00", + "2063-03-24 00:00:00", + "2063-03-25 00:00:00", + "2063-03-31 00:00:00", + "2063-04-01 00:00:00", + "2063-04-04 00:00:00", + "2063-04-07 00:00:00", + "2063-04-08 00:00:00", + "2063-04-14 00:00:00", + "2063-04-15 00:00:00", + "2063-04-21 00:00:00", + "2063-04-22 00:00:00", + "2063-04-28 00:00:00", + "2063-04-29 00:00:00", + "2063-04-30 00:00:00", + "2063-05-01 00:00:00", + "2063-05-02 00:00:00", + "2063-05-05 00:00:00", + "2063-05-06 00:00:00", + "2063-05-12 00:00:00", + "2063-05-13 00:00:00", + "2063-05-19 00:00:00", + "2063-05-20 00:00:00", + "2063-05-26 00:00:00", + "2063-05-27 00:00:00", + "2063-06-01 00:00:00", + "2063-06-02 00:00:00", + "2063-06-03 00:00:00", + "2063-06-09 00:00:00", + "2063-06-10 00:00:00", + "2063-06-16 00:00:00", + "2063-06-17 00:00:00", + "2063-06-23 00:00:00", + "2063-06-24 00:00:00", + "2063-06-30 00:00:00", + "2063-07-01 00:00:00", + "2063-07-07 00:00:00", + "2063-07-08 00:00:00", + "2063-07-14 00:00:00", + "2063-07-15 00:00:00", + "2063-07-21 00:00:00", + "2063-07-22 00:00:00", + "2063-07-28 00:00:00", + "2063-07-29 00:00:00", + "2063-08-04 00:00:00", + "2063-08-05 00:00:00", + "2063-08-11 00:00:00", + "2063-08-12 00:00:00", + "2063-08-18 00:00:00", + "2063-08-19 00:00:00", + "2063-08-25 00:00:00", + "2063-08-26 00:00:00", + "2063-09-01 00:00:00", + "2063-09-02 00:00:00", + "2063-09-08 00:00:00", + "2063-09-09 00:00:00", + "2063-09-15 00:00:00", + "2063-09-16 00:00:00", + "2063-09-22 00:00:00", + "2063-09-23 00:00:00", + "2063-09-30 00:00:00", + "2063-10-01 00:00:00", + "2063-10-02 00:00:00", + "2063-10-03 00:00:00", + "2063-10-04 00:00:00", + "2063-10-05 00:00:00", + "2063-10-06 00:00:00", + "2063-10-07 00:00:00", + "2063-10-08 00:00:00", + "2063-10-14 00:00:00", + "2063-10-20 00:00:00", + "2063-10-21 00:00:00", + "2063-10-27 00:00:00", + "2063-10-28 00:00:00", + "2063-11-03 00:00:00", + "2063-11-04 00:00:00", + "2063-11-10 00:00:00", + "2063-11-11 00:00:00", + "2063-11-17 00:00:00", + "2063-11-18 00:00:00", + "2063-11-24 00:00:00", + "2063-11-25 00:00:00", + "2063-12-01 00:00:00", + "2063-12-02 00:00:00", + "2063-12-08 00:00:00", + "2063-12-09 00:00:00", + "2063-12-15 00:00:00", + "2063-12-16 00:00:00", + "2063-12-22 00:00:00", + "2063-12-23 00:00:00", + "2063-12-30 00:00:00", + "2063-12-31 00:00:00", + "2064-01-01 00:00:00", + "2064-01-05 00:00:00", + "2064-01-06 00:00:00", + "2064-01-12 00:00:00", + "2064-01-13 00:00:00", + "2064-01-19 00:00:00", + "2064-01-20 00:00:00", + "2064-01-26 00:00:00", + "2064-01-27 00:00:00", + "2064-02-02 00:00:00", + "2064-02-03 00:00:00", + "2064-02-09 00:00:00", + "2064-02-16 00:00:00", + "2064-02-17 00:00:00", + "2064-02-18 00:00:00", + "2064-02-19 00:00:00", + "2064-02-20 00:00:00", + "2064-02-21 00:00:00", + "2064-02-22 00:00:00", + "2064-02-23 00:00:00", + "2064-03-01 00:00:00", + "2064-03-02 00:00:00", + "2064-03-08 00:00:00", + "2064-03-09 00:00:00", + "2064-03-15 00:00:00", + "2064-03-16 00:00:00", + "2064-03-22 00:00:00", + "2064-03-23 00:00:00", + "2064-03-29 00:00:00", + "2064-03-30 00:00:00", + "2064-04-03 00:00:00", + "2064-04-04 00:00:00", + "2064-04-05 00:00:00", + "2064-04-06 00:00:00", + "2064-04-12 00:00:00", + "2064-04-19 00:00:00", + "2064-04-20 00:00:00", + "2064-04-26 00:00:00", + "2064-05-01 00:00:00", + "2064-05-02 00:00:00", + "2064-05-03 00:00:00", + "2064-05-04 00:00:00", + "2064-05-05 00:00:00", + "2064-05-10 00:00:00", + "2064-05-11 00:00:00", + "2064-05-17 00:00:00", + "2064-05-18 00:00:00", + "2064-05-24 00:00:00", + "2064-05-25 00:00:00", + "2064-05-31 00:00:00", + "2064-06-01 00:00:00", + "2064-06-07 00:00:00", + "2064-06-08 00:00:00", + "2064-06-14 00:00:00", + "2064-06-15 00:00:00", + "2064-06-19 00:00:00", + "2064-06-20 00:00:00", + "2064-06-21 00:00:00", + "2064-06-22 00:00:00", + "2064-06-28 00:00:00", + "2064-07-05 00:00:00", + "2064-07-06 00:00:00", + "2064-07-12 00:00:00", + "2064-07-13 00:00:00", + "2064-07-19 00:00:00", + "2064-07-20 00:00:00", + "2064-07-26 00:00:00", + "2064-07-27 00:00:00", + "2064-08-02 00:00:00", + "2064-08-03 00:00:00", + "2064-08-09 00:00:00", + "2064-08-10 00:00:00", + "2064-08-16 00:00:00", + "2064-08-17 00:00:00", + "2064-08-23 00:00:00", + "2064-08-24 00:00:00", + "2064-08-30 00:00:00", + "2064-08-31 00:00:00", + "2064-09-06 00:00:00", + "2064-09-07 00:00:00", + "2064-09-13 00:00:00", + "2064-09-14 00:00:00", + "2064-09-20 00:00:00", + "2064-09-21 00:00:00", + "2064-09-25 00:00:00", + "2064-09-26 00:00:00", + "2064-09-27 00:00:00", + "2064-10-01 00:00:00", + "2064-10-02 00:00:00", + "2064-10-03 00:00:00", + "2064-10-04 00:00:00", + "2064-10-05 00:00:00", + "2064-10-06 00:00:00", + "2064-10-07 00:00:00", + "2064-10-12 00:00:00", + "2064-10-18 00:00:00", + "2064-10-19 00:00:00", + "2064-10-25 00:00:00", + "2064-10-26 00:00:00", + "2064-11-01 00:00:00", + "2064-11-02 00:00:00", + "2064-11-08 00:00:00", + "2064-11-09 00:00:00", + "2064-11-15 00:00:00", + "2064-11-16 00:00:00", + "2064-11-22 00:00:00", + "2064-11-23 00:00:00", + "2064-11-29 00:00:00", + "2064-11-30 00:00:00", + "2064-12-06 00:00:00", + "2064-12-07 00:00:00", + "2064-12-13 00:00:00", + "2064-12-14 00:00:00", + "2064-12-20 00:00:00", + "2064-12-21 00:00:00", + "2064-12-27 00:00:00", + "2064-12-28 00:00:00", + "2065-01-01 00:00:00", + "2065-01-02 00:00:00", + "2065-01-03 00:00:00", + "2065-01-10 00:00:00", + "2065-01-11 00:00:00", + "2065-01-17 00:00:00", + "2065-01-18 00:00:00", + "2065-01-24 00:00:00", + "2065-01-25 00:00:00", + "2065-01-31 00:00:00", + "2065-02-04 00:00:00", + "2065-02-05 00:00:00", + "2065-02-06 00:00:00", + "2065-02-07 00:00:00", + "2065-02-08 00:00:00", + "2065-02-09 00:00:00", + "2065-02-10 00:00:00", + "2065-02-11 00:00:00", + "2065-02-15 00:00:00", + "2065-02-21 00:00:00", + "2065-02-22 00:00:00", + "2065-02-28 00:00:00", + "2065-03-01 00:00:00", + "2065-03-07 00:00:00", + "2065-03-08 00:00:00", + "2065-03-14 00:00:00", + "2065-03-15 00:00:00", + "2065-03-21 00:00:00", + "2065-03-22 00:00:00", + "2065-03-28 00:00:00", + "2065-03-29 00:00:00", + "2065-04-04 00:00:00", + "2065-04-05 00:00:00", + "2065-04-06 00:00:00", + "2065-04-11 00:00:00", + "2065-04-12 00:00:00", + "2065-04-18 00:00:00", + "2065-04-19 00:00:00", + "2065-04-25 00:00:00", + "2065-04-26 00:00:00", + "2065-05-01 00:00:00", + "2065-05-02 00:00:00", + "2065-05-03 00:00:00", + "2065-05-04 00:00:00", + "2065-05-05 00:00:00", + "2065-05-10 00:00:00", + "2065-05-16 00:00:00", + "2065-05-17 00:00:00", + "2065-05-23 00:00:00", + "2065-05-24 00:00:00", + "2065-05-30 00:00:00", + "2065-05-31 00:00:00", + "2065-06-06 00:00:00", + "2065-06-07 00:00:00", + "2065-06-08 00:00:00", + "2065-06-13 00:00:00", + "2065-06-14 00:00:00", + "2065-06-20 00:00:00", + "2065-06-21 00:00:00", + "2065-06-27 00:00:00", + "2065-06-28 00:00:00", + "2065-07-04 00:00:00", + "2065-07-05 00:00:00", + "2065-07-11 00:00:00", + "2065-07-12 00:00:00", + "2065-07-18 00:00:00", + "2065-07-19 00:00:00", + "2065-07-25 00:00:00", + "2065-07-26 00:00:00", + "2065-08-01 00:00:00", + "2065-08-02 00:00:00", + "2065-08-08 00:00:00", + "2065-08-09 00:00:00", + "2065-08-15 00:00:00", + "2065-08-16 00:00:00", + "2065-08-22 00:00:00", + "2065-08-23 00:00:00", + "2065-08-29 00:00:00", + "2065-08-30 00:00:00", + "2065-09-05 00:00:00", + "2065-09-12 00:00:00", + "2065-09-13 00:00:00", + "2065-09-14 00:00:00", + "2065-09-15 00:00:00", + "2065-09-19 00:00:00", + "2065-09-20 00:00:00", + "2065-09-26 00:00:00", + "2065-10-01 00:00:00", + "2065-10-02 00:00:00", + "2065-10-03 00:00:00", + "2065-10-04 00:00:00", + "2065-10-05 00:00:00", + "2065-10-06 00:00:00", + "2065-10-07 00:00:00", + "2065-10-11 00:00:00", + "2065-10-17 00:00:00", + "2065-10-18 00:00:00", + "2065-10-24 00:00:00", + "2065-10-25 00:00:00", + "2065-10-31 00:00:00", + "2065-11-01 00:00:00", + "2065-11-07 00:00:00", + "2065-11-08 00:00:00", + "2065-11-14 00:00:00", + "2065-11-15 00:00:00", + "2065-11-21 00:00:00", + "2065-11-22 00:00:00", + "2065-11-28 00:00:00", + "2065-11-29 00:00:00", + "2065-12-05 00:00:00", + "2065-12-06 00:00:00", + "2065-12-12 00:00:00", + "2065-12-13 00:00:00", + "2065-12-19 00:00:00", + "2065-12-20 00:00:00", + "2065-12-26 00:00:00", + "2065-12-27 00:00:00", + "2066-01-01 00:00:00", + "2066-01-02 00:00:00", + "2066-01-03 00:00:00", + "2066-01-09 00:00:00", + "2066-01-10 00:00:00", + "2066-01-16 00:00:00", + "2066-01-17 00:00:00", + "2066-01-24 00:00:00", + "2066-01-25 00:00:00", + "2066-01-26 00:00:00", + "2066-01-27 00:00:00", + "2066-01-28 00:00:00", + "2066-01-29 00:00:00", + "2066-01-30 00:00:00", + "2066-01-31 00:00:00", + "2066-02-01 00:00:00", + "2066-02-07 00:00:00", + "2066-02-13 00:00:00", + "2066-02-14 00:00:00", + "2066-02-20 00:00:00", + "2066-02-21 00:00:00", + "2066-02-27 00:00:00", + "2066-02-28 00:00:00", + "2066-03-06 00:00:00", + "2066-03-07 00:00:00", + "2066-03-13 00:00:00", + "2066-03-14 00:00:00", + "2066-03-20 00:00:00", + "2066-03-21 00:00:00", + "2066-03-27 00:00:00", + "2066-03-28 00:00:00", + "2066-04-03 00:00:00", + "2066-04-04 00:00:00", + "2066-04-05 00:00:00", + "2066-04-10 00:00:00", + "2066-04-11 00:00:00", + "2066-04-17 00:00:00", + "2066-04-18 00:00:00", + "2066-04-24 00:00:00", + "2066-04-25 00:00:00", + "2066-05-01 00:00:00", + "2066-05-02 00:00:00", + "2066-05-03 00:00:00", + "2066-05-04 00:00:00", + "2066-05-05 00:00:00", + "2066-05-08 00:00:00", + "2066-05-15 00:00:00", + "2066-05-16 00:00:00", + "2066-05-22 00:00:00", + "2066-05-23 00:00:00", + "2066-05-28 00:00:00", + "2066-05-29 00:00:00", + "2066-05-30 00:00:00", + "2066-06-05 00:00:00", + "2066-06-06 00:00:00", + "2066-06-12 00:00:00", + "2066-06-13 00:00:00", + "2066-06-19 00:00:00", + "2066-06-20 00:00:00", + "2066-06-26 00:00:00", + "2066-06-27 00:00:00", + "2066-07-03 00:00:00", + "2066-07-04 00:00:00", + "2066-07-10 00:00:00", + "2066-07-11 00:00:00", + "2066-07-17 00:00:00", + "2066-07-18 00:00:00", + "2066-07-24 00:00:00", + "2066-07-25 00:00:00", + "2066-07-31 00:00:00", + "2066-08-01 00:00:00", + "2066-08-07 00:00:00", + "2066-08-08 00:00:00", + "2066-08-14 00:00:00", + "2066-08-15 00:00:00", + "2066-08-21 00:00:00", + "2066-08-22 00:00:00", + "2066-08-28 00:00:00", + "2066-08-29 00:00:00", + "2066-09-04 00:00:00", + "2066-09-05 00:00:00", + "2066-09-11 00:00:00", + "2066-09-12 00:00:00", + "2066-09-18 00:00:00", + "2066-09-19 00:00:00", + "2066-09-25 00:00:00", + "2066-10-01 00:00:00", + "2066-10-02 00:00:00", + "2066-10-03 00:00:00", + "2066-10-04 00:00:00", + "2066-10-05 00:00:00", + "2066-10-06 00:00:00", + "2066-10-07 00:00:00", + "2066-10-08 00:00:00", + "2066-10-10 00:00:00", + "2066-10-16 00:00:00", + "2066-10-17 00:00:00", + "2066-10-23 00:00:00", + "2066-10-24 00:00:00", + "2066-10-30 00:00:00", + "2066-10-31 00:00:00", + "2066-11-06 00:00:00", + "2066-11-07 00:00:00", + "2066-11-13 00:00:00", + "2066-11-14 00:00:00", + "2066-11-20 00:00:00", + "2066-11-21 00:00:00", + "2066-11-27 00:00:00", + "2066-11-28 00:00:00", + "2066-12-04 00:00:00", + "2066-12-05 00:00:00", + "2066-12-11 00:00:00", + "2066-12-12 00:00:00", + "2066-12-18 00:00:00", + "2066-12-19 00:00:00", + "2066-12-25 00:00:00", + "2066-12-26 00:00:00", + "2067-01-01 00:00:00", + "2067-01-02 00:00:00", + "2067-01-03 00:00:00", + "2067-01-08 00:00:00", + "2067-01-09 00:00:00", + "2067-01-15 00:00:00", + "2067-01-16 00:00:00", + "2067-01-22 00:00:00", + "2067-01-23 00:00:00", + "2067-01-29 00:00:00", + "2067-01-30 00:00:00", + "2067-02-05 00:00:00", + "2067-02-06 00:00:00", + "2067-02-13 00:00:00", + "2067-02-14 00:00:00", + "2067-02-15 00:00:00", + "2067-02-16 00:00:00", + "2067-02-17 00:00:00", + "2067-02-18 00:00:00", + "2067-02-19 00:00:00", + "2067-02-20 00:00:00", + "2067-02-27 00:00:00", + "2067-03-05 00:00:00", + "2067-03-06 00:00:00", + "2067-03-12 00:00:00", + "2067-03-13 00:00:00", + "2067-03-19 00:00:00", + "2067-03-20 00:00:00", + "2067-03-26 00:00:00", + "2067-03-27 00:00:00", + "2067-04-02 00:00:00", + "2067-04-03 00:00:00", + "2067-04-04 00:00:00", + "2067-04-09 00:00:00", + "2067-04-10 00:00:00", + "2067-04-16 00:00:00", + "2067-04-17 00:00:00", + "2067-04-23 00:00:00", + "2067-04-24 00:00:00", + "2067-04-30 00:00:00", + "2067-05-01 00:00:00", + "2067-05-02 00:00:00", + "2067-05-03 00:00:00", + "2067-05-04 00:00:00", + "2067-05-07 00:00:00", + "2067-05-14 00:00:00", + "2067-05-15 00:00:00", + "2067-05-21 00:00:00", + "2067-05-22 00:00:00", + "2067-05-28 00:00:00", + "2067-05-29 00:00:00", + "2067-06-04 00:00:00", + "2067-06-05 00:00:00", + "2067-06-11 00:00:00", + "2067-06-12 00:00:00", + "2067-06-16 00:00:00", + "2067-06-17 00:00:00", + "2067-06-18 00:00:00", + "2067-06-19 00:00:00", + "2067-06-25 00:00:00", + "2067-07-02 00:00:00", + "2067-07-03 00:00:00", + "2067-07-09 00:00:00", + "2067-07-10 00:00:00", + "2067-07-16 00:00:00", + "2067-07-17 00:00:00", + "2067-07-23 00:00:00", + "2067-07-24 00:00:00", + "2067-07-30 00:00:00", + "2067-07-31 00:00:00", + "2067-08-06 00:00:00", + "2067-08-07 00:00:00", + "2067-08-13 00:00:00", + "2067-08-14 00:00:00", + "2067-08-20 00:00:00", + "2067-08-21 00:00:00", + "2067-08-27 00:00:00", + "2067-08-28 00:00:00", + "2067-09-03 00:00:00", + "2067-09-04 00:00:00", + "2067-09-10 00:00:00", + "2067-09-11 00:00:00", + "2067-09-17 00:00:00", + "2067-09-23 00:00:00", + "2067-09-24 00:00:00", + "2067-09-25 00:00:00", + "2067-10-01 00:00:00", + "2067-10-02 00:00:00", + "2067-10-03 00:00:00", + "2067-10-04 00:00:00", + "2067-10-05 00:00:00", + "2067-10-06 00:00:00", + "2067-10-07 00:00:00", + "2067-10-08 00:00:00", + "2067-10-15 00:00:00", + "2067-10-16 00:00:00", + "2067-10-22 00:00:00", + "2067-10-23 00:00:00", + "2067-10-29 00:00:00", + "2067-10-30 00:00:00", + "2067-11-05 00:00:00", + "2067-11-06 00:00:00", + "2067-11-12 00:00:00", + "2067-11-13 00:00:00", + "2067-11-19 00:00:00", + "2067-11-20 00:00:00", + "2067-11-26 00:00:00", + "2067-11-27 00:00:00", + "2067-12-03 00:00:00", + "2067-12-04 00:00:00", + "2067-12-10 00:00:00", + "2067-12-11 00:00:00", + "2067-12-17 00:00:00", + "2067-12-18 00:00:00", + "2067-12-24 00:00:00", + "2067-12-25 00:00:00", + "2067-12-31 00:00:00", + "2068-01-01 00:00:00", + "2068-01-02 00:00:00", + "2068-01-07 00:00:00", + "2068-01-08 00:00:00", + "2068-01-14 00:00:00", + "2068-01-15 00:00:00", + "2068-01-21 00:00:00", + "2068-01-22 00:00:00", + "2068-01-28 00:00:00", + "2068-02-02 00:00:00", + "2068-02-03 00:00:00", + "2068-02-04 00:00:00", + "2068-02-05 00:00:00", + "2068-02-06 00:00:00", + "2068-02-07 00:00:00", + "2068-02-08 00:00:00", + "2068-02-09 00:00:00", + "2068-02-12 00:00:00", + "2068-02-18 00:00:00", + "2068-02-19 00:00:00", + "2068-02-25 00:00:00", + "2068-02-26 00:00:00", + "2068-03-03 00:00:00", + "2068-03-04 00:00:00", + "2068-03-10 00:00:00", + "2068-03-11 00:00:00", + "2068-03-17 00:00:00", + "2068-03-18 00:00:00", + "2068-03-24 00:00:00", + "2068-03-31 00:00:00", + "2068-04-01 00:00:00", + "2068-04-02 00:00:00", + "2068-04-03 00:00:00", + "2068-04-07 00:00:00", + "2068-04-08 00:00:00", + "2068-04-14 00:00:00", + "2068-04-15 00:00:00", + "2068-04-21 00:00:00", + "2068-04-22 00:00:00", + "2068-04-28 00:00:00", + "2068-04-29 00:00:00", + "2068-04-30 00:00:00", + "2068-05-01 00:00:00", + "2068-05-02 00:00:00", + "2068-05-05 00:00:00", + "2068-05-06 00:00:00", + "2068-05-12 00:00:00", + "2068-05-13 00:00:00", + "2068-05-19 00:00:00", + "2068-05-20 00:00:00", + "2068-05-26 00:00:00", + "2068-05-27 00:00:00", + "2068-06-02 00:00:00", + "2068-06-03 00:00:00", + "2068-06-04 00:00:00", + "2068-06-09 00:00:00", + "2068-06-10 00:00:00", + "2068-06-16 00:00:00", + "2068-06-17 00:00:00", + "2068-06-23 00:00:00", + "2068-06-24 00:00:00", + "2068-06-30 00:00:00", + "2068-07-01 00:00:00", + "2068-07-07 00:00:00", + "2068-07-08 00:00:00", + "2068-07-14 00:00:00", + "2068-07-15 00:00:00", + "2068-07-21 00:00:00", + "2068-07-22 00:00:00", + "2068-07-28 00:00:00", + "2068-07-29 00:00:00", + "2068-08-04 00:00:00", + "2068-08-05 00:00:00", + "2068-08-11 00:00:00", + "2068-08-12 00:00:00", + "2068-08-18 00:00:00", + "2068-08-19 00:00:00", + "2068-08-25 00:00:00", + "2068-08-26 00:00:00", + "2068-09-01 00:00:00", + "2068-09-08 00:00:00", + "2068-09-09 00:00:00", + "2068-09-10 00:00:00", + "2068-09-11 00:00:00", + "2068-09-15 00:00:00", + "2068-09-16 00:00:00", + "2068-09-22 00:00:00", + "2068-09-23 00:00:00", + "2068-09-30 00:00:00", + "2068-10-01 00:00:00", + "2068-10-02 00:00:00", + "2068-10-03 00:00:00", + "2068-10-04 00:00:00", + "2068-10-05 00:00:00", + "2068-10-06 00:00:00", + "2068-10-07 00:00:00", + "2068-10-14 00:00:00", + "2068-10-20 00:00:00", + "2068-10-21 00:00:00", + "2068-10-27 00:00:00", + "2068-10-28 00:00:00", + "2068-11-03 00:00:00", + "2068-11-04 00:00:00", + "2068-11-10 00:00:00", + "2068-11-11 00:00:00", + "2068-11-17 00:00:00", + "2068-11-18 00:00:00", + "2068-11-24 00:00:00", + "2068-11-25 00:00:00", + "2068-12-01 00:00:00", + "2068-12-02 00:00:00", + "2068-12-08 00:00:00", + "2068-12-09 00:00:00", + "2068-12-15 00:00:00", + "2068-12-16 00:00:00", + "2068-12-22 00:00:00", + "2068-12-23 00:00:00", + "2068-12-30 00:00:00", + "2068-12-31 00:00:00", + "2069-01-01 00:00:00", + "2069-01-05 00:00:00", + "2069-01-06 00:00:00", + "2069-01-12 00:00:00", + "2069-01-13 00:00:00", + "2069-01-19 00:00:00", + "2069-01-22 00:00:00", + "2069-01-23 00:00:00", + "2069-01-24 00:00:00", + "2069-01-25 00:00:00", + "2069-01-26 00:00:00", + "2069-01-27 00:00:00", + "2069-01-28 00:00:00", + "2069-01-29 00:00:00", + "2069-02-03 00:00:00", + "2069-02-09 00:00:00", + "2069-02-10 00:00:00", + "2069-02-16 00:00:00", + "2069-02-17 00:00:00", + "2069-02-23 00:00:00", + "2069-02-24 00:00:00", + "2069-03-02 00:00:00", + "2069-03-03 00:00:00", + "2069-03-09 00:00:00", + "2069-03-10 00:00:00", + "2069-03-16 00:00:00", + "2069-03-17 00:00:00", + "2069-03-23 00:00:00", + "2069-03-24 00:00:00", + "2069-03-30 00:00:00", + "2069-03-31 00:00:00", + "2069-04-04 00:00:00", + "2069-04-05 00:00:00", + "2069-04-06 00:00:00", + "2069-04-07 00:00:00", + "2069-04-13 00:00:00", + "2069-04-20 00:00:00", + "2069-04-21 00:00:00", + "2069-04-27 00:00:00", + "2069-04-28 00:00:00", + "2069-05-01 00:00:00", + "2069-05-02 00:00:00", + "2069-05-04 00:00:00", + "2069-05-05 00:00:00", + "2069-05-11 00:00:00", + "2069-05-12 00:00:00", + "2069-05-18 00:00:00", + "2069-05-19 00:00:00", + "2069-05-25 00:00:00", + "2069-05-26 00:00:00", + "2069-06-01 00:00:00", + "2069-06-02 00:00:00", + "2069-06-08 00:00:00", + "2069-06-09 00:00:00", + "2069-06-15 00:00:00", + "2069-06-16 00:00:00", + "2069-06-22 00:00:00", + "2069-06-23 00:00:00", + "2069-06-24 00:00:00", + "2069-06-29 00:00:00", + "2069-06-30 00:00:00", + "2069-07-06 00:00:00", + "2069-07-07 00:00:00", + "2069-07-13 00:00:00", + "2069-07-14 00:00:00", + "2069-07-20 00:00:00", + "2069-07-21 00:00:00", + "2069-07-27 00:00:00", + "2069-07-28 00:00:00", + "2069-08-03 00:00:00", + "2069-08-04 00:00:00", + "2069-08-10 00:00:00", + "2069-08-11 00:00:00", + "2069-08-17 00:00:00", + "2069-08-18 00:00:00", + "2069-08-24 00:00:00", + "2069-08-25 00:00:00", + "2069-08-31 00:00:00", + "2069-09-01 00:00:00", + "2069-09-07 00:00:00", + "2069-09-08 00:00:00", + "2069-09-14 00:00:00", + "2069-09-15 00:00:00", + "2069-09-21 00:00:00", + "2069-09-28 00:00:00", + "2069-09-29 00:00:00", + "2069-09-30 00:00:00", + "2069-10-01 00:00:00", + "2069-10-02 00:00:00", + "2069-10-03 00:00:00", + "2069-10-04 00:00:00", + "2069-10-05 00:00:00", + "2069-10-06 00:00:00", + "2069-10-07 00:00:00", + "2069-10-13 00:00:00", + "2069-10-19 00:00:00", + "2069-10-20 00:00:00", + "2069-10-26 00:00:00", + "2069-10-27 00:00:00", + "2069-11-02 00:00:00", + "2069-11-03 00:00:00", + "2069-11-09 00:00:00", + "2069-11-10 00:00:00", + "2069-11-16 00:00:00", + "2069-11-17 00:00:00", + "2069-11-23 00:00:00", + "2069-11-24 00:00:00", + "2069-11-30 00:00:00", + "2069-12-01 00:00:00", + "2069-12-07 00:00:00", + "2069-12-08 00:00:00", + "2069-12-14 00:00:00", + "2069-12-15 00:00:00", + "2069-12-21 00:00:00", + "2069-12-22 00:00:00", + "2069-12-28 00:00:00", + "2069-12-29 00:00:00", + "2070-01-01 00:00:00", + "2070-01-04 00:00:00", + "2070-01-05 00:00:00", + "2070-01-11 00:00:00", + "2070-01-12 00:00:00", + "2070-01-18 00:00:00", + "2070-01-19 00:00:00", + "2070-01-25 00:00:00", + "2070-01-26 00:00:00", + "2070-02-01 00:00:00", + "2070-02-02 00:00:00", + "2070-02-09 00:00:00", + "2070-02-10 00:00:00", + "2070-02-11 00:00:00", + "2070-02-12 00:00:00", + "2070-02-13 00:00:00", + "2070-02-14 00:00:00", + "2070-02-15 00:00:00", + "2070-02-16 00:00:00", + "2070-02-17 00:00:00", + "2070-02-23 00:00:00", + "2070-03-01 00:00:00", + "2070-03-02 00:00:00", + "2070-03-08 00:00:00", + "2070-03-09 00:00:00", + "2070-03-15 00:00:00", + "2070-03-16 00:00:00", + "2070-03-22 00:00:00", + "2070-03-23 00:00:00", + "2070-03-29 00:00:00", + "2070-03-30 00:00:00", + "2070-04-04 00:00:00", + "2070-04-05 00:00:00", + "2070-04-06 00:00:00", + "2070-04-12 00:00:00", + "2070-04-13 00:00:00", + "2070-04-19 00:00:00", + "2070-04-20 00:00:00", + "2070-04-26 00:00:00", + "2070-05-01 00:00:00", + "2070-05-02 00:00:00", + "2070-05-03 00:00:00", + "2070-05-04 00:00:00", + "2070-05-05 00:00:00", + "2070-05-10 00:00:00", + "2070-05-11 00:00:00", + "2070-05-17 00:00:00", + "2070-05-18 00:00:00", + "2070-05-24 00:00:00", + "2070-05-25 00:00:00", + "2070-05-31 00:00:00", + "2070-06-01 00:00:00", + "2070-06-07 00:00:00", + "2070-06-08 00:00:00", + "2070-06-13 00:00:00", + "2070-06-14 00:00:00", + "2070-06-15 00:00:00", + "2070-06-21 00:00:00", + "2070-06-22 00:00:00", + "2070-06-28 00:00:00", + "2070-06-29 00:00:00", + "2070-07-05 00:00:00", + "2070-07-06 00:00:00", + "2070-07-12 00:00:00", + "2070-07-13 00:00:00", + "2070-07-19 00:00:00", + "2070-07-20 00:00:00", + "2070-07-26 00:00:00", + "2070-07-27 00:00:00", + "2070-08-02 00:00:00", + "2070-08-03 00:00:00", + "2070-08-09 00:00:00", + "2070-08-10 00:00:00", + "2070-08-16 00:00:00", + "2070-08-17 00:00:00", + "2070-08-23 00:00:00", + "2070-08-24 00:00:00", + "2070-08-30 00:00:00", + "2070-08-31 00:00:00", + "2070-09-06 00:00:00", + "2070-09-07 00:00:00", + "2070-09-13 00:00:00", + "2070-09-14 00:00:00", + "2070-09-19 00:00:00", + "2070-09-20 00:00:00", + "2070-09-21 00:00:00", + "2070-09-27 00:00:00", + "2070-10-01 00:00:00", + "2070-10-02 00:00:00", + "2070-10-03 00:00:00", + "2070-10-04 00:00:00", + "2070-10-05 00:00:00", + "2070-10-06 00:00:00", + "2070-10-07 00:00:00", + "2070-10-12 00:00:00", + "2070-10-18 00:00:00", + "2070-10-19 00:00:00", + "2070-10-25 00:00:00", + "2070-10-26 00:00:00", + "2070-11-01 00:00:00", + "2070-11-02 00:00:00", + "2070-11-08 00:00:00", + "2070-11-09 00:00:00", + "2070-11-15 00:00:00", + "2070-11-16 00:00:00", + "2070-11-22 00:00:00", + "2070-11-23 00:00:00", + "2070-11-29 00:00:00", + "2070-11-30 00:00:00", + "2070-12-06 00:00:00", + "2070-12-07 00:00:00", + "2070-12-13 00:00:00", + "2070-12-14 00:00:00", + "2070-12-20 00:00:00", + "2070-12-21 00:00:00", + "2070-12-27 00:00:00", + "2070-12-28 00:00:00", + "2071-01-01 00:00:00", + "2071-01-02 00:00:00", + "2071-01-03 00:00:00", + "2071-01-10 00:00:00", + "2071-01-11 00:00:00", + "2071-01-17 00:00:00", + "2071-01-18 00:00:00", + "2071-01-24 00:00:00", + "2071-01-30 00:00:00", + "2071-01-31 00:00:00", + "2071-02-01 00:00:00", + "2071-02-02 00:00:00", + "2071-02-03 00:00:00", + "2071-02-04 00:00:00", + "2071-02-05 00:00:00", + "2071-02-06 00:00:00", + "2071-02-08 00:00:00", + "2071-02-14 00:00:00", + "2071-02-15 00:00:00", + "2071-02-21 00:00:00", + "2071-02-22 00:00:00", + "2071-02-28 00:00:00", + "2071-03-01 00:00:00", + "2071-03-07 00:00:00", + "2071-03-08 00:00:00", + "2071-03-14 00:00:00", + "2071-03-15 00:00:00", + "2071-03-21 00:00:00", + "2071-03-22 00:00:00", + "2071-03-28 00:00:00", + "2071-03-29 00:00:00", + "2071-04-04 00:00:00", + "2071-04-05 00:00:00", + "2071-04-06 00:00:00", + "2071-04-11 00:00:00", + "2071-04-12 00:00:00", + "2071-04-18 00:00:00", + "2071-04-19 00:00:00", + "2071-04-25 00:00:00", + "2071-04-26 00:00:00", + "2071-05-01 00:00:00", + "2071-05-02 00:00:00", + "2071-05-03 00:00:00", + "2071-05-04 00:00:00", + "2071-05-05 00:00:00", + "2071-05-10 00:00:00", + "2071-05-16 00:00:00", + "2071-05-17 00:00:00", + "2071-05-23 00:00:00", + "2071-05-30 00:00:00", + "2071-05-31 00:00:00", + "2071-06-01 00:00:00", + "2071-06-02 00:00:00", + "2071-06-06 00:00:00", + "2071-06-07 00:00:00", + "2071-06-13 00:00:00", + "2071-06-14 00:00:00", + "2071-06-20 00:00:00", + "2071-06-21 00:00:00", + "2071-06-27 00:00:00", + "2071-06-28 00:00:00", + "2071-07-04 00:00:00", + "2071-07-05 00:00:00", + "2071-07-11 00:00:00", + "2071-07-12 00:00:00", + "2071-07-18 00:00:00", + "2071-07-19 00:00:00", + "2071-07-25 00:00:00", + "2071-07-26 00:00:00", + "2071-08-01 00:00:00", + "2071-08-02 00:00:00", + "2071-08-08 00:00:00", + "2071-08-09 00:00:00", + "2071-08-15 00:00:00", + "2071-08-16 00:00:00", + "2071-08-22 00:00:00", + "2071-08-23 00:00:00", + "2071-08-29 00:00:00", + "2071-09-05 00:00:00", + "2071-09-06 00:00:00", + "2071-09-07 00:00:00", + "2071-09-08 00:00:00", + "2071-09-12 00:00:00", + "2071-09-13 00:00:00", + "2071-09-19 00:00:00", + "2071-09-20 00:00:00", + "2071-09-26 00:00:00", + "2071-10-01 00:00:00", + "2071-10-02 00:00:00", + "2071-10-03 00:00:00", + "2071-10-04 00:00:00", + "2071-10-05 00:00:00", + "2071-10-06 00:00:00", + "2071-10-07 00:00:00", + "2071-10-11 00:00:00", + "2071-10-17 00:00:00", + "2071-10-18 00:00:00", + "2071-10-24 00:00:00", + "2071-10-25 00:00:00", + "2071-10-31 00:00:00", + "2071-11-01 00:00:00", + "2071-11-07 00:00:00", + "2071-11-08 00:00:00", + "2071-11-14 00:00:00", + "2071-11-15 00:00:00", + "2071-11-21 00:00:00", + "2071-11-22 00:00:00", + "2071-11-28 00:00:00", + "2071-11-29 00:00:00", + "2071-12-05 00:00:00", + "2071-12-06 00:00:00", + "2071-12-12 00:00:00", + "2071-12-13 00:00:00", + "2071-12-19 00:00:00", + "2071-12-20 00:00:00", + "2071-12-26 00:00:00", + "2071-12-27 00:00:00", + "2072-01-01 00:00:00", + "2072-01-02 00:00:00", + "2072-01-03 00:00:00", + "2072-01-09 00:00:00", + "2072-01-10 00:00:00", + "2072-01-16 00:00:00", + "2072-01-17 00:00:00", + "2072-01-23 00:00:00", + "2072-01-24 00:00:00", + "2072-01-30 00:00:00", + "2072-01-31 00:00:00", + "2072-02-06 00:00:00", + "2072-02-07 00:00:00", + "2072-02-13 00:00:00", + "2072-02-18 00:00:00", + "2072-02-19 00:00:00", + "2072-02-20 00:00:00", + "2072-02-21 00:00:00", + "2072-02-22 00:00:00", + "2072-02-23 00:00:00", + "2072-02-24 00:00:00", + "2072-02-25 00:00:00", + "2072-02-28 00:00:00", + "2072-03-05 00:00:00", + "2072-03-06 00:00:00", + "2072-03-12 00:00:00", + "2072-03-13 00:00:00", + "2072-03-19 00:00:00", + "2072-03-20 00:00:00", + "2072-03-26 00:00:00", + "2072-03-27 00:00:00", + "2072-04-02 00:00:00", + "2072-04-03 00:00:00", + "2072-04-04 00:00:00", + "2072-04-09 00:00:00", + "2072-04-10 00:00:00", + "2072-04-16 00:00:00", + "2072-04-17 00:00:00", + "2072-04-23 00:00:00", + "2072-04-24 00:00:00", + "2072-04-30 00:00:00", + "2072-05-01 00:00:00", + "2072-05-02 00:00:00", + "2072-05-03 00:00:00", + "2072-05-04 00:00:00", + "2072-05-07 00:00:00", + "2072-05-14 00:00:00", + "2072-05-15 00:00:00", + "2072-05-21 00:00:00", + "2072-05-22 00:00:00", + "2072-05-28 00:00:00", + "2072-05-29 00:00:00", + "2072-06-04 00:00:00", + "2072-06-05 00:00:00", + "2072-06-11 00:00:00", + "2072-06-12 00:00:00", + "2072-06-18 00:00:00", + "2072-06-19 00:00:00", + "2072-06-20 00:00:00", + "2072-06-25 00:00:00", + "2072-06-26 00:00:00", + "2072-07-02 00:00:00", + "2072-07-03 00:00:00", + "2072-07-09 00:00:00", + "2072-07-10 00:00:00", + "2072-07-16 00:00:00", + "2072-07-17 00:00:00", + "2072-07-23 00:00:00", + "2072-07-24 00:00:00", + "2072-07-30 00:00:00", + "2072-07-31 00:00:00", + "2072-08-06 00:00:00", + "2072-08-07 00:00:00", + "2072-08-13 00:00:00", + "2072-08-14 00:00:00", + "2072-08-20 00:00:00", + "2072-08-21 00:00:00", + "2072-08-27 00:00:00", + "2072-08-28 00:00:00", + "2072-09-03 00:00:00", + "2072-09-04 00:00:00", + "2072-09-10 00:00:00", + "2072-09-11 00:00:00", + "2072-09-17 00:00:00", + "2072-09-24 00:00:00", + "2072-09-25 00:00:00", + "2072-09-26 00:00:00", + "2072-10-01 00:00:00", + "2072-10-02 00:00:00", + "2072-10-03 00:00:00", + "2072-10-04 00:00:00", + "2072-10-05 00:00:00", + "2072-10-06 00:00:00", + "2072-10-07 00:00:00", + "2072-10-08 00:00:00", + "2072-10-15 00:00:00", + "2072-10-16 00:00:00", + "2072-10-22 00:00:00", + "2072-10-23 00:00:00", + "2072-10-29 00:00:00", + "2072-10-30 00:00:00", + "2072-11-05 00:00:00", + "2072-11-06 00:00:00", + "2072-11-12 00:00:00", + "2072-11-13 00:00:00", + "2072-11-19 00:00:00", + "2072-11-20 00:00:00", + "2072-11-26 00:00:00", + "2072-11-27 00:00:00", + "2072-12-03 00:00:00", + "2072-12-04 00:00:00", + "2072-12-10 00:00:00", + "2072-12-11 00:00:00", + "2072-12-17 00:00:00", + "2072-12-18 00:00:00", + "2072-12-24 00:00:00", + "2072-12-25 00:00:00", + "2072-12-31 00:00:00", + "2073-01-01 00:00:00", + "2073-01-02 00:00:00", + "2073-01-07 00:00:00", + "2073-01-08 00:00:00", + "2073-01-14 00:00:00", + "2073-01-15 00:00:00", + "2073-01-21 00:00:00", + "2073-01-22 00:00:00", + "2073-01-28 00:00:00", + "2073-01-29 00:00:00", + "2073-02-05 00:00:00", + "2073-02-06 00:00:00", + "2073-02-07 00:00:00", + "2073-02-08 00:00:00", + "2073-02-09 00:00:00", + "2073-02-10 00:00:00", + "2073-02-11 00:00:00", + "2073-02-12 00:00:00", + "2073-02-13 00:00:00", + "2073-02-19 00:00:00", + "2073-02-25 00:00:00", + "2073-02-26 00:00:00", + "2073-03-04 00:00:00", + "2073-03-05 00:00:00", + "2073-03-11 00:00:00", + "2073-03-12 00:00:00", + "2073-03-18 00:00:00", + "2073-03-19 00:00:00", + "2073-03-25 00:00:00", + "2073-04-01 00:00:00", + "2073-04-02 00:00:00", + "2073-04-03 00:00:00", + "2073-04-04 00:00:00", + "2073-04-08 00:00:00", + "2073-04-09 00:00:00", + "2073-04-15 00:00:00", + "2073-04-16 00:00:00", + "2073-04-22 00:00:00", + "2073-04-23 00:00:00", + "2073-04-29 00:00:00", + "2073-04-30 00:00:00", + "2073-05-01 00:00:00", + "2073-05-02 00:00:00", + "2073-05-03 00:00:00", + "2073-05-06 00:00:00", + "2073-05-13 00:00:00", + "2073-05-14 00:00:00", + "2073-05-20 00:00:00", + "2073-05-21 00:00:00", + "2073-05-27 00:00:00", + "2073-05-28 00:00:00", + "2073-06-03 00:00:00", + "2073-06-04 00:00:00", + "2073-06-10 00:00:00", + "2073-06-11 00:00:00", + "2073-06-12 00:00:00", + "2073-06-17 00:00:00", + "2073-06-18 00:00:00", + "2073-06-24 00:00:00", + "2073-06-25 00:00:00", + "2073-07-01 00:00:00", + "2073-07-02 00:00:00", + "2073-07-08 00:00:00", + "2073-07-09 00:00:00", + "2073-07-15 00:00:00", + "2073-07-16 00:00:00", + "2073-07-22 00:00:00", + "2073-07-23 00:00:00", + "2073-07-29 00:00:00", + "2073-07-30 00:00:00", + "2073-08-05 00:00:00", + "2073-08-06 00:00:00", + "2073-08-12 00:00:00", + "2073-08-13 00:00:00", + "2073-08-19 00:00:00", + "2073-08-20 00:00:00", + "2073-08-26 00:00:00", + "2073-08-27 00:00:00", + "2073-09-02 00:00:00", + "2073-09-03 00:00:00", + "2073-09-09 00:00:00", + "2073-09-10 00:00:00", + "2073-09-16 00:00:00", + "2073-09-17 00:00:00", + "2073-09-18 00:00:00", + "2073-09-23 00:00:00", + "2073-09-30 00:00:00", + "2073-10-01 00:00:00", + "2073-10-02 00:00:00", + "2073-10-03 00:00:00", + "2073-10-04 00:00:00", + "2073-10-05 00:00:00", + "2073-10-06 00:00:00", + "2073-10-07 00:00:00", + "2073-10-14 00:00:00", + "2073-10-15 00:00:00", + "2073-10-21 00:00:00", + "2073-10-22 00:00:00", + "2073-10-28 00:00:00", + "2073-10-29 00:00:00", + "2073-11-04 00:00:00", + "2073-11-05 00:00:00", + "2073-11-11 00:00:00", + "2073-11-12 00:00:00", + "2073-11-18 00:00:00", + "2073-11-19 00:00:00", + "2073-11-25 00:00:00", + "2073-11-26 00:00:00", + "2073-12-02 00:00:00", + "2073-12-03 00:00:00", + "2073-12-09 00:00:00", + "2073-12-10 00:00:00", + "2073-12-16 00:00:00", + "2073-12-17 00:00:00", + "2073-12-23 00:00:00", + "2073-12-24 00:00:00", + "2073-12-30 00:00:00", + "2073-12-31 00:00:00", + "2074-01-01 00:00:00", + "2074-01-06 00:00:00", + "2074-01-07 00:00:00", + "2074-01-13 00:00:00", + "2074-01-14 00:00:00", + "2074-01-20 00:00:00", + "2074-01-26 00:00:00", + "2074-01-27 00:00:00", + "2074-01-28 00:00:00", + "2074-01-29 00:00:00", + "2074-01-30 00:00:00", + "2074-01-31 00:00:00", + "2074-02-01 00:00:00", + "2074-02-02 00:00:00", + "2074-02-04 00:00:00", + "2074-02-10 00:00:00", + "2074-02-11 00:00:00", + "2074-02-17 00:00:00", + "2074-02-18 00:00:00", + "2074-02-24 00:00:00", + "2074-02-25 00:00:00", + "2074-03-03 00:00:00", + "2074-03-04 00:00:00", + "2074-03-10 00:00:00", + "2074-03-11 00:00:00", + "2074-03-17 00:00:00", + "2074-03-18 00:00:00", + "2074-03-24 00:00:00", + "2074-03-25 00:00:00", + "2074-03-31 00:00:00", + "2074-04-01 00:00:00", + "2074-04-04 00:00:00", + "2074-04-07 00:00:00", + "2074-04-08 00:00:00", + "2074-04-14 00:00:00", + "2074-04-15 00:00:00", + "2074-04-21 00:00:00", + "2074-04-22 00:00:00", + "2074-04-28 00:00:00", + "2074-04-29 00:00:00", + "2074-04-30 00:00:00", + "2074-05-01 00:00:00", + "2074-05-02 00:00:00", + "2074-05-05 00:00:00", + "2074-05-06 00:00:00", + "2074-05-12 00:00:00", + "2074-05-13 00:00:00", + "2074-05-19 00:00:00", + "2074-05-20 00:00:00", + "2074-05-26 00:00:00", + "2074-05-27 00:00:00", + "2074-05-30 00:00:00", + "2074-06-02 00:00:00", + "2074-06-03 00:00:00", + "2074-06-09 00:00:00", + "2074-06-10 00:00:00", + "2074-06-16 00:00:00", + "2074-06-17 00:00:00", + "2074-06-23 00:00:00", + "2074-06-24 00:00:00", + "2074-06-30 00:00:00", + "2074-07-01 00:00:00", + "2074-07-07 00:00:00", + "2074-07-08 00:00:00", + "2074-07-14 00:00:00", + "2074-07-15 00:00:00", + "2074-07-21 00:00:00", + "2074-07-22 00:00:00", + "2074-07-28 00:00:00", + "2074-07-29 00:00:00", + "2074-08-04 00:00:00", + "2074-08-05 00:00:00", + "2074-08-11 00:00:00", + "2074-08-12 00:00:00", + "2074-08-18 00:00:00", + "2074-08-19 00:00:00", + "2074-08-25 00:00:00", + "2074-08-26 00:00:00", + "2074-09-01 00:00:00", + "2074-09-02 00:00:00", + "2074-09-08 00:00:00", + "2074-09-09 00:00:00", + "2074-09-15 00:00:00", + "2074-09-16 00:00:00", + "2074-09-22 00:00:00", + "2074-09-23 00:00:00", + "2074-09-30 00:00:00", + "2074-10-01 00:00:00", + "2074-10-02 00:00:00", + "2074-10-03 00:00:00", + "2074-10-04 00:00:00", + "2074-10-05 00:00:00", + "2074-10-06 00:00:00", + "2074-10-07 00:00:00", + "2074-10-08 00:00:00", + "2074-10-14 00:00:00", + "2074-10-20 00:00:00", + "2074-10-21 00:00:00", + "2074-10-27 00:00:00", + "2074-10-28 00:00:00", + "2074-11-03 00:00:00", + "2074-11-04 00:00:00", + "2074-11-10 00:00:00", + "2074-11-11 00:00:00", + "2074-11-17 00:00:00", + "2074-11-18 00:00:00", + "2074-11-24 00:00:00", + "2074-11-25 00:00:00", + "2074-12-01 00:00:00", + "2074-12-02 00:00:00", + "2074-12-08 00:00:00", + "2074-12-09 00:00:00", + "2074-12-15 00:00:00", + "2074-12-16 00:00:00", + "2074-12-22 00:00:00", + "2074-12-23 00:00:00", + "2074-12-30 00:00:00", + "2074-12-31 00:00:00", + "2075-01-01 00:00:00", + "2075-01-05 00:00:00", + "2075-01-06 00:00:00", + "2075-01-12 00:00:00", + "2075-01-13 00:00:00", + "2075-01-19 00:00:00", + "2075-01-20 00:00:00", + "2075-01-26 00:00:00", + "2075-01-27 00:00:00", + "2075-02-02 00:00:00", + "2075-02-03 00:00:00", + "2075-02-09 00:00:00", + "2075-02-14 00:00:00", + "2075-02-15 00:00:00", + "2075-02-16 00:00:00", + "2075-02-17 00:00:00", + "2075-02-18 00:00:00", + "2075-02-19 00:00:00", + "2075-02-20 00:00:00", + "2075-02-21 00:00:00", + "2075-02-24 00:00:00", + "2075-03-02 00:00:00", + "2075-03-03 00:00:00", + "2075-03-09 00:00:00", + "2075-03-10 00:00:00", + "2075-03-16 00:00:00", + "2075-03-17 00:00:00", + "2075-03-23 00:00:00", + "2075-03-24 00:00:00", + "2075-03-30 00:00:00", + "2075-03-31 00:00:00", + "2075-04-04 00:00:00", + "2075-04-05 00:00:00", + "2075-04-06 00:00:00", + "2075-04-07 00:00:00", + "2075-04-13 00:00:00", + "2075-04-20 00:00:00", + "2075-04-21 00:00:00", + "2075-04-27 00:00:00", + "2075-04-28 00:00:00", + "2075-05-01 00:00:00", + "2075-05-02 00:00:00", + "2075-05-04 00:00:00", + "2075-05-05 00:00:00", + "2075-05-11 00:00:00", + "2075-05-12 00:00:00", + "2075-05-18 00:00:00", + "2075-05-19 00:00:00", + "2075-05-25 00:00:00", + "2075-05-26 00:00:00", + "2075-06-01 00:00:00", + "2075-06-02 00:00:00", + "2075-06-08 00:00:00", + "2075-06-09 00:00:00", + "2075-06-15 00:00:00", + "2075-06-16 00:00:00", + "2075-06-17 00:00:00", + "2075-06-22 00:00:00", + "2075-06-23 00:00:00", + "2075-06-29 00:00:00", + "2075-06-30 00:00:00", + "2075-07-06 00:00:00", + "2075-07-07 00:00:00", + "2075-07-13 00:00:00", + "2075-07-14 00:00:00", + "2075-07-20 00:00:00", + "2075-07-21 00:00:00", + "2075-07-27 00:00:00", + "2075-07-28 00:00:00", + "2075-08-03 00:00:00", + "2075-08-04 00:00:00", + "2075-08-10 00:00:00", + "2075-08-11 00:00:00", + "2075-08-17 00:00:00", + "2075-08-18 00:00:00", + "2075-08-24 00:00:00", + "2075-08-25 00:00:00", + "2075-08-31 00:00:00", + "2075-09-01 00:00:00", + "2075-09-07 00:00:00", + "2075-09-08 00:00:00", + "2075-09-14 00:00:00", + "2075-09-21 00:00:00", + "2075-09-22 00:00:00", + "2075-09-23 00:00:00", + "2075-09-24 00:00:00", + "2075-09-28 00:00:00", + "2075-10-01 00:00:00", + "2075-10-02 00:00:00", + "2075-10-03 00:00:00", + "2075-10-04 00:00:00", + "2075-10-05 00:00:00", + "2075-10-06 00:00:00", + "2075-10-07 00:00:00", + "2075-10-13 00:00:00", + "2075-10-19 00:00:00", + "2075-10-20 00:00:00", + "2075-10-26 00:00:00", + "2075-10-27 00:00:00", + "2075-11-02 00:00:00", + "2075-11-03 00:00:00", + "2075-11-09 00:00:00", + "2075-11-10 00:00:00", + "2075-11-16 00:00:00", + "2075-11-17 00:00:00", + "2075-11-23 00:00:00", + "2075-11-24 00:00:00", + "2075-11-30 00:00:00", + "2075-12-01 00:00:00", + "2075-12-07 00:00:00", + "2075-12-08 00:00:00", + "2075-12-14 00:00:00", + "2075-12-15 00:00:00", + "2075-12-21 00:00:00", + "2075-12-22 00:00:00", + "2075-12-28 00:00:00", + "2075-12-29 00:00:00", + "2076-01-01 00:00:00", + "2076-01-04 00:00:00", + "2076-01-05 00:00:00", + "2076-01-11 00:00:00", + "2076-01-12 00:00:00", + "2076-01-18 00:00:00", + "2076-01-19 00:00:00", + "2076-01-25 00:00:00", + "2076-01-26 00:00:00", + "2076-02-01 00:00:00", + "2076-02-04 00:00:00", + "2076-02-05 00:00:00", + "2076-02-06 00:00:00", + "2076-02-07 00:00:00", + "2076-02-08 00:00:00", + "2076-02-09 00:00:00", + "2076-02-10 00:00:00", + "2076-02-11 00:00:00", + "2076-02-16 00:00:00", + "2076-02-22 00:00:00", + "2076-02-23 00:00:00", + "2076-02-29 00:00:00", + "2076-03-01 00:00:00", + "2076-03-07 00:00:00", + "2076-03-08 00:00:00", + "2076-03-14 00:00:00", + "2076-03-15 00:00:00", + "2076-03-21 00:00:00", + "2076-03-22 00:00:00", + "2076-03-28 00:00:00", + "2076-03-29 00:00:00", + "2076-04-03 00:00:00", + "2076-04-04 00:00:00", + "2076-04-05 00:00:00", + "2076-04-11 00:00:00", + "2076-04-12 00:00:00", + "2076-04-18 00:00:00", + "2076-04-19 00:00:00", + "2076-04-25 00:00:00", + "2076-04-26 00:00:00", + "2076-05-01 00:00:00", + "2076-05-02 00:00:00", + "2076-05-03 00:00:00", + "2076-05-04 00:00:00", + "2076-05-05 00:00:00", + "2076-05-10 00:00:00", + "2076-05-16 00:00:00", + "2076-05-17 00:00:00", + "2076-05-23 00:00:00", + "2076-05-24 00:00:00", + "2076-05-30 00:00:00", + "2076-05-31 00:00:00", + "2076-06-06 00:00:00", + "2076-06-07 00:00:00", + "2076-06-08 00:00:00", + "2076-06-13 00:00:00", + "2076-06-14 00:00:00", + "2076-06-20 00:00:00", + "2076-06-21 00:00:00", + "2076-06-27 00:00:00", + "2076-06-28 00:00:00", + "2076-07-04 00:00:00", + "2076-07-05 00:00:00", + "2076-07-11 00:00:00", + "2076-07-12 00:00:00", + "2076-07-18 00:00:00", + "2076-07-19 00:00:00", + "2076-07-25 00:00:00", + "2076-07-26 00:00:00", + "2076-08-01 00:00:00", + "2076-08-02 00:00:00", + "2076-08-08 00:00:00", + "2076-08-09 00:00:00", + "2076-08-15 00:00:00", + "2076-08-16 00:00:00", + "2076-08-22 00:00:00", + "2076-08-23 00:00:00", + "2076-08-29 00:00:00", + "2076-08-30 00:00:00", + "2076-09-05 00:00:00", + "2076-09-06 00:00:00", + "2076-09-12 00:00:00", + "2076-09-13 00:00:00", + "2076-09-14 00:00:00", + "2076-09-19 00:00:00", + "2076-09-20 00:00:00", + "2076-09-26 00:00:00", + "2076-10-01 00:00:00", + "2076-10-02 00:00:00", + "2076-10-03 00:00:00", + "2076-10-04 00:00:00", + "2076-10-05 00:00:00", + "2076-10-06 00:00:00", + "2076-10-07 00:00:00", + "2076-10-11 00:00:00", + "2076-10-17 00:00:00", + "2076-10-18 00:00:00", + "2076-10-24 00:00:00", + "2076-10-25 00:00:00", + "2076-10-31 00:00:00", + "2076-11-01 00:00:00", + "2076-11-07 00:00:00", + "2076-11-08 00:00:00", + "2076-11-14 00:00:00", + "2076-11-15 00:00:00", + "2076-11-21 00:00:00", + "2076-11-22 00:00:00", + "2076-11-28 00:00:00", + "2076-11-29 00:00:00", + "2076-12-05 00:00:00", + "2076-12-06 00:00:00", + "2076-12-12 00:00:00", + "2076-12-13 00:00:00", + "2076-12-19 00:00:00", + "2076-12-20 00:00:00", + "2076-12-26 00:00:00", + "2076-12-27 00:00:00", + "2077-01-01 00:00:00", + "2077-01-02 00:00:00", + "2077-01-03 00:00:00", + "2077-01-09 00:00:00", + "2077-01-10 00:00:00", + "2077-01-16 00:00:00", + "2077-01-23 00:00:00", + "2077-01-24 00:00:00", + "2077-01-25 00:00:00", + "2077-01-26 00:00:00", + "2077-01-27 00:00:00", + "2077-01-28 00:00:00", + "2077-01-29 00:00:00", + "2077-01-30 00:00:00", + "2077-02-06 00:00:00", + "2077-02-07 00:00:00", + "2077-02-13 00:00:00", + "2077-02-14 00:00:00", + "2077-02-20 00:00:00", + "2077-02-21 00:00:00", + "2077-02-27 00:00:00", + "2077-02-28 00:00:00", + "2077-03-06 00:00:00", + "2077-03-07 00:00:00", + "2077-03-13 00:00:00", + "2077-03-14 00:00:00", + "2077-03-20 00:00:00", + "2077-03-21 00:00:00", + "2077-03-27 00:00:00", + "2077-03-28 00:00:00", + "2077-04-03 00:00:00", + "2077-04-04 00:00:00", + "2077-04-05 00:00:00", + "2077-04-10 00:00:00", + "2077-04-11 00:00:00", + "2077-04-17 00:00:00", + "2077-04-18 00:00:00", + "2077-04-24 00:00:00", + "2077-04-25 00:00:00", + "2077-05-01 00:00:00", + "2077-05-02 00:00:00", + "2077-05-03 00:00:00", + "2077-05-04 00:00:00", + "2077-05-05 00:00:00", + "2077-05-08 00:00:00", + "2077-05-15 00:00:00", + "2077-05-16 00:00:00", + "2077-05-22 00:00:00", + "2077-05-23 00:00:00", + "2077-05-29 00:00:00", + "2077-05-30 00:00:00", + "2077-06-05 00:00:00", + "2077-06-06 00:00:00", + "2077-06-12 00:00:00", + "2077-06-13 00:00:00", + "2077-06-19 00:00:00", + "2077-06-20 00:00:00", + "2077-06-24 00:00:00", + "2077-06-25 00:00:00", + "2077-06-26 00:00:00", + "2077-06-27 00:00:00", + "2077-07-03 00:00:00", + "2077-07-10 00:00:00", + "2077-07-11 00:00:00", + "2077-07-17 00:00:00", + "2077-07-18 00:00:00", + "2077-07-24 00:00:00", + "2077-07-25 00:00:00", + "2077-07-31 00:00:00", + "2077-08-01 00:00:00", + "2077-08-07 00:00:00", + "2077-08-08 00:00:00", + "2077-08-14 00:00:00", + "2077-08-15 00:00:00", + "2077-08-21 00:00:00", + "2077-08-22 00:00:00", + "2077-08-28 00:00:00", + "2077-08-29 00:00:00", + "2077-09-04 00:00:00", + "2077-09-05 00:00:00", + "2077-09-11 00:00:00", + "2077-09-12 00:00:00", + "2077-09-18 00:00:00", + "2077-09-19 00:00:00", + "2077-09-25 00:00:00", + "2077-10-01 00:00:00", + "2077-10-02 00:00:00", + "2077-10-03 00:00:00", + "2077-10-04 00:00:00", + "2077-10-05 00:00:00", + "2077-10-06 00:00:00", + "2077-10-07 00:00:00", + "2077-10-08 00:00:00", + "2077-10-10 00:00:00", + "2077-10-16 00:00:00", + "2077-10-17 00:00:00", + "2077-10-23 00:00:00", + "2077-10-24 00:00:00", + "2077-10-30 00:00:00", + "2077-10-31 00:00:00", + "2077-11-06 00:00:00", + "2077-11-07 00:00:00", + "2077-11-13 00:00:00", + "2077-11-14 00:00:00", + "2077-11-20 00:00:00", + "2077-11-21 00:00:00", + "2077-11-27 00:00:00", + "2077-11-28 00:00:00", + "2077-12-04 00:00:00", + "2077-12-05 00:00:00", + "2077-12-11 00:00:00", + "2077-12-12 00:00:00", + "2077-12-18 00:00:00", + "2077-12-19 00:00:00", + "2077-12-25 00:00:00", + "2077-12-26 00:00:00", + "2078-01-01 00:00:00", + "2078-01-02 00:00:00", + "2078-01-03 00:00:00", + "2078-01-08 00:00:00", + "2078-01-09 00:00:00", + "2078-01-15 00:00:00", + "2078-01-16 00:00:00", + "2078-01-22 00:00:00", + "2078-01-23 00:00:00", + "2078-01-29 00:00:00", + "2078-01-30 00:00:00", + "2078-02-05 00:00:00", + "2078-02-11 00:00:00", + "2078-02-12 00:00:00", + "2078-02-13 00:00:00", + "2078-02-14 00:00:00", + "2078-02-15 00:00:00", + "2078-02-16 00:00:00", + "2078-02-17 00:00:00", + "2078-02-18 00:00:00", + "2078-02-20 00:00:00", + "2078-02-26 00:00:00", + "2078-02-27 00:00:00", + "2078-03-05 00:00:00", + "2078-03-06 00:00:00", + "2078-03-12 00:00:00", + "2078-03-13 00:00:00", + "2078-03-19 00:00:00", + "2078-03-20 00:00:00", + "2078-03-26 00:00:00", + "2078-03-27 00:00:00", + "2078-04-02 00:00:00", + "2078-04-03 00:00:00", + "2078-04-04 00:00:00", + "2078-04-09 00:00:00", + "2078-04-10 00:00:00", + "2078-04-16 00:00:00", + "2078-04-17 00:00:00", + "2078-04-23 00:00:00", + "2078-04-24 00:00:00", + "2078-04-30 00:00:00", + "2078-05-01 00:00:00", + "2078-05-02 00:00:00", + "2078-05-03 00:00:00", + "2078-05-04 00:00:00", + "2078-05-07 00:00:00", + "2078-05-14 00:00:00", + "2078-05-15 00:00:00", + "2078-05-21 00:00:00", + "2078-05-22 00:00:00", + "2078-05-28 00:00:00", + "2078-05-29 00:00:00", + "2078-06-04 00:00:00", + "2078-06-11 00:00:00", + "2078-06-12 00:00:00", + "2078-06-13 00:00:00", + "2078-06-14 00:00:00", + "2078-06-18 00:00:00", + "2078-06-19 00:00:00", + "2078-06-25 00:00:00", + "2078-06-26 00:00:00", + "2078-07-02 00:00:00", + "2078-07-03 00:00:00", + "2078-07-09 00:00:00", + "2078-07-10 00:00:00", + "2078-07-16 00:00:00", + "2078-07-17 00:00:00", + "2078-07-23 00:00:00", + "2078-07-24 00:00:00", + "2078-07-30 00:00:00", + "2078-07-31 00:00:00", + "2078-08-06 00:00:00", + "2078-08-07 00:00:00", + "2078-08-13 00:00:00", + "2078-08-14 00:00:00", + "2078-08-20 00:00:00", + "2078-08-21 00:00:00", + "2078-08-27 00:00:00", + "2078-08-28 00:00:00", + "2078-09-03 00:00:00", + "2078-09-04 00:00:00", + "2078-09-10 00:00:00", + "2078-09-17 00:00:00", + "2078-09-18 00:00:00", + "2078-09-19 00:00:00", + "2078-09-20 00:00:00", + "2078-09-24 00:00:00", + "2078-10-01 00:00:00", + "2078-10-02 00:00:00", + "2078-10-03 00:00:00", + "2078-10-04 00:00:00", + "2078-10-05 00:00:00", + "2078-10-06 00:00:00", + "2078-10-07 00:00:00", + "2078-10-08 00:00:00", + "2078-10-15 00:00:00", + "2078-10-16 00:00:00", + "2078-10-22 00:00:00", + "2078-10-23 00:00:00", + "2078-10-29 00:00:00", + "2078-10-30 00:00:00", + "2078-11-05 00:00:00", + "2078-11-06 00:00:00", + "2078-11-12 00:00:00", + "2078-11-13 00:00:00", + "2078-11-19 00:00:00", + "2078-11-20 00:00:00", + "2078-11-26 00:00:00", + "2078-11-27 00:00:00", + "2078-12-03 00:00:00", + "2078-12-04 00:00:00", + "2078-12-10 00:00:00", + "2078-12-11 00:00:00", + "2078-12-17 00:00:00", + "2078-12-18 00:00:00", + "2078-12-24 00:00:00", + "2078-12-25 00:00:00", + "2078-12-31 00:00:00", + "2079-01-01 00:00:00", + "2079-01-02 00:00:00", + "2079-01-07 00:00:00", + "2079-01-08 00:00:00", + "2079-01-14 00:00:00", + "2079-01-15 00:00:00", + "2079-01-21 00:00:00", + "2079-01-22 00:00:00", + "2079-01-28 00:00:00", + "2079-02-01 00:00:00", + "2079-02-02 00:00:00", + "2079-02-03 00:00:00", + "2079-02-04 00:00:00", + "2079-02-05 00:00:00", + "2079-02-06 00:00:00", + "2079-02-07 00:00:00", + "2079-02-08 00:00:00", + "2079-02-12 00:00:00", + "2079-02-18 00:00:00", + "2079-02-19 00:00:00", + "2079-02-25 00:00:00", + "2079-02-26 00:00:00", + "2079-03-04 00:00:00", + "2079-03-05 00:00:00", + "2079-03-11 00:00:00", + "2079-03-12 00:00:00", + "2079-03-18 00:00:00", + "2079-03-19 00:00:00", + "2079-03-25 00:00:00", + "2079-04-01 00:00:00", + "2079-04-02 00:00:00", + "2079-04-03 00:00:00", + "2079-04-04 00:00:00", + "2079-04-08 00:00:00", + "2079-04-09 00:00:00", + "2079-04-15 00:00:00", + "2079-04-16 00:00:00", + "2079-04-22 00:00:00", + "2079-04-23 00:00:00", + "2079-04-29 00:00:00", + "2079-04-30 00:00:00", + "2079-05-01 00:00:00", + "2079-05-02 00:00:00", + "2079-05-03 00:00:00", + "2079-05-06 00:00:00", + "2079-05-13 00:00:00", + "2079-05-14 00:00:00", + "2079-05-20 00:00:00", + "2079-05-21 00:00:00", + "2079-05-27 00:00:00", + "2079-05-28 00:00:00", + "2079-06-03 00:00:00", + "2079-06-04 00:00:00", + "2079-06-05 00:00:00", + "2079-06-10 00:00:00", + "2079-06-11 00:00:00", + "2079-06-17 00:00:00", + "2079-06-18 00:00:00", + "2079-06-24 00:00:00", + "2079-06-25 00:00:00", + "2079-07-01 00:00:00", + "2079-07-02 00:00:00", + "2079-07-08 00:00:00", + "2079-07-09 00:00:00", + "2079-07-15 00:00:00", + "2079-07-16 00:00:00", + "2079-07-22 00:00:00", + "2079-07-23 00:00:00", + "2079-07-29 00:00:00", + "2079-07-30 00:00:00", + "2079-08-05 00:00:00", + "2079-08-06 00:00:00", + "2079-08-12 00:00:00", + "2079-08-13 00:00:00", + "2079-08-19 00:00:00", + "2079-08-20 00:00:00", + "2079-08-26 00:00:00", + "2079-08-27 00:00:00", + "2079-09-02 00:00:00", + "2079-09-03 00:00:00", + "2079-09-09 00:00:00", + "2079-09-10 00:00:00", + "2079-09-11 00:00:00", + "2079-09-16 00:00:00", + "2079-09-17 00:00:00", + "2079-09-23 00:00:00", + "2079-09-30 00:00:00", + "2079-10-01 00:00:00", + "2079-10-02 00:00:00", + "2079-10-03 00:00:00", + "2079-10-04 00:00:00", + "2079-10-05 00:00:00", + "2079-10-06 00:00:00", + "2079-10-07 00:00:00", + "2079-10-14 00:00:00", + "2079-10-15 00:00:00", + "2079-10-21 00:00:00", + "2079-10-22 00:00:00", + "2079-10-28 00:00:00", + "2079-10-29 00:00:00", + "2079-11-04 00:00:00", + "2079-11-05 00:00:00", + "2079-11-11 00:00:00", + "2079-11-12 00:00:00", + "2079-11-18 00:00:00", + "2079-11-19 00:00:00", + "2079-11-25 00:00:00", + "2079-11-26 00:00:00", + "2079-12-02 00:00:00", + "2079-12-03 00:00:00", + "2079-12-09 00:00:00", + "2079-12-10 00:00:00", + "2079-12-16 00:00:00", + "2079-12-17 00:00:00", + "2079-12-23 00:00:00", + "2079-12-24 00:00:00", + "2079-12-30 00:00:00", + "2079-12-31 00:00:00", + "2080-01-01 00:00:00", + "2080-01-06 00:00:00", + "2080-01-07 00:00:00", + "2080-01-13 00:00:00", + "2080-01-14 00:00:00", + "2080-01-21 00:00:00", + "2080-01-22 00:00:00", + "2080-01-23 00:00:00", + "2080-01-24 00:00:00", + "2080-01-25 00:00:00", + "2080-01-26 00:00:00", + "2080-01-27 00:00:00", + "2080-01-28 00:00:00", + "2080-02-04 00:00:00", + "2080-02-10 00:00:00", + "2080-02-11 00:00:00", + "2080-02-17 00:00:00", + "2080-02-18 00:00:00", + "2080-02-24 00:00:00", + "2080-02-25 00:00:00", + "2080-03-02 00:00:00", + "2080-03-03 00:00:00", + "2080-03-09 00:00:00", + "2080-03-10 00:00:00", + "2080-03-16 00:00:00", + "2080-03-17 00:00:00", + "2080-03-23 00:00:00", + "2080-03-24 00:00:00", + "2080-03-30 00:00:00", + "2080-03-31 00:00:00", + "2080-04-03 00:00:00", + "2080-04-06 00:00:00", + "2080-04-07 00:00:00", + "2080-04-13 00:00:00", + "2080-04-14 00:00:00", + "2080-04-20 00:00:00", + "2080-04-21 00:00:00", + "2080-04-27 00:00:00", + "2080-04-28 00:00:00", + "2080-05-01 00:00:00", + "2080-05-02 00:00:00", + "2080-05-04 00:00:00", + "2080-05-05 00:00:00", + "2080-05-11 00:00:00", + "2080-05-12 00:00:00", + "2080-05-18 00:00:00", + "2080-05-19 00:00:00", + "2080-05-25 00:00:00", + "2080-05-26 00:00:00", + "2080-06-01 00:00:00", + "2080-06-02 00:00:00", + "2080-06-08 00:00:00", + "2080-06-09 00:00:00", + "2080-06-15 00:00:00", + "2080-06-16 00:00:00", + "2080-06-22 00:00:00", + "2080-06-23 00:00:00", + "2080-06-24 00:00:00", + "2080-06-29 00:00:00", + "2080-06-30 00:00:00", + "2080-07-06 00:00:00", + "2080-07-07 00:00:00", + "2080-07-13 00:00:00", + "2080-07-14 00:00:00", + "2080-07-20 00:00:00", + "2080-07-21 00:00:00", + "2080-07-27 00:00:00", + "2080-07-28 00:00:00", + "2080-08-03 00:00:00", + "2080-08-04 00:00:00", + "2080-08-10 00:00:00", + "2080-08-11 00:00:00", + "2080-08-17 00:00:00", + "2080-08-18 00:00:00", + "2080-08-24 00:00:00", + "2080-08-25 00:00:00", + "2080-08-31 00:00:00", + "2080-09-01 00:00:00", + "2080-09-07 00:00:00", + "2080-09-08 00:00:00", + "2080-09-14 00:00:00", + "2080-09-15 00:00:00", + "2080-09-21 00:00:00", + "2080-09-28 00:00:00", + "2080-09-29 00:00:00", + "2080-09-30 00:00:00", + "2080-10-01 00:00:00", + "2080-10-02 00:00:00", + "2080-10-03 00:00:00", + "2080-10-04 00:00:00", + "2080-10-05 00:00:00", + "2080-10-06 00:00:00", + "2080-10-07 00:00:00", + "2080-10-13 00:00:00", + "2080-10-19 00:00:00", + "2080-10-20 00:00:00", + "2080-10-26 00:00:00", + "2080-10-27 00:00:00", + "2080-11-02 00:00:00", + "2080-11-03 00:00:00", + "2080-11-09 00:00:00", + "2080-11-10 00:00:00", + "2080-11-16 00:00:00", + "2080-11-17 00:00:00", + "2080-11-23 00:00:00", + "2080-11-24 00:00:00", + "2080-11-30 00:00:00", + "2080-12-01 00:00:00", + "2080-12-07 00:00:00", + "2080-12-08 00:00:00", + "2080-12-14 00:00:00", + "2080-12-15 00:00:00", + "2080-12-21 00:00:00", + "2080-12-22 00:00:00", + "2080-12-28 00:00:00", + "2080-12-29 00:00:00", + "2081-01-01 00:00:00", + "2081-01-04 00:00:00", + "2081-01-05 00:00:00", + "2081-01-11 00:00:00", + "2081-01-12 00:00:00", + "2081-01-18 00:00:00", + "2081-01-19 00:00:00", + "2081-01-25 00:00:00", + "2081-01-26 00:00:00", + "2081-02-01 00:00:00", + "2081-02-08 00:00:00", + "2081-02-09 00:00:00", + "2081-02-10 00:00:00", + "2081-02-11 00:00:00", + "2081-02-12 00:00:00", + "2081-02-13 00:00:00", + "2081-02-14 00:00:00", + "2081-02-15 00:00:00", + "2081-02-22 00:00:00", + "2081-02-23 00:00:00", + "2081-03-01 00:00:00", + "2081-03-02 00:00:00", + "2081-03-08 00:00:00", + "2081-03-09 00:00:00", + "2081-03-15 00:00:00", + "2081-03-16 00:00:00", + "2081-03-22 00:00:00", + "2081-03-23 00:00:00", + "2081-03-29 00:00:00", + "2081-03-30 00:00:00", + "2081-04-03 00:00:00", + "2081-04-04 00:00:00", + "2081-04-05 00:00:00", + "2081-04-06 00:00:00", + "2081-04-12 00:00:00", + "2081-04-19 00:00:00", + "2081-04-20 00:00:00", + "2081-04-26 00:00:00", + "2081-05-01 00:00:00", + "2081-05-02 00:00:00", + "2081-05-03 00:00:00", + "2081-05-04 00:00:00", + "2081-05-05 00:00:00", + "2081-05-10 00:00:00", + "2081-05-11 00:00:00", + "2081-05-17 00:00:00", + "2081-05-18 00:00:00", + "2081-05-24 00:00:00", + "2081-05-25 00:00:00", + "2081-05-31 00:00:00", + "2081-06-01 00:00:00", + "2081-06-07 00:00:00", + "2081-06-08 00:00:00", + "2081-06-11 00:00:00", + "2081-06-14 00:00:00", + "2081-06-15 00:00:00", + "2081-06-21 00:00:00", + "2081-06-22 00:00:00", + "2081-06-28 00:00:00", + "2081-06-29 00:00:00", + "2081-07-05 00:00:00", + "2081-07-06 00:00:00", + "2081-07-12 00:00:00", + "2081-07-13 00:00:00", + "2081-07-19 00:00:00", + "2081-07-20 00:00:00", + "2081-07-26 00:00:00", + "2081-07-27 00:00:00", + "2081-08-02 00:00:00", + "2081-08-03 00:00:00", + "2081-08-09 00:00:00", + "2081-08-10 00:00:00", + "2081-08-16 00:00:00", + "2081-08-17 00:00:00", + "2081-08-23 00:00:00", + "2081-08-24 00:00:00", + "2081-08-30 00:00:00", + "2081-08-31 00:00:00", + "2081-09-06 00:00:00", + "2081-09-07 00:00:00", + "2081-09-13 00:00:00", + "2081-09-14 00:00:00", + "2081-09-17 00:00:00", + "2081-09-20 00:00:00", + "2081-09-21 00:00:00", + "2081-09-27 00:00:00", + "2081-10-01 00:00:00", + "2081-10-02 00:00:00", + "2081-10-03 00:00:00", + "2081-10-04 00:00:00", + "2081-10-05 00:00:00", + "2081-10-06 00:00:00", + "2081-10-07 00:00:00", + "2081-10-12 00:00:00", + "2081-10-18 00:00:00", + "2081-10-19 00:00:00", + "2081-10-25 00:00:00", + "2081-10-26 00:00:00", + "2081-11-01 00:00:00", + "2081-11-02 00:00:00", + "2081-11-08 00:00:00", + "2081-11-09 00:00:00", + "2081-11-15 00:00:00", + "2081-11-16 00:00:00", + "2081-11-22 00:00:00", + "2081-11-23 00:00:00", + "2081-11-29 00:00:00", + "2081-11-30 00:00:00", + "2081-12-06 00:00:00", + "2081-12-07 00:00:00", + "2081-12-13 00:00:00", + "2081-12-14 00:00:00", + "2081-12-20 00:00:00", + "2081-12-21 00:00:00", + "2081-12-27 00:00:00", + "2081-12-28 00:00:00", + "2082-01-01 00:00:00", + "2082-01-02 00:00:00", + "2082-01-03 00:00:00", + "2082-01-10 00:00:00", + "2082-01-11 00:00:00", + "2082-01-17 00:00:00", + "2082-01-18 00:00:00", + "2082-01-24 00:00:00", + "2082-01-28 00:00:00", + "2082-01-29 00:00:00", + "2082-01-30 00:00:00", + "2082-01-31 00:00:00", + "2082-02-01 00:00:00", + "2082-02-02 00:00:00", + "2082-02-03 00:00:00", + "2082-02-04 00:00:00", + "2082-02-08 00:00:00", + "2082-02-14 00:00:00", + "2082-02-15 00:00:00", + "2082-02-21 00:00:00", + "2082-02-22 00:00:00", + "2082-02-28 00:00:00", + "2082-03-01 00:00:00", + "2082-03-07 00:00:00", + "2082-03-08 00:00:00", + "2082-03-14 00:00:00", + "2082-03-15 00:00:00", + "2082-03-21 00:00:00", + "2082-03-22 00:00:00", + "2082-03-28 00:00:00", + "2082-03-29 00:00:00", + "2082-04-04 00:00:00", + "2082-04-05 00:00:00", + "2082-04-06 00:00:00", + "2082-04-11 00:00:00", + "2082-04-12 00:00:00", + "2082-04-18 00:00:00", + "2082-04-19 00:00:00", + "2082-04-25 00:00:00", + "2082-04-26 00:00:00", + "2082-05-01 00:00:00", + "2082-05-02 00:00:00", + "2082-05-03 00:00:00", + "2082-05-04 00:00:00", + "2082-05-05 00:00:00", + "2082-05-10 00:00:00", + "2082-05-16 00:00:00", + "2082-05-17 00:00:00", + "2082-05-23 00:00:00", + "2082-05-24 00:00:00", + "2082-05-30 00:00:00", + "2082-05-31 00:00:00", + "2082-06-01 00:00:00", + "2082-06-06 00:00:00", + "2082-06-07 00:00:00", + "2082-06-13 00:00:00", + "2082-06-14 00:00:00", + "2082-06-20 00:00:00", + "2082-06-21 00:00:00", + "2082-06-27 00:00:00", + "2082-06-28 00:00:00", + "2082-07-04 00:00:00", + "2082-07-05 00:00:00", + "2082-07-11 00:00:00", + "2082-07-12 00:00:00", + "2082-07-18 00:00:00", + "2082-07-19 00:00:00", + "2082-07-25 00:00:00", + "2082-07-26 00:00:00", + "2082-08-01 00:00:00", + "2082-08-02 00:00:00", + "2082-08-08 00:00:00", + "2082-08-09 00:00:00", + "2082-08-15 00:00:00", + "2082-08-16 00:00:00", + "2082-08-22 00:00:00", + "2082-08-23 00:00:00", + "2082-08-29 00:00:00", + "2082-08-30 00:00:00", + "2082-09-05 00:00:00", + "2082-09-06 00:00:00", + "2082-09-12 00:00:00", + "2082-09-13 00:00:00", + "2082-09-19 00:00:00", + "2082-09-20 00:00:00", + "2082-09-26 00:00:00", + "2082-10-01 00:00:00", + "2082-10-02 00:00:00", + "2082-10-03 00:00:00", + "2082-10-04 00:00:00", + "2082-10-05 00:00:00", + "2082-10-06 00:00:00", + "2082-10-07 00:00:00", + "2082-10-08 00:00:00", + "2082-10-11 00:00:00", + "2082-10-17 00:00:00", + "2082-10-18 00:00:00", + "2082-10-24 00:00:00", + "2082-10-25 00:00:00", + "2082-10-31 00:00:00", + "2082-11-01 00:00:00", + "2082-11-07 00:00:00", + "2082-11-08 00:00:00", + "2082-11-14 00:00:00", + "2082-11-15 00:00:00", + "2082-11-21 00:00:00", + "2082-11-22 00:00:00", + "2082-11-28 00:00:00", + "2082-11-29 00:00:00", + "2082-12-05 00:00:00", + "2082-12-06 00:00:00", + "2082-12-12 00:00:00", + "2082-12-13 00:00:00", + "2082-12-19 00:00:00", + "2082-12-20 00:00:00", + "2082-12-26 00:00:00", + "2082-12-27 00:00:00", + "2083-01-01 00:00:00", + "2083-01-02 00:00:00", + "2083-01-03 00:00:00", + "2083-01-09 00:00:00", + "2083-01-10 00:00:00", + "2083-01-16 00:00:00", + "2083-01-17 00:00:00", + "2083-01-23 00:00:00", + "2083-01-24 00:00:00", + "2083-01-30 00:00:00", + "2083-01-31 00:00:00", + "2083-02-06 00:00:00", + "2083-02-07 00:00:00", + "2083-02-13 00:00:00", + "2083-02-16 00:00:00", + "2083-02-17 00:00:00", + "2083-02-18 00:00:00", + "2083-02-19 00:00:00", + "2083-02-20 00:00:00", + "2083-02-21 00:00:00", + "2083-02-22 00:00:00", + "2083-02-23 00:00:00", + "2083-02-28 00:00:00", + "2083-03-06 00:00:00", + "2083-03-07 00:00:00", + "2083-03-13 00:00:00", + "2083-03-14 00:00:00", + "2083-03-20 00:00:00", + "2083-03-21 00:00:00", + "2083-03-27 00:00:00", + "2083-03-28 00:00:00", + "2083-04-03 00:00:00", + "2083-04-04 00:00:00", + "2083-04-05 00:00:00", + "2083-04-10 00:00:00", + "2083-04-11 00:00:00", + "2083-04-17 00:00:00", + "2083-04-18 00:00:00", + "2083-04-24 00:00:00", + "2083-04-25 00:00:00", + "2083-05-01 00:00:00", + "2083-05-02 00:00:00", + "2083-05-03 00:00:00", + "2083-05-04 00:00:00", + "2083-05-05 00:00:00", + "2083-05-08 00:00:00", + "2083-05-15 00:00:00", + "2083-05-16 00:00:00", + "2083-05-22 00:00:00", + "2083-05-23 00:00:00", + "2083-05-29 00:00:00", + "2083-05-30 00:00:00", + "2083-06-05 00:00:00", + "2083-06-06 00:00:00", + "2083-06-12 00:00:00", + "2083-06-13 00:00:00", + "2083-06-19 00:00:00", + "2083-06-20 00:00:00", + "2083-06-21 00:00:00", + "2083-06-26 00:00:00", + "2083-06-27 00:00:00", + "2083-07-03 00:00:00", + "2083-07-04 00:00:00", + "2083-07-10 00:00:00", + "2083-07-11 00:00:00", + "2083-07-17 00:00:00", + "2083-07-18 00:00:00", + "2083-07-24 00:00:00", + "2083-07-25 00:00:00", + "2083-07-31 00:00:00", + "2083-08-01 00:00:00", + "2083-08-07 00:00:00", + "2083-08-08 00:00:00", + "2083-08-14 00:00:00", + "2083-08-15 00:00:00", + "2083-08-21 00:00:00", + "2083-08-22 00:00:00", + "2083-08-28 00:00:00", + "2083-08-29 00:00:00", + "2083-09-04 00:00:00", + "2083-09-05 00:00:00", + "2083-09-11 00:00:00", + "2083-09-12 00:00:00", + "2083-09-18 00:00:00", + "2083-09-25 00:00:00", + "2083-09-26 00:00:00", + "2083-09-27 00:00:00", + "2083-10-01 00:00:00", + "2083-10-02 00:00:00", + "2083-10-03 00:00:00", + "2083-10-04 00:00:00", + "2083-10-05 00:00:00", + "2083-10-06 00:00:00", + "2083-10-07 00:00:00", + "2083-10-10 00:00:00", + "2083-10-16 00:00:00", + "2083-10-17 00:00:00", + "2083-10-23 00:00:00", + "2083-10-24 00:00:00", + "2083-10-30 00:00:00", + "2083-10-31 00:00:00", + "2083-11-06 00:00:00", + "2083-11-07 00:00:00", + "2083-11-13 00:00:00", + "2083-11-14 00:00:00", + "2083-11-20 00:00:00", + "2083-11-21 00:00:00", + "2083-11-27 00:00:00", + "2083-11-28 00:00:00", + "2083-12-04 00:00:00", + "2083-12-05 00:00:00", + "2083-12-11 00:00:00", + "2083-12-12 00:00:00", + "2083-12-18 00:00:00", + "2083-12-19 00:00:00", + "2083-12-25 00:00:00", + "2083-12-26 00:00:00", + "2084-01-01 00:00:00", + "2084-01-02 00:00:00", + "2084-01-03 00:00:00", + "2084-01-08 00:00:00", + "2084-01-09 00:00:00", + "2084-01-15 00:00:00", + "2084-01-16 00:00:00", + "2084-01-22 00:00:00", + "2084-01-23 00:00:00", + "2084-01-29 00:00:00", + "2084-02-05 00:00:00", + "2084-02-06 00:00:00", + "2084-02-07 00:00:00", + "2084-02-08 00:00:00", + "2084-02-09 00:00:00", + "2084-02-10 00:00:00", + "2084-02-11 00:00:00", + "2084-02-12 00:00:00", + "2084-02-19 00:00:00", + "2084-02-20 00:00:00", + "2084-02-26 00:00:00", + "2084-02-27 00:00:00", + "2084-03-04 00:00:00", + "2084-03-05 00:00:00", + "2084-03-11 00:00:00", + "2084-03-12 00:00:00", + "2084-03-18 00:00:00", + "2084-03-19 00:00:00", + "2084-03-25 00:00:00", + "2084-03-26 00:00:00", + "2084-04-01 00:00:00", + "2084-04-02 00:00:00", + "2084-04-03 00:00:00", + "2084-04-08 00:00:00", + "2084-04-09 00:00:00", + "2084-04-15 00:00:00", + "2084-04-16 00:00:00", + "2084-04-22 00:00:00", + "2084-04-23 00:00:00", + "2084-04-29 00:00:00", + "2084-04-30 00:00:00", + "2084-05-01 00:00:00", + "2084-05-02 00:00:00", + "2084-05-03 00:00:00", + "2084-05-06 00:00:00", + "2084-05-13 00:00:00", + "2084-05-14 00:00:00", + "2084-05-20 00:00:00", + "2084-05-21 00:00:00", + "2084-05-27 00:00:00", + "2084-05-28 00:00:00", + "2084-06-03 00:00:00", + "2084-06-04 00:00:00", + "2084-06-07 00:00:00", + "2084-06-10 00:00:00", + "2084-06-11 00:00:00", + "2084-06-17 00:00:00", + "2084-06-18 00:00:00", + "2084-06-24 00:00:00", + "2084-06-25 00:00:00", + "2084-07-01 00:00:00", + "2084-07-02 00:00:00", + "2084-07-08 00:00:00", + "2084-07-09 00:00:00", + "2084-07-15 00:00:00", + "2084-07-16 00:00:00", + "2084-07-22 00:00:00", + "2084-07-23 00:00:00", + "2084-07-29 00:00:00", + "2084-07-30 00:00:00", + "2084-08-05 00:00:00", + "2084-08-06 00:00:00", + "2084-08-12 00:00:00", + "2084-08-13 00:00:00", + "2084-08-19 00:00:00", + "2084-08-20 00:00:00", + "2084-08-26 00:00:00", + "2084-08-27 00:00:00", + "2084-09-02 00:00:00", + "2084-09-03 00:00:00", + "2084-09-09 00:00:00", + "2084-09-10 00:00:00", + "2084-09-14 00:00:00", + "2084-09-15 00:00:00", + "2084-09-16 00:00:00", + "2084-09-17 00:00:00", + "2084-09-23 00:00:00", + "2084-09-30 00:00:00", + "2084-10-01 00:00:00", + "2084-10-02 00:00:00", + "2084-10-03 00:00:00", + "2084-10-04 00:00:00", + "2084-10-05 00:00:00", + "2084-10-06 00:00:00", + "2084-10-07 00:00:00", + "2084-10-14 00:00:00", + "2084-10-15 00:00:00", + "2084-10-21 00:00:00", + "2084-10-22 00:00:00", + "2084-10-28 00:00:00", + "2084-10-29 00:00:00", + "2084-11-04 00:00:00", + "2084-11-05 00:00:00", + "2084-11-11 00:00:00", + "2084-11-12 00:00:00", + "2084-11-18 00:00:00", + "2084-11-19 00:00:00", + "2084-11-25 00:00:00", + "2084-11-26 00:00:00", + "2084-12-02 00:00:00", + "2084-12-03 00:00:00", + "2084-12-09 00:00:00", + "2084-12-10 00:00:00", + "2084-12-16 00:00:00", + "2084-12-17 00:00:00", + "2084-12-23 00:00:00", + "2084-12-24 00:00:00", + "2084-12-30 00:00:00", + "2084-12-31 00:00:00", + "2085-01-01 00:00:00", + "2085-01-06 00:00:00", + "2085-01-07 00:00:00", + "2085-01-13 00:00:00", + "2085-01-14 00:00:00", + "2085-01-20 00:00:00", + "2085-01-25 00:00:00", + "2085-01-26 00:00:00", + "2085-01-27 00:00:00", + "2085-01-28 00:00:00", + "2085-01-29 00:00:00", + "2085-01-30 00:00:00", + "2085-01-31 00:00:00", + "2085-02-01 00:00:00", + "2085-02-04 00:00:00", + "2085-02-10 00:00:00", + "2085-02-11 00:00:00", + "2085-02-17 00:00:00", + "2085-02-18 00:00:00", + "2085-02-24 00:00:00", + "2085-02-25 00:00:00", + "2085-03-03 00:00:00", + "2085-03-04 00:00:00", + "2085-03-10 00:00:00", + "2085-03-11 00:00:00", + "2085-03-17 00:00:00", + "2085-03-18 00:00:00", + "2085-03-24 00:00:00", + "2085-03-31 00:00:00", + "2085-04-01 00:00:00", + "2085-04-02 00:00:00", + "2085-04-03 00:00:00", + "2085-04-07 00:00:00", + "2085-04-08 00:00:00", + "2085-04-14 00:00:00", + "2085-04-15 00:00:00", + "2085-04-21 00:00:00", + "2085-04-22 00:00:00", + "2085-04-28 00:00:00", + "2085-04-29 00:00:00", + "2085-04-30 00:00:00", + "2085-05-01 00:00:00", + "2085-05-02 00:00:00", + "2085-05-05 00:00:00", + "2085-05-06 00:00:00", + "2085-05-12 00:00:00", + "2085-05-13 00:00:00", + "2085-05-19 00:00:00", + "2085-05-20 00:00:00", + "2085-05-26 00:00:00", + "2085-05-27 00:00:00", + "2085-05-28 00:00:00", + "2085-06-02 00:00:00", + "2085-06-03 00:00:00", + "2085-06-09 00:00:00", + "2085-06-10 00:00:00", + "2085-06-16 00:00:00", + "2085-06-17 00:00:00", + "2085-06-23 00:00:00", + "2085-06-24 00:00:00", + "2085-06-30 00:00:00", + "2085-07-01 00:00:00", + "2085-07-07 00:00:00", + "2085-07-08 00:00:00", + "2085-07-14 00:00:00", + "2085-07-15 00:00:00", + "2085-07-21 00:00:00", + "2085-07-22 00:00:00", + "2085-07-28 00:00:00", + "2085-07-29 00:00:00", + "2085-08-04 00:00:00", + "2085-08-05 00:00:00", + "2085-08-11 00:00:00", + "2085-08-12 00:00:00", + "2085-08-18 00:00:00", + "2085-08-19 00:00:00", + "2085-08-25 00:00:00", + "2085-08-26 00:00:00", + "2085-09-01 00:00:00", + "2085-09-02 00:00:00", + "2085-09-08 00:00:00", + "2085-09-09 00:00:00", + "2085-09-15 00:00:00", + "2085-09-16 00:00:00", + "2085-09-22 00:00:00", + "2085-09-23 00:00:00", + "2085-09-30 00:00:00", + "2085-10-01 00:00:00", + "2085-10-02 00:00:00", + "2085-10-03 00:00:00", + "2085-10-04 00:00:00", + "2085-10-05 00:00:00", + "2085-10-06 00:00:00", + "2085-10-07 00:00:00", + "2085-10-08 00:00:00", + "2085-10-14 00:00:00", + "2085-10-20 00:00:00", + "2085-10-21 00:00:00", + "2085-10-27 00:00:00", + "2085-10-28 00:00:00", + "2085-11-03 00:00:00", + "2085-11-04 00:00:00", + "2085-11-10 00:00:00", + "2085-11-11 00:00:00", + "2085-11-17 00:00:00", + "2085-11-18 00:00:00", + "2085-11-24 00:00:00", + "2085-11-25 00:00:00", + "2085-12-01 00:00:00", + "2085-12-02 00:00:00", + "2085-12-08 00:00:00", + "2085-12-09 00:00:00", + "2085-12-15 00:00:00", + "2085-12-16 00:00:00", + "2085-12-22 00:00:00", + "2085-12-23 00:00:00", + "2085-12-30 00:00:00", + "2085-12-31 00:00:00", + "2086-01-01 00:00:00", + "2086-01-05 00:00:00", + "2086-01-06 00:00:00", + "2086-01-12 00:00:00", + "2086-01-13 00:00:00", + "2086-01-19 00:00:00", + "2086-01-20 00:00:00", + "2086-01-26 00:00:00", + "2086-01-27 00:00:00", + "2086-02-02 00:00:00", + "2086-02-03 00:00:00", + "2086-02-09 00:00:00", + "2086-02-13 00:00:00", + "2086-02-14 00:00:00", + "2086-02-15 00:00:00", + "2086-02-16 00:00:00", + "2086-02-17 00:00:00", + "2086-02-18 00:00:00", + "2086-02-19 00:00:00", + "2086-02-20 00:00:00", + "2086-02-24 00:00:00", + "2086-03-02 00:00:00", + "2086-03-03 00:00:00", + "2086-03-09 00:00:00", + "2086-03-10 00:00:00", + "2086-03-16 00:00:00", + "2086-03-17 00:00:00", + "2086-03-23 00:00:00", + "2086-03-24 00:00:00", + "2086-03-30 00:00:00", + "2086-03-31 00:00:00", + "2086-04-04 00:00:00", + "2086-04-05 00:00:00", + "2086-04-06 00:00:00", + "2086-04-07 00:00:00", + "2086-04-13 00:00:00", + "2086-04-20 00:00:00", + "2086-04-21 00:00:00", + "2086-04-27 00:00:00", + "2086-04-28 00:00:00", + "2086-05-01 00:00:00", + "2086-05-02 00:00:00", + "2086-05-04 00:00:00", + "2086-05-05 00:00:00", + "2086-05-11 00:00:00", + "2086-05-12 00:00:00", + "2086-05-18 00:00:00", + "2086-05-19 00:00:00", + "2086-05-25 00:00:00", + "2086-05-26 00:00:00", + "2086-06-01 00:00:00", + "2086-06-02 00:00:00", + "2086-06-08 00:00:00", + "2086-06-09 00:00:00", + "2086-06-15 00:00:00", + "2086-06-16 00:00:00", + "2086-06-17 00:00:00", + "2086-06-22 00:00:00", + "2086-06-23 00:00:00", + "2086-06-29 00:00:00", + "2086-06-30 00:00:00", + "2086-07-06 00:00:00", + "2086-07-07 00:00:00", + "2086-07-13 00:00:00", + "2086-07-14 00:00:00", + "2086-07-20 00:00:00", + "2086-07-21 00:00:00", + "2086-07-27 00:00:00", + "2086-07-28 00:00:00", + "2086-08-03 00:00:00", + "2086-08-04 00:00:00", + "2086-08-10 00:00:00", + "2086-08-11 00:00:00", + "2086-08-17 00:00:00", + "2086-08-18 00:00:00", + "2086-08-24 00:00:00", + "2086-08-25 00:00:00", + "2086-08-31 00:00:00", + "2086-09-01 00:00:00", + "2086-09-07 00:00:00", + "2086-09-08 00:00:00", + "2086-09-14 00:00:00", + "2086-09-15 00:00:00", + "2086-09-21 00:00:00", + "2086-09-22 00:00:00", + "2086-09-23 00:00:00", + "2086-09-28 00:00:00", + "2086-10-01 00:00:00", + "2086-10-02 00:00:00", + "2086-10-03 00:00:00", + "2086-10-04 00:00:00", + "2086-10-05 00:00:00", + "2086-10-06 00:00:00", + "2086-10-07 00:00:00", + "2086-10-13 00:00:00", + "2086-10-19 00:00:00", + "2086-10-20 00:00:00", + "2086-10-26 00:00:00", + "2086-10-27 00:00:00", + "2086-11-02 00:00:00", + "2086-11-03 00:00:00", + "2086-11-09 00:00:00", + "2086-11-10 00:00:00", + "2086-11-16 00:00:00", + "2086-11-17 00:00:00", + "2086-11-23 00:00:00", + "2086-11-24 00:00:00", + "2086-11-30 00:00:00", + "2086-12-01 00:00:00", + "2086-12-07 00:00:00", + "2086-12-08 00:00:00", + "2086-12-14 00:00:00", + "2086-12-15 00:00:00", + "2086-12-21 00:00:00", + "2086-12-22 00:00:00", + "2086-12-28 00:00:00", + "2086-12-29 00:00:00", + "2087-01-01 00:00:00", + "2087-01-04 00:00:00", + "2087-01-05 00:00:00", + "2087-01-11 00:00:00", + "2087-01-12 00:00:00", + "2087-01-18 00:00:00", + "2087-01-19 00:00:00", + "2087-01-25 00:00:00", + "2087-01-26 00:00:00", + "2087-02-02 00:00:00", + "2087-02-03 00:00:00", + "2087-02-04 00:00:00", + "2087-02-05 00:00:00", + "2087-02-06 00:00:00", + "2087-02-07 00:00:00", + "2087-02-08 00:00:00", + "2087-02-09 00:00:00", + "2087-02-16 00:00:00", + "2087-02-22 00:00:00", + "2087-02-23 00:00:00", + "2087-03-01 00:00:00", + "2087-03-02 00:00:00", + "2087-03-08 00:00:00", + "2087-03-09 00:00:00", + "2087-03-15 00:00:00", + "2087-03-16 00:00:00", + "2087-03-22 00:00:00", + "2087-03-23 00:00:00", + "2087-03-29 00:00:00", + "2087-03-30 00:00:00", + "2087-04-04 00:00:00", + "2087-04-05 00:00:00", + "2087-04-06 00:00:00", + "2087-04-12 00:00:00", + "2087-04-13 00:00:00", + "2087-04-19 00:00:00", + "2087-04-20 00:00:00", + "2087-04-26 00:00:00", + "2087-05-01 00:00:00", + "2087-05-02 00:00:00", + "2087-05-03 00:00:00", + "2087-05-04 00:00:00", + "2087-05-05 00:00:00", + "2087-05-10 00:00:00", + "2087-05-11 00:00:00", + "2087-05-17 00:00:00", + "2087-05-18 00:00:00", + "2087-05-24 00:00:00", + "2087-05-25 00:00:00", + "2087-05-31 00:00:00", + "2087-06-01 00:00:00", + "2087-06-05 00:00:00", + "2087-06-06 00:00:00", + "2087-06-07 00:00:00", + "2087-06-08 00:00:00", + "2087-06-14 00:00:00", + "2087-06-21 00:00:00", + "2087-06-22 00:00:00", + "2087-06-28 00:00:00", + "2087-06-29 00:00:00", + "2087-07-05 00:00:00", + "2087-07-06 00:00:00", + "2087-07-12 00:00:00", + "2087-07-13 00:00:00", + "2087-07-19 00:00:00", + "2087-07-20 00:00:00", + "2087-07-26 00:00:00", + "2087-07-27 00:00:00", + "2087-08-02 00:00:00", + "2087-08-03 00:00:00", + "2087-08-09 00:00:00", + "2087-08-10 00:00:00", + "2087-08-16 00:00:00", + "2087-08-17 00:00:00", + "2087-08-23 00:00:00", + "2087-08-24 00:00:00", + "2087-08-30 00:00:00", + "2087-08-31 00:00:00", + "2087-09-06 00:00:00", + "2087-09-07 00:00:00", + "2087-09-11 00:00:00", + "2087-09-12 00:00:00", + "2087-09-13 00:00:00", + "2087-09-14 00:00:00", + "2087-09-20 00:00:00", + "2087-09-27 00:00:00", + "2087-10-01 00:00:00", + "2087-10-02 00:00:00", + "2087-10-03 00:00:00", + "2087-10-04 00:00:00", + "2087-10-05 00:00:00", + "2087-10-06 00:00:00", + "2087-10-07 00:00:00", + "2087-10-12 00:00:00", + "2087-10-18 00:00:00", + "2087-10-19 00:00:00", + "2087-10-25 00:00:00", + "2087-10-26 00:00:00", + "2087-11-01 00:00:00", + "2087-11-02 00:00:00", + "2087-11-08 00:00:00", + "2087-11-09 00:00:00", + "2087-11-15 00:00:00", + "2087-11-16 00:00:00", + "2087-11-22 00:00:00", + "2087-11-23 00:00:00", + "2087-11-29 00:00:00", + "2087-11-30 00:00:00", + "2087-12-06 00:00:00", + "2087-12-07 00:00:00", + "2087-12-13 00:00:00", + "2087-12-14 00:00:00", + "2087-12-20 00:00:00", + "2087-12-21 00:00:00", + "2087-12-27 00:00:00", + "2087-12-28 00:00:00", + "2088-01-01 00:00:00", + "2088-01-02 00:00:00", + "2088-01-03 00:00:00", + "2088-01-10 00:00:00", + "2088-01-11 00:00:00", + "2088-01-17 00:00:00", + "2088-01-23 00:00:00", + "2088-01-24 00:00:00", + "2088-01-25 00:00:00", + "2088-01-26 00:00:00", + "2088-01-27 00:00:00", + "2088-01-28 00:00:00", + "2088-01-29 00:00:00", + "2088-01-30 00:00:00", + "2088-02-01 00:00:00", + "2088-02-07 00:00:00", + "2088-02-08 00:00:00", + "2088-02-14 00:00:00", + "2088-02-15 00:00:00", + "2088-02-21 00:00:00", + "2088-02-22 00:00:00", + "2088-02-28 00:00:00", + "2088-02-29 00:00:00", + "2088-03-06 00:00:00", + "2088-03-07 00:00:00", + "2088-03-13 00:00:00", + "2088-03-14 00:00:00", + "2088-03-20 00:00:00", + "2088-03-21 00:00:00", + "2088-03-27 00:00:00", + "2088-03-28 00:00:00", + "2088-04-03 00:00:00", + "2088-04-04 00:00:00", + "2088-04-05 00:00:00", + "2088-04-10 00:00:00", + "2088-04-11 00:00:00", + "2088-04-17 00:00:00", + "2088-04-18 00:00:00", + "2088-04-24 00:00:00", + "2088-04-25 00:00:00", + "2088-05-01 00:00:00", + "2088-05-02 00:00:00", + "2088-05-03 00:00:00", + "2088-05-04 00:00:00", + "2088-05-05 00:00:00", + "2088-05-08 00:00:00", + "2088-05-15 00:00:00", + "2088-05-16 00:00:00", + "2088-05-22 00:00:00", + "2088-05-23 00:00:00", + "2088-05-29 00:00:00", + "2088-05-30 00:00:00", + "2088-06-05 00:00:00", + "2088-06-06 00:00:00", + "2088-06-12 00:00:00", + "2088-06-13 00:00:00", + "2088-06-19 00:00:00", + "2088-06-20 00:00:00", + "2088-06-23 00:00:00", + "2088-06-26 00:00:00", + "2088-06-27 00:00:00", + "2088-07-03 00:00:00", + "2088-07-04 00:00:00", + "2088-07-10 00:00:00", + "2088-07-11 00:00:00", + "2088-07-17 00:00:00", + "2088-07-18 00:00:00", + "2088-07-24 00:00:00", + "2088-07-25 00:00:00", + "2088-07-31 00:00:00", + "2088-08-01 00:00:00", + "2088-08-07 00:00:00", + "2088-08-08 00:00:00", + "2088-08-14 00:00:00", + "2088-08-15 00:00:00", + "2088-08-21 00:00:00", + "2088-08-22 00:00:00", + "2088-08-28 00:00:00", + "2088-08-29 00:00:00", + "2088-09-04 00:00:00", + "2088-09-05 00:00:00", + "2088-09-11 00:00:00", + "2088-09-12 00:00:00", + "2088-09-18 00:00:00", + "2088-09-19 00:00:00", + "2088-09-25 00:00:00", + "2088-09-29 00:00:00", + "2088-10-01 00:00:00", + "2088-10-02 00:00:00", + "2088-10-03 00:00:00", + "2088-10-04 00:00:00", + "2088-10-05 00:00:00", + "2088-10-06 00:00:00", + "2088-10-07 00:00:00", + "2088-10-10 00:00:00", + "2088-10-16 00:00:00", + "2088-10-17 00:00:00", + "2088-10-23 00:00:00", + "2088-10-24 00:00:00", + "2088-10-30 00:00:00", + "2088-10-31 00:00:00", + "2088-11-06 00:00:00", + "2088-11-07 00:00:00", + "2088-11-13 00:00:00", + "2088-11-14 00:00:00", + "2088-11-20 00:00:00", + "2088-11-21 00:00:00", + "2088-11-27 00:00:00", + "2088-11-28 00:00:00", + "2088-12-04 00:00:00", + "2088-12-05 00:00:00", + "2088-12-11 00:00:00", + "2088-12-12 00:00:00", + "2088-12-18 00:00:00", + "2088-12-19 00:00:00", + "2088-12-25 00:00:00", + "2088-12-26 00:00:00", + "2089-01-01 00:00:00", + "2089-01-02 00:00:00", + "2089-01-03 00:00:00", + "2089-01-08 00:00:00", + "2089-01-09 00:00:00", + "2089-01-15 00:00:00", + "2089-01-16 00:00:00", + "2089-01-22 00:00:00", + "2089-01-23 00:00:00", + "2089-01-29 00:00:00", + "2089-01-30 00:00:00", + "2089-02-05 00:00:00", + "2089-02-09 00:00:00", + "2089-02-10 00:00:00", + "2089-02-11 00:00:00", + "2089-02-12 00:00:00", + "2089-02-13 00:00:00", + "2089-02-14 00:00:00", + "2089-02-15 00:00:00", + "2089-02-16 00:00:00", + "2089-02-20 00:00:00", + "2089-02-26 00:00:00", + "2089-02-27 00:00:00", + "2089-03-05 00:00:00", + "2089-03-06 00:00:00", + "2089-03-12 00:00:00", + "2089-03-13 00:00:00", + "2089-03-19 00:00:00", + "2089-03-20 00:00:00", + "2089-03-26 00:00:00", + "2089-03-27 00:00:00", + "2089-04-02 00:00:00", + "2089-04-03 00:00:00", + "2089-04-04 00:00:00", + "2089-04-09 00:00:00", + "2089-04-10 00:00:00", + "2089-04-16 00:00:00", + "2089-04-17 00:00:00", + "2089-04-23 00:00:00", + "2089-04-24 00:00:00", + "2089-04-30 00:00:00", + "2089-05-01 00:00:00", + "2089-05-02 00:00:00", + "2089-05-03 00:00:00", + "2089-05-04 00:00:00", + "2089-05-07 00:00:00", + "2089-05-14 00:00:00", + "2089-05-15 00:00:00", + "2089-05-21 00:00:00", + "2089-05-22 00:00:00", + "2089-05-28 00:00:00", + "2089-05-29 00:00:00", + "2089-06-04 00:00:00", + "2089-06-05 00:00:00", + "2089-06-11 00:00:00", + "2089-06-12 00:00:00", + "2089-06-13 00:00:00", + "2089-06-18 00:00:00", + "2089-06-19 00:00:00", + "2089-06-25 00:00:00", + "2089-06-26 00:00:00", + "2089-07-02 00:00:00", + "2089-07-03 00:00:00", + "2089-07-09 00:00:00", + "2089-07-10 00:00:00", + "2089-07-16 00:00:00", + "2089-07-17 00:00:00", + "2089-07-23 00:00:00", + "2089-07-24 00:00:00", + "2089-07-30 00:00:00", + "2089-07-31 00:00:00", + "2089-08-06 00:00:00", + "2089-08-07 00:00:00", + "2089-08-13 00:00:00", + "2089-08-14 00:00:00", + "2089-08-20 00:00:00", + "2089-08-21 00:00:00", + "2089-08-27 00:00:00", + "2089-08-28 00:00:00", + "2089-09-03 00:00:00", + "2089-09-04 00:00:00", + "2089-09-10 00:00:00", + "2089-09-11 00:00:00", + "2089-09-17 00:00:00", + "2089-09-18 00:00:00", + "2089-09-19 00:00:00", + "2089-09-24 00:00:00", + "2089-10-01 00:00:00", + "2089-10-02 00:00:00", + "2089-10-03 00:00:00", + "2089-10-04 00:00:00", + "2089-10-05 00:00:00", + "2089-10-06 00:00:00", + "2089-10-07 00:00:00", + "2089-10-08 00:00:00", + "2089-10-15 00:00:00", + "2089-10-16 00:00:00", + "2089-10-22 00:00:00", + "2089-10-23 00:00:00", + "2089-10-29 00:00:00", + "2089-10-30 00:00:00", + "2089-11-05 00:00:00", + "2089-11-06 00:00:00", + "2089-11-12 00:00:00", + "2089-11-13 00:00:00", + "2089-11-19 00:00:00", + "2089-11-20 00:00:00", + "2089-11-26 00:00:00", + "2089-11-27 00:00:00", + "2089-12-03 00:00:00", + "2089-12-04 00:00:00", + "2089-12-10 00:00:00", + "2089-12-11 00:00:00", + "2089-12-17 00:00:00", + "2089-12-18 00:00:00", + "2089-12-24 00:00:00", + "2089-12-25 00:00:00", + "2089-12-31 00:00:00", + "2090-01-01 00:00:00", + "2090-01-02 00:00:00", + "2090-01-07 00:00:00", + "2090-01-08 00:00:00", + "2090-01-14 00:00:00", + "2090-01-15 00:00:00", + "2090-01-21 00:00:00", + "2090-01-22 00:00:00", + "2090-01-29 00:00:00", + "2090-01-30 00:00:00", + "2090-01-31 00:00:00", + "2090-02-01 00:00:00", + "2090-02-02 00:00:00", + "2090-02-03 00:00:00", + "2090-02-04 00:00:00", + "2090-02-05 00:00:00", + "2090-02-12 00:00:00", + "2090-02-18 00:00:00", + "2090-02-19 00:00:00", + "2090-02-25 00:00:00", + "2090-02-26 00:00:00", + "2090-03-04 00:00:00", + "2090-03-05 00:00:00", + "2090-03-11 00:00:00", + "2090-03-12 00:00:00", + "2090-03-18 00:00:00", + "2090-03-19 00:00:00", + "2090-03-25 00:00:00", + "2090-04-01 00:00:00", + "2090-04-02 00:00:00", + "2090-04-03 00:00:00", + "2090-04-04 00:00:00", + "2090-04-08 00:00:00", + "2090-04-09 00:00:00", + "2090-04-15 00:00:00", + "2090-04-16 00:00:00", + "2090-04-22 00:00:00", + "2090-04-23 00:00:00", + "2090-04-29 00:00:00", + "2090-04-30 00:00:00", + "2090-05-01 00:00:00", + "2090-05-02 00:00:00", + "2090-05-03 00:00:00", + "2090-05-06 00:00:00", + "2090-05-13 00:00:00", + "2090-05-14 00:00:00", + "2090-05-20 00:00:00", + "2090-05-21 00:00:00", + "2090-05-27 00:00:00", + "2090-05-28 00:00:00", + "2090-06-02 00:00:00", + "2090-06-03 00:00:00", + "2090-06-04 00:00:00", + "2090-06-10 00:00:00", + "2090-06-11 00:00:00", + "2090-06-17 00:00:00", + "2090-06-18 00:00:00", + "2090-06-24 00:00:00", + "2090-06-25 00:00:00", + "2090-07-01 00:00:00", + "2090-07-02 00:00:00", + "2090-07-08 00:00:00", + "2090-07-09 00:00:00", + "2090-07-15 00:00:00", + "2090-07-16 00:00:00", + "2090-07-22 00:00:00", + "2090-07-23 00:00:00", + "2090-07-29 00:00:00", + "2090-07-30 00:00:00", + "2090-08-05 00:00:00", + "2090-08-06 00:00:00", + "2090-08-12 00:00:00", + "2090-08-13 00:00:00", + "2090-08-19 00:00:00", + "2090-08-20 00:00:00", + "2090-08-26 00:00:00", + "2090-08-27 00:00:00", + "2090-09-02 00:00:00", + "2090-09-03 00:00:00", + "2090-09-08 00:00:00", + "2090-09-09 00:00:00", + "2090-09-10 00:00:00", + "2090-09-16 00:00:00", + "2090-09-17 00:00:00", + "2090-09-23 00:00:00", + "2090-09-30 00:00:00", + "2090-10-01 00:00:00", + "2090-10-02 00:00:00", + "2090-10-03 00:00:00", + "2090-10-04 00:00:00", + "2090-10-05 00:00:00", + "2090-10-06 00:00:00", + "2090-10-07 00:00:00", + "2090-10-14 00:00:00", + "2090-10-15 00:00:00", + "2090-10-21 00:00:00", + "2090-10-22 00:00:00", + "2090-10-28 00:00:00", + "2090-10-29 00:00:00", + "2090-11-04 00:00:00", + "2090-11-05 00:00:00", + "2090-11-11 00:00:00", + "2090-11-12 00:00:00", + "2090-11-18 00:00:00", + "2090-11-19 00:00:00", + "2090-11-25 00:00:00", + "2090-11-26 00:00:00", + "2090-12-02 00:00:00", + "2090-12-03 00:00:00", + "2090-12-09 00:00:00", + "2090-12-10 00:00:00", + "2090-12-16 00:00:00", + "2090-12-17 00:00:00", + "2090-12-23 00:00:00", + "2090-12-24 00:00:00", + "2090-12-30 00:00:00", + "2090-12-31 00:00:00", + "2091-01-01 00:00:00", + "2091-01-06 00:00:00", + "2091-01-07 00:00:00", + "2091-01-13 00:00:00", + "2091-01-14 00:00:00", + "2091-01-20 00:00:00", + "2091-01-21 00:00:00", + "2091-01-27 00:00:00", + "2091-01-28 00:00:00", + "2091-02-03 00:00:00", + "2091-02-04 00:00:00", + "2091-02-10 00:00:00", + "2091-02-17 00:00:00", + "2091-02-18 00:00:00", + "2091-02-19 00:00:00", + "2091-02-20 00:00:00", + "2091-02-21 00:00:00", + "2091-02-22 00:00:00", + "2091-02-23 00:00:00", + "2091-02-24 00:00:00", + "2091-03-03 00:00:00", + "2091-03-04 00:00:00", + "2091-03-10 00:00:00", + "2091-03-11 00:00:00", + "2091-03-17 00:00:00", + "2091-03-18 00:00:00", + "2091-03-24 00:00:00", + "2091-03-25 00:00:00", + "2091-03-31 00:00:00", + "2091-04-01 00:00:00", + "2091-04-04 00:00:00", + "2091-04-07 00:00:00", + "2091-04-08 00:00:00", + "2091-04-14 00:00:00", + "2091-04-15 00:00:00", + "2091-04-21 00:00:00", + "2091-04-22 00:00:00", + "2091-04-28 00:00:00", + "2091-04-29 00:00:00", + "2091-04-30 00:00:00", + "2091-05-01 00:00:00", + "2091-05-02 00:00:00", + "2091-05-05 00:00:00", + "2091-05-06 00:00:00", + "2091-05-12 00:00:00", + "2091-05-13 00:00:00", + "2091-05-19 00:00:00", + "2091-05-20 00:00:00", + "2091-05-26 00:00:00", + "2091-05-27 00:00:00", + "2091-06-02 00:00:00", + "2091-06-03 00:00:00", + "2091-06-09 00:00:00", + "2091-06-10 00:00:00", + "2091-06-16 00:00:00", + "2091-06-17 00:00:00", + "2091-06-21 00:00:00", + "2091-06-22 00:00:00", + "2091-06-23 00:00:00", + "2091-06-24 00:00:00", + "2091-06-30 00:00:00", + "2091-07-07 00:00:00", + "2091-07-08 00:00:00", + "2091-07-14 00:00:00", + "2091-07-15 00:00:00", + "2091-07-21 00:00:00", + "2091-07-22 00:00:00", + "2091-07-28 00:00:00", + "2091-07-29 00:00:00", + "2091-08-04 00:00:00", + "2091-08-05 00:00:00", + "2091-08-11 00:00:00", + "2091-08-12 00:00:00", + "2091-08-18 00:00:00", + "2091-08-19 00:00:00", + "2091-08-25 00:00:00", + "2091-08-26 00:00:00", + "2091-09-01 00:00:00", + "2091-09-02 00:00:00", + "2091-09-08 00:00:00", + "2091-09-09 00:00:00", + "2091-09-15 00:00:00", + "2091-09-16 00:00:00", + "2091-09-23 00:00:00", + "2091-09-27 00:00:00", + "2091-09-28 00:00:00", + "2091-09-29 00:00:00", + "2091-09-30 00:00:00", + "2091-10-01 00:00:00", + "2091-10-02 00:00:00", + "2091-10-03 00:00:00", + "2091-10-04 00:00:00", + "2091-10-05 00:00:00", + "2091-10-06 00:00:00", + "2091-10-07 00:00:00", + "2091-10-14 00:00:00", + "2091-10-20 00:00:00", + "2091-10-21 00:00:00", + "2091-10-27 00:00:00", + "2091-10-28 00:00:00", + "2091-11-03 00:00:00", + "2091-11-04 00:00:00", + "2091-11-10 00:00:00", + "2091-11-11 00:00:00", + "2091-11-17 00:00:00", + "2091-11-18 00:00:00", + "2091-11-24 00:00:00", + "2091-11-25 00:00:00", + "2091-12-01 00:00:00", + "2091-12-02 00:00:00", + "2091-12-08 00:00:00", + "2091-12-09 00:00:00", + "2091-12-15 00:00:00", + "2091-12-16 00:00:00", + "2091-12-22 00:00:00", + "2091-12-23 00:00:00", + "2091-12-30 00:00:00", + "2091-12-31 00:00:00", + "2092-01-01 00:00:00", + "2092-01-05 00:00:00", + "2092-01-06 00:00:00", + "2092-01-12 00:00:00", + "2092-01-13 00:00:00", + "2092-01-19 00:00:00", + "2092-01-20 00:00:00", + "2092-01-26 00:00:00", + "2092-01-27 00:00:00", + "2092-02-02 00:00:00", + "2092-02-06 00:00:00", + "2092-02-07 00:00:00", + "2092-02-08 00:00:00", + "2092-02-09 00:00:00", + "2092-02-10 00:00:00", + "2092-02-11 00:00:00", + "2092-02-12 00:00:00", + "2092-02-13 00:00:00", + "2092-02-17 00:00:00", + "2092-02-23 00:00:00", + "2092-02-24 00:00:00", + "2092-03-01 00:00:00", + "2092-03-02 00:00:00", + "2092-03-08 00:00:00", + "2092-03-09 00:00:00", + "2092-03-15 00:00:00", + "2092-03-16 00:00:00", + "2092-03-22 00:00:00", + "2092-03-23 00:00:00", + "2092-03-29 00:00:00", + "2092-03-30 00:00:00", + "2092-04-03 00:00:00", + "2092-04-04 00:00:00", + "2092-04-05 00:00:00", + "2092-04-06 00:00:00", + "2092-04-12 00:00:00", + "2092-04-19 00:00:00", + "2092-04-20 00:00:00", + "2092-04-26 00:00:00", + "2092-05-01 00:00:00", + "2092-05-02 00:00:00", + "2092-05-03 00:00:00", + "2092-05-04 00:00:00", + "2092-05-05 00:00:00", + "2092-05-10 00:00:00", + "2092-05-11 00:00:00", + "2092-05-17 00:00:00", + "2092-05-18 00:00:00", + "2092-05-24 00:00:00", + "2092-05-25 00:00:00", + "2092-05-31 00:00:00", + "2092-06-01 00:00:00", + "2092-06-07 00:00:00", + "2092-06-08 00:00:00", + "2092-06-09 00:00:00", + "2092-06-14 00:00:00", + "2092-06-15 00:00:00", + "2092-06-21 00:00:00", + "2092-06-22 00:00:00", + "2092-06-28 00:00:00", + "2092-06-29 00:00:00", + "2092-07-05 00:00:00", + "2092-07-06 00:00:00", + "2092-07-12 00:00:00", + "2092-07-13 00:00:00", + "2092-07-19 00:00:00", + "2092-07-20 00:00:00", + "2092-07-26 00:00:00", + "2092-07-27 00:00:00", + "2092-08-02 00:00:00", + "2092-08-03 00:00:00", + "2092-08-09 00:00:00", + "2092-08-10 00:00:00", + "2092-08-16 00:00:00", + "2092-08-17 00:00:00", + "2092-08-23 00:00:00", + "2092-08-24 00:00:00", + "2092-08-30 00:00:00", + "2092-08-31 00:00:00", + "2092-09-06 00:00:00", + "2092-09-13 00:00:00", + "2092-09-14 00:00:00", + "2092-09-15 00:00:00", + "2092-09-16 00:00:00", + "2092-09-20 00:00:00", + "2092-09-21 00:00:00", + "2092-09-27 00:00:00", + "2092-10-01 00:00:00", + "2092-10-02 00:00:00", + "2092-10-03 00:00:00", + "2092-10-04 00:00:00", + "2092-10-05 00:00:00", + "2092-10-06 00:00:00", + "2092-10-07 00:00:00", + "2092-10-12 00:00:00", + "2092-10-18 00:00:00", + "2092-10-19 00:00:00", + "2092-10-25 00:00:00", + "2092-10-26 00:00:00", + "2092-11-01 00:00:00", + "2092-11-02 00:00:00", + "2092-11-08 00:00:00", + "2092-11-09 00:00:00", + "2092-11-15 00:00:00", + "2092-11-16 00:00:00", + "2092-11-22 00:00:00", + "2092-11-23 00:00:00", + "2092-11-29 00:00:00", + "2092-11-30 00:00:00", + "2092-12-06 00:00:00", + "2092-12-07 00:00:00", + "2092-12-13 00:00:00", + "2092-12-14 00:00:00", + "2092-12-20 00:00:00", + "2092-12-21 00:00:00", + "2092-12-27 00:00:00", + "2092-12-28 00:00:00", + "2093-01-01 00:00:00", + "2093-01-02 00:00:00", + "2093-01-03 00:00:00", + "2093-01-10 00:00:00", + "2093-01-11 00:00:00", + "2093-01-17 00:00:00", + "2093-01-18 00:00:00", + "2093-01-25 00:00:00", + "2093-01-26 00:00:00", + "2093-01-27 00:00:00", + "2093-01-28 00:00:00", + "2093-01-29 00:00:00", + "2093-01-30 00:00:00", + "2093-01-31 00:00:00", + "2093-02-01 00:00:00", + "2093-02-02 00:00:00", + "2093-02-08 00:00:00", + "2093-02-14 00:00:00", + "2093-02-15 00:00:00", + "2093-02-21 00:00:00", + "2093-02-22 00:00:00", + "2093-02-28 00:00:00", + "2093-03-01 00:00:00", + "2093-03-07 00:00:00", + "2093-03-08 00:00:00", + "2093-03-14 00:00:00", + "2093-03-15 00:00:00", + "2093-03-21 00:00:00", + "2093-03-22 00:00:00", + "2093-03-28 00:00:00", + "2093-03-29 00:00:00", + "2093-04-03 00:00:00", + "2093-04-04 00:00:00", + "2093-04-05 00:00:00", + "2093-04-11 00:00:00", + "2093-04-12 00:00:00", + "2093-04-18 00:00:00", + "2093-04-19 00:00:00", + "2093-04-25 00:00:00", + "2093-04-26 00:00:00", + "2093-05-01 00:00:00", + "2093-05-02 00:00:00", + "2093-05-03 00:00:00", + "2093-05-04 00:00:00", + "2093-05-05 00:00:00", + "2093-05-10 00:00:00", + "2093-05-16 00:00:00", + "2093-05-17 00:00:00", + "2093-05-23 00:00:00", + "2093-05-24 00:00:00", + "2093-05-29 00:00:00", + "2093-05-30 00:00:00", + "2093-05-31 00:00:00", + "2093-06-06 00:00:00", + "2093-06-07 00:00:00", + "2093-06-13 00:00:00", + "2093-06-14 00:00:00", + "2093-06-20 00:00:00", + "2093-06-21 00:00:00", + "2093-06-27 00:00:00", + "2093-06-28 00:00:00", + "2093-07-04 00:00:00", + "2093-07-05 00:00:00", + "2093-07-11 00:00:00", + "2093-07-12 00:00:00", + "2093-07-18 00:00:00", + "2093-07-19 00:00:00", + "2093-07-25 00:00:00", + "2093-07-26 00:00:00", + "2093-08-01 00:00:00", + "2093-08-02 00:00:00", + "2093-08-08 00:00:00", + "2093-08-09 00:00:00", + "2093-08-15 00:00:00", + "2093-08-16 00:00:00", + "2093-08-22 00:00:00", + "2093-08-23 00:00:00", + "2093-08-29 00:00:00", + "2093-08-30 00:00:00", + "2093-09-05 00:00:00", + "2093-09-06 00:00:00", + "2093-09-12 00:00:00", + "2093-09-13 00:00:00", + "2093-09-19 00:00:00", + "2093-09-20 00:00:00", + "2093-09-26 00:00:00", + "2093-10-01 00:00:00", + "2093-10-02 00:00:00", + "2093-10-03 00:00:00", + "2093-10-04 00:00:00", + "2093-10-05 00:00:00", + "2093-10-06 00:00:00", + "2093-10-07 00:00:00", + "2093-10-08 00:00:00", + "2093-10-11 00:00:00", + "2093-10-17 00:00:00", + "2093-10-18 00:00:00", + "2093-10-24 00:00:00", + "2093-10-25 00:00:00", + "2093-10-31 00:00:00", + "2093-11-01 00:00:00", + "2093-11-07 00:00:00", + "2093-11-08 00:00:00", + "2093-11-14 00:00:00", + "2093-11-15 00:00:00", + "2093-11-21 00:00:00", + "2093-11-22 00:00:00", + "2093-11-28 00:00:00", + "2093-11-29 00:00:00", + "2093-12-05 00:00:00", + "2093-12-06 00:00:00", + "2093-12-12 00:00:00", + "2093-12-13 00:00:00", + "2093-12-19 00:00:00", + "2093-12-20 00:00:00", + "2093-12-26 00:00:00", + "2093-12-27 00:00:00", + "2094-01-01 00:00:00", + "2094-01-02 00:00:00", + "2094-01-03 00:00:00", + "2094-01-09 00:00:00", + "2094-01-10 00:00:00", + "2094-01-16 00:00:00", + "2094-01-17 00:00:00", + "2094-01-23 00:00:00", + "2094-01-24 00:00:00", + "2094-01-30 00:00:00", + "2094-01-31 00:00:00", + "2094-02-06 00:00:00", + "2094-02-07 00:00:00", + "2094-02-14 00:00:00", + "2094-02-15 00:00:00", + "2094-02-16 00:00:00", + "2094-02-17 00:00:00", + "2094-02-18 00:00:00", + "2094-02-19 00:00:00", + "2094-02-20 00:00:00", + "2094-02-21 00:00:00", + "2094-02-28 00:00:00", + "2094-03-06 00:00:00", + "2094-03-07 00:00:00", + "2094-03-13 00:00:00", + "2094-03-14 00:00:00", + "2094-03-20 00:00:00", + "2094-03-21 00:00:00", + "2094-03-27 00:00:00", + "2094-03-28 00:00:00", + "2094-04-03 00:00:00", + "2094-04-04 00:00:00", + "2094-04-05 00:00:00", + "2094-04-10 00:00:00", + "2094-04-11 00:00:00", + "2094-04-17 00:00:00", + "2094-04-18 00:00:00", + "2094-04-24 00:00:00", + "2094-04-25 00:00:00", + "2094-05-01 00:00:00", + "2094-05-02 00:00:00", + "2094-05-03 00:00:00", + "2094-05-04 00:00:00", + "2094-05-05 00:00:00", + "2094-05-08 00:00:00", + "2094-05-15 00:00:00", + "2094-05-16 00:00:00", + "2094-05-22 00:00:00", + "2094-05-23 00:00:00", + "2094-05-29 00:00:00", + "2094-05-30 00:00:00", + "2094-06-05 00:00:00", + "2094-06-06 00:00:00", + "2094-06-12 00:00:00", + "2094-06-13 00:00:00", + "2094-06-17 00:00:00", + "2094-06-18 00:00:00", + "2094-06-19 00:00:00", + "2094-06-20 00:00:00", + "2094-06-26 00:00:00", + "2094-07-03 00:00:00", + "2094-07-04 00:00:00", + "2094-07-10 00:00:00", + "2094-07-11 00:00:00", + "2094-07-17 00:00:00", + "2094-07-18 00:00:00", + "2094-07-24 00:00:00", + "2094-07-25 00:00:00", + "2094-07-31 00:00:00", + "2094-08-01 00:00:00", + "2094-08-07 00:00:00", + "2094-08-08 00:00:00", + "2094-08-14 00:00:00", + "2094-08-15 00:00:00", + "2094-08-21 00:00:00", + "2094-08-22 00:00:00", + "2094-08-28 00:00:00", + "2094-08-29 00:00:00", + "2094-09-04 00:00:00", + "2094-09-05 00:00:00", + "2094-09-11 00:00:00", + "2094-09-12 00:00:00", + "2094-09-18 00:00:00", + "2094-09-24 00:00:00", + "2094-09-25 00:00:00", + "2094-09-26 00:00:00", + "2094-10-01 00:00:00", + "2094-10-02 00:00:00", + "2094-10-03 00:00:00", + "2094-10-04 00:00:00", + "2094-10-05 00:00:00", + "2094-10-06 00:00:00", + "2094-10-07 00:00:00", + "2094-10-10 00:00:00", + "2094-10-16 00:00:00", + "2094-10-17 00:00:00", + "2094-10-23 00:00:00", + "2094-10-24 00:00:00", + "2094-10-30 00:00:00", + "2094-10-31 00:00:00", + "2094-11-06 00:00:00", + "2094-11-07 00:00:00", + "2094-11-13 00:00:00", + "2094-11-14 00:00:00", + "2094-11-20 00:00:00", + "2094-11-21 00:00:00", + "2094-11-27 00:00:00", + "2094-11-28 00:00:00", + "2094-12-04 00:00:00", + "2094-12-05 00:00:00", + "2094-12-11 00:00:00", + "2094-12-12 00:00:00", + "2094-12-18 00:00:00", + "2094-12-19 00:00:00", + "2094-12-25 00:00:00", + "2094-12-26 00:00:00", + "2095-01-01 00:00:00", + "2095-01-02 00:00:00", + "2095-01-03 00:00:00", + "2095-01-08 00:00:00", + "2095-01-09 00:00:00", + "2095-01-15 00:00:00", + "2095-01-16 00:00:00", + "2095-01-22 00:00:00", + "2095-01-23 00:00:00", + "2095-01-29 00:00:00", + "2095-02-04 00:00:00", + "2095-02-05 00:00:00", + "2095-02-06 00:00:00", + "2095-02-07 00:00:00", + "2095-02-08 00:00:00", + "2095-02-09 00:00:00", + "2095-02-10 00:00:00", + "2095-02-11 00:00:00", + "2095-02-13 00:00:00", + "2095-02-19 00:00:00", + "2095-02-20 00:00:00", + "2095-02-26 00:00:00", + "2095-02-27 00:00:00", + "2095-03-05 00:00:00", + "2095-03-06 00:00:00", + "2095-03-12 00:00:00", + "2095-03-13 00:00:00", + "2095-03-19 00:00:00", + "2095-03-20 00:00:00", + "2095-03-26 00:00:00", + "2095-03-27 00:00:00", + "2095-04-02 00:00:00", + "2095-04-03 00:00:00", + "2095-04-04 00:00:00", + "2095-04-09 00:00:00", + "2095-04-10 00:00:00", + "2095-04-16 00:00:00", + "2095-04-17 00:00:00", + "2095-04-23 00:00:00", + "2095-04-24 00:00:00", + "2095-04-30 00:00:00", + "2095-05-01 00:00:00", + "2095-05-02 00:00:00", + "2095-05-03 00:00:00", + "2095-05-04 00:00:00", + "2095-05-07 00:00:00", + "2095-05-14 00:00:00", + "2095-05-15 00:00:00", + "2095-05-21 00:00:00", + "2095-05-22 00:00:00", + "2095-05-28 00:00:00", + "2095-05-29 00:00:00", + "2095-06-04 00:00:00", + "2095-06-05 00:00:00", + "2095-06-06 00:00:00", + "2095-06-11 00:00:00", + "2095-06-12 00:00:00", + "2095-06-18 00:00:00", + "2095-06-19 00:00:00", + "2095-06-25 00:00:00", + "2095-06-26 00:00:00", + "2095-07-02 00:00:00", + "2095-07-03 00:00:00", + "2095-07-09 00:00:00", + "2095-07-10 00:00:00", + "2095-07-16 00:00:00", + "2095-07-17 00:00:00", + "2095-07-23 00:00:00", + "2095-07-24 00:00:00", + "2095-07-30 00:00:00", + "2095-07-31 00:00:00", + "2095-08-06 00:00:00", + "2095-08-07 00:00:00", + "2095-08-13 00:00:00", + "2095-08-14 00:00:00", + "2095-08-20 00:00:00", + "2095-08-21 00:00:00", + "2095-08-27 00:00:00", + "2095-08-28 00:00:00", + "2095-09-03 00:00:00", + "2095-09-10 00:00:00", + "2095-09-11 00:00:00", + "2095-09-12 00:00:00", + "2095-09-13 00:00:00", + "2095-09-17 00:00:00", + "2095-09-18 00:00:00", + "2095-09-24 00:00:00", + "2095-10-01 00:00:00", + "2095-10-02 00:00:00", + "2095-10-03 00:00:00", + "2095-10-04 00:00:00", + "2095-10-05 00:00:00", + "2095-10-06 00:00:00", + "2095-10-07 00:00:00", + "2095-10-08 00:00:00", + "2095-10-15 00:00:00", + "2095-10-16 00:00:00", + "2095-10-22 00:00:00", + "2095-10-23 00:00:00", + "2095-10-29 00:00:00", + "2095-10-30 00:00:00", + "2095-11-05 00:00:00", + "2095-11-06 00:00:00", + "2095-11-12 00:00:00", + "2095-11-13 00:00:00", + "2095-11-19 00:00:00", + "2095-11-20 00:00:00", + "2095-11-26 00:00:00", + "2095-11-27 00:00:00", + "2095-12-03 00:00:00", + "2095-12-04 00:00:00", + "2095-12-10 00:00:00", + "2095-12-11 00:00:00", + "2095-12-17 00:00:00", + "2095-12-18 00:00:00", + "2095-12-24 00:00:00", + "2095-12-25 00:00:00", + "2095-12-31 00:00:00", + "2096-01-01 00:00:00", + "2096-01-02 00:00:00", + "2096-01-07 00:00:00", + "2096-01-08 00:00:00", + "2096-01-14 00:00:00", + "2096-01-15 00:00:00", + "2096-01-21 00:00:00", + "2096-01-24 00:00:00", + "2096-01-25 00:00:00", + "2096-01-26 00:00:00", + "2096-01-27 00:00:00", + "2096-01-28 00:00:00", + "2096-01-29 00:00:00", + "2096-01-30 00:00:00", + "2096-01-31 00:00:00", + "2096-02-05 00:00:00", + "2096-02-11 00:00:00", + "2096-02-12 00:00:00", + "2096-02-18 00:00:00", + "2096-02-19 00:00:00", + "2096-02-25 00:00:00", + "2096-02-26 00:00:00", + "2096-03-03 00:00:00", + "2096-03-04 00:00:00", + "2096-03-10 00:00:00", + "2096-03-11 00:00:00", + "2096-03-17 00:00:00", + "2096-03-18 00:00:00", + "2096-03-24 00:00:00", + "2096-03-31 00:00:00", + "2096-04-01 00:00:00", + "2096-04-02 00:00:00", + "2096-04-03 00:00:00", + "2096-04-07 00:00:00", + "2096-04-08 00:00:00", + "2096-04-14 00:00:00", + "2096-04-15 00:00:00", + "2096-04-21 00:00:00", + "2096-04-22 00:00:00", + "2096-04-28 00:00:00", + "2096-04-29 00:00:00", + "2096-04-30 00:00:00", + "2096-05-01 00:00:00", + "2096-05-02 00:00:00", + "2096-05-05 00:00:00", + "2096-05-06 00:00:00", + "2096-05-12 00:00:00", + "2096-05-13 00:00:00", + "2096-05-19 00:00:00", + "2096-05-20 00:00:00", + "2096-05-26 00:00:00", + "2096-05-27 00:00:00", + "2096-06-02 00:00:00", + "2096-06-03 00:00:00", + "2096-06-09 00:00:00", + "2096-06-10 00:00:00", + "2096-06-16 00:00:00", + "2096-06-17 00:00:00", + "2096-06-23 00:00:00", + "2096-06-24 00:00:00", + "2096-06-25 00:00:00", + "2096-06-30 00:00:00", + "2096-07-01 00:00:00", + "2096-07-07 00:00:00", + "2096-07-08 00:00:00", + "2096-07-14 00:00:00", + "2096-07-15 00:00:00", + "2096-07-21 00:00:00", + "2096-07-22 00:00:00", + "2096-07-28 00:00:00", + "2096-07-29 00:00:00", + "2096-08-04 00:00:00", + "2096-08-05 00:00:00", + "2096-08-11 00:00:00", + "2096-08-12 00:00:00", + "2096-08-18 00:00:00", + "2096-08-19 00:00:00", + "2096-08-25 00:00:00", + "2096-08-26 00:00:00", + "2096-09-01 00:00:00", + "2096-09-02 00:00:00", + "2096-09-08 00:00:00", + "2096-09-09 00:00:00", + "2096-09-15 00:00:00", + "2096-09-16 00:00:00", + "2096-09-23 00:00:00", + "2096-09-29 00:00:00", + "2096-09-30 00:00:00", + "2096-10-01 00:00:00", + "2096-10-02 00:00:00", + "2096-10-03 00:00:00", + "2096-10-04 00:00:00", + "2096-10-05 00:00:00", + "2096-10-06 00:00:00", + "2096-10-07 00:00:00", + "2096-10-14 00:00:00", + "2096-10-20 00:00:00", + "2096-10-21 00:00:00", + "2096-10-27 00:00:00", + "2096-10-28 00:00:00", + "2096-11-03 00:00:00", + "2096-11-04 00:00:00", + "2096-11-10 00:00:00", + "2096-11-11 00:00:00", + "2096-11-17 00:00:00", + "2096-11-18 00:00:00", + "2096-11-24 00:00:00", + "2096-11-25 00:00:00", + "2096-12-01 00:00:00", + "2096-12-02 00:00:00", + "2096-12-08 00:00:00", + "2096-12-09 00:00:00", + "2096-12-15 00:00:00", + "2096-12-16 00:00:00", + "2096-12-22 00:00:00", + "2096-12-23 00:00:00", + "2096-12-30 00:00:00", + "2096-12-31 00:00:00", + "2097-01-01 00:00:00", + "2097-01-05 00:00:00", + "2097-01-06 00:00:00", + "2097-01-12 00:00:00", + "2097-01-13 00:00:00", + "2097-01-19 00:00:00", + "2097-01-20 00:00:00", + "2097-01-26 00:00:00", + "2097-01-27 00:00:00", + "2097-02-02 00:00:00", + "2097-02-03 00:00:00", + "2097-02-10 00:00:00", + "2097-02-11 00:00:00", + "2097-02-12 00:00:00", + "2097-02-13 00:00:00", + "2097-02-14 00:00:00", + "2097-02-15 00:00:00", + "2097-02-16 00:00:00", + "2097-02-17 00:00:00", + "2097-02-18 00:00:00", + "2097-02-24 00:00:00", + "2097-03-02 00:00:00", + "2097-03-03 00:00:00", + "2097-03-09 00:00:00", + "2097-03-10 00:00:00", + "2097-03-16 00:00:00", + "2097-03-17 00:00:00", + "2097-03-23 00:00:00", + "2097-03-24 00:00:00", + "2097-03-30 00:00:00", + "2097-03-31 00:00:00", + "2097-04-03 00:00:00", + "2097-04-06 00:00:00", + "2097-04-07 00:00:00", + "2097-04-13 00:00:00", + "2097-04-14 00:00:00", + "2097-04-20 00:00:00", + "2097-04-21 00:00:00", + "2097-04-27 00:00:00", + "2097-04-28 00:00:00", + "2097-05-01 00:00:00", + "2097-05-02 00:00:00", + "2097-05-04 00:00:00", + "2097-05-05 00:00:00", + "2097-05-11 00:00:00", + "2097-05-12 00:00:00", + "2097-05-18 00:00:00", + "2097-05-19 00:00:00", + "2097-05-25 00:00:00", + "2097-05-26 00:00:00", + "2097-06-01 00:00:00", + "2097-06-02 00:00:00", + "2097-06-08 00:00:00", + "2097-06-09 00:00:00", + "2097-06-14 00:00:00", + "2097-06-15 00:00:00", + "2097-06-16 00:00:00", + "2097-06-22 00:00:00", + "2097-06-23 00:00:00", + "2097-06-29 00:00:00", + "2097-06-30 00:00:00", + "2097-07-06 00:00:00", + "2097-07-07 00:00:00", + "2097-07-13 00:00:00", + "2097-07-14 00:00:00", + "2097-07-20 00:00:00", + "2097-07-21 00:00:00", + "2097-07-27 00:00:00", + "2097-07-28 00:00:00", + "2097-08-03 00:00:00", + "2097-08-04 00:00:00", + "2097-08-10 00:00:00", + "2097-08-11 00:00:00", + "2097-08-17 00:00:00", + "2097-08-18 00:00:00", + "2097-08-24 00:00:00", + "2097-08-25 00:00:00", + "2097-08-31 00:00:00", + "2097-09-01 00:00:00", + "2097-09-07 00:00:00", + "2097-09-08 00:00:00", + "2097-09-14 00:00:00", + "2097-09-15 00:00:00", + "2097-09-20 00:00:00", + "2097-09-21 00:00:00", + "2097-09-22 00:00:00", + "2097-09-28 00:00:00", + "2097-10-01 00:00:00", + "2097-10-02 00:00:00", + "2097-10-03 00:00:00", + "2097-10-04 00:00:00", + "2097-10-05 00:00:00", + "2097-10-06 00:00:00", + "2097-10-07 00:00:00", + "2097-10-13 00:00:00", + "2097-10-19 00:00:00", + "2097-10-20 00:00:00", + "2097-10-26 00:00:00", + "2097-10-27 00:00:00", + "2097-11-02 00:00:00", + "2097-11-03 00:00:00", + "2097-11-09 00:00:00", + "2097-11-10 00:00:00", + "2097-11-16 00:00:00", + "2097-11-17 00:00:00", + "2097-11-23 00:00:00", + "2097-11-24 00:00:00", + "2097-11-30 00:00:00", + "2097-12-01 00:00:00", + "2097-12-07 00:00:00", + "2097-12-08 00:00:00", + "2097-12-14 00:00:00", + "2097-12-15 00:00:00", + "2097-12-21 00:00:00", + "2097-12-22 00:00:00", + "2097-12-28 00:00:00", + "2097-12-29 00:00:00", + "2098-01-01 00:00:00", + "2098-01-04 00:00:00", + "2098-01-05 00:00:00", + "2098-01-11 00:00:00", + "2098-01-12 00:00:00", + "2098-01-18 00:00:00", + "2098-01-19 00:00:00", + "2098-01-25 00:00:00", + "2098-01-31 00:00:00", + "2098-02-01 00:00:00", + "2098-02-02 00:00:00", + "2098-02-03 00:00:00", + "2098-02-04 00:00:00", + "2098-02-05 00:00:00", + "2098-02-06 00:00:00", + "2098-02-07 00:00:00", + "2098-02-09 00:00:00", + "2098-02-15 00:00:00", + "2098-02-16 00:00:00", + "2098-02-22 00:00:00", + "2098-02-23 00:00:00", + "2098-03-01 00:00:00", + "2098-03-02 00:00:00", + "2098-03-08 00:00:00", + "2098-03-09 00:00:00", + "2098-03-15 00:00:00", + "2098-03-16 00:00:00", + "2098-03-22 00:00:00", + "2098-03-23 00:00:00", + "2098-03-29 00:00:00", + "2098-03-30 00:00:00", + "2098-04-04 00:00:00", + "2098-04-05 00:00:00", + "2098-04-06 00:00:00", + "2098-04-12 00:00:00", + "2098-04-13 00:00:00", + "2098-04-19 00:00:00", + "2098-04-20 00:00:00", + "2098-04-26 00:00:00", + "2098-05-01 00:00:00", + "2098-05-02 00:00:00", + "2098-05-03 00:00:00", + "2098-05-04 00:00:00", + "2098-05-05 00:00:00", + "2098-05-10 00:00:00", + "2098-05-11 00:00:00", + "2098-05-17 00:00:00", + "2098-05-18 00:00:00", + "2098-05-24 00:00:00", + "2098-05-25 00:00:00", + "2098-05-31 00:00:00", + "2098-06-01 00:00:00", + "2098-06-04 00:00:00", + "2098-06-07 00:00:00", + "2098-06-08 00:00:00", + "2098-06-14 00:00:00", + "2098-06-15 00:00:00", + "2098-06-21 00:00:00", + "2098-06-22 00:00:00", + "2098-06-28 00:00:00", + "2098-06-29 00:00:00", + "2098-07-05 00:00:00", + "2098-07-06 00:00:00", + "2098-07-12 00:00:00", + "2098-07-13 00:00:00", + "2098-07-19 00:00:00", + "2098-07-20 00:00:00", + "2098-07-26 00:00:00", + "2098-07-27 00:00:00", + "2098-08-02 00:00:00", + "2098-08-03 00:00:00", + "2098-08-09 00:00:00", + "2098-08-10 00:00:00", + "2098-08-16 00:00:00", + "2098-08-17 00:00:00", + "2098-08-23 00:00:00", + "2098-08-24 00:00:00", + "2098-08-30 00:00:00", + "2098-09-06 00:00:00", + "2098-09-07 00:00:00", + "2098-09-08 00:00:00", + "2098-09-09 00:00:00", + "2098-09-13 00:00:00", + "2098-09-14 00:00:00", + "2098-09-20 00:00:00", + "2098-09-21 00:00:00", + "2098-09-27 00:00:00", + "2098-10-01 00:00:00", + "2098-10-02 00:00:00", + "2098-10-03 00:00:00", + "2098-10-04 00:00:00", + "2098-10-05 00:00:00", + "2098-10-06 00:00:00", + "2098-10-07 00:00:00", + "2098-10-12 00:00:00", + "2098-10-18 00:00:00", + "2098-10-19 00:00:00", + "2098-10-25 00:00:00", + "2098-10-26 00:00:00", + "2098-11-01 00:00:00", + "2098-11-02 00:00:00", + "2098-11-08 00:00:00", + "2098-11-09 00:00:00", + "2098-11-15 00:00:00", + "2098-11-16 00:00:00", + "2098-11-22 00:00:00", + "2098-11-23 00:00:00", + "2098-11-29 00:00:00", + "2098-11-30 00:00:00", + "2098-12-06 00:00:00", + "2098-12-07 00:00:00", + "2098-12-13 00:00:00", + "2098-12-14 00:00:00", + "2098-12-20 00:00:00", + "2098-12-21 00:00:00", + "2098-12-27 00:00:00", + "2098-12-28 00:00:00", + "2099-01-01 00:00:00", + "2099-01-02 00:00:00", + "2099-01-03 00:00:00", + "2099-01-10 00:00:00", + "2099-01-11 00:00:00", + "2099-01-17 00:00:00", + "2099-01-20 00:00:00", + "2099-01-21 00:00:00", + "2099-01-22 00:00:00", + "2099-01-23 00:00:00", + "2099-01-24 00:00:00", + "2099-01-25 00:00:00", + "2099-01-26 00:00:00", + "2099-01-27 00:00:00", + "2099-02-01 00:00:00", + "2099-02-07 00:00:00", + "2099-02-08 00:00:00", + "2099-02-14 00:00:00", + "2099-02-15 00:00:00", + "2099-02-21 00:00:00", + "2099-02-22 00:00:00", + "2099-02-28 00:00:00", + "2099-03-01 00:00:00", + "2099-03-07 00:00:00", + "2099-03-08 00:00:00", + "2099-03-14 00:00:00", + "2099-03-15 00:00:00", + "2099-03-21 00:00:00", + "2099-03-22 00:00:00", + "2099-03-28 00:00:00", + "2099-03-29 00:00:00", + "2099-04-04 00:00:00", + "2099-04-05 00:00:00", + "2099-04-06 00:00:00", + "2099-04-11 00:00:00", + "2099-04-12 00:00:00", + "2099-04-18 00:00:00", + "2099-04-19 00:00:00", + "2099-04-25 00:00:00", + "2099-04-26 00:00:00", + "2099-05-01 00:00:00", + "2099-05-02 00:00:00", + "2099-05-03 00:00:00", + "2099-05-04 00:00:00", + "2099-05-05 00:00:00", + "2099-05-10 00:00:00", + "2099-05-16 00:00:00", + "2099-05-17 00:00:00", + "2099-05-23 00:00:00", + "2099-05-24 00:00:00", + "2099-05-30 00:00:00", + "2099-05-31 00:00:00", + "2099-06-06 00:00:00", + "2099-06-07 00:00:00", + "2099-06-13 00:00:00", + "2099-06-20 00:00:00", + "2099-06-21 00:00:00", + "2099-06-22 00:00:00", + "2099-06-23 00:00:00", + "2099-06-27 00:00:00", + "2099-06-28 00:00:00", + "2099-07-04 00:00:00", + "2099-07-05 00:00:00", + "2099-07-11 00:00:00", + "2099-07-12 00:00:00", + "2099-07-18 00:00:00", + "2099-07-19 00:00:00", + "2099-07-25 00:00:00", + "2099-07-26 00:00:00", + "2099-08-01 00:00:00", + "2099-08-02 00:00:00", + "2099-08-08 00:00:00", + "2099-08-09 00:00:00", + "2099-08-15 00:00:00", + "2099-08-16 00:00:00", + "2099-08-22 00:00:00", + "2099-08-23 00:00:00", + "2099-08-29 00:00:00", + "2099-08-30 00:00:00", + "2099-09-05 00:00:00", + "2099-09-06 00:00:00", + "2099-09-12 00:00:00", + "2099-09-13 00:00:00", + "2099-09-19 00:00:00", + "2099-09-26 00:00:00", + "2099-09-27 00:00:00", + "2099-09-28 00:00:00", + "2099-09-29 00:00:00", + "2099-10-01 00:00:00", + "2099-10-02 00:00:00", + "2099-10-03 00:00:00", + "2099-10-04 00:00:00", + "2099-10-05 00:00:00", + "2099-10-06 00:00:00", + "2099-10-07 00:00:00", + "2099-10-11 00:00:00", + "2099-10-17 00:00:00", + "2099-10-18 00:00:00", + "2099-10-24 00:00:00", + "2099-10-25 00:00:00", + "2099-10-31 00:00:00", + "2099-11-01 00:00:00", + "2099-11-07 00:00:00", + "2099-11-08 00:00:00", + "2099-11-14 00:00:00", + "2099-11-15 00:00:00", + "2099-11-21 00:00:00", + "2099-11-22 00:00:00", + "2099-11-28 00:00:00", + "2099-11-29 00:00:00", + "2099-12-05 00:00:00", + "2099-12-06 00:00:00", + "2099-12-12 00:00:00", + "2099-12-13 00:00:00", + "2099-12-19 00:00:00", + "2099-12-20 00:00:00", + "2099-12-26 00:00:00", + "2099-12-27 00:00:00", + "2100-01-01 00:00:00", + "2100-01-02 00:00:00", + "2100-01-03 00:00:00", + "2100-01-09 00:00:00", + "2100-01-10 00:00:00", + "2100-01-16 00:00:00", + "2100-01-17 00:00:00", + "2100-01-23 00:00:00", + "2100-01-24 00:00:00", + "2100-01-30 00:00:00", + "2100-01-31 00:00:00", + "2100-02-07 00:00:00", + "2100-02-08 00:00:00", + "2100-02-09 00:00:00", + "2100-02-10 00:00:00", + "2100-02-11 00:00:00", + "2100-02-12 00:00:00", + "2100-02-13 00:00:00", + "2100-02-14 00:00:00", + "2100-02-15 00:00:00", + "2100-02-21 00:00:00", + "2100-02-27 00:00:00", + "2100-02-28 00:00:00", + "2100-03-06 00:00:00", + "2100-03-07 00:00:00", + "2100-03-13 00:00:00", + "2100-03-14 00:00:00", + "2100-03-20 00:00:00", + "2100-03-21 00:00:00", + "2100-03-27 00:00:00", + "2100-03-28 00:00:00", + "2100-04-03 00:00:00", + "2100-04-04 00:00:00", + "2100-04-05 00:00:00", + "2100-04-10 00:00:00", + "2100-04-11 00:00:00", + "2100-04-17 00:00:00", + "2100-04-18 00:00:00", + "2100-04-24 00:00:00", + "2100-04-25 00:00:00", + "2100-05-01 00:00:00", + "2100-05-02 00:00:00", + "2100-05-03 00:00:00", + "2100-05-04 00:00:00", + "2100-05-05 00:00:00", + "2100-05-08 00:00:00", + "2100-05-15 00:00:00", + "2100-05-16 00:00:00", + "2100-05-22 00:00:00", + "2100-05-23 00:00:00", + "2100-05-29 00:00:00", + "2100-05-30 00:00:00", + "2100-06-05 00:00:00", + "2100-06-06 00:00:00", + "2100-06-12 00:00:00", + "2100-06-13 00:00:00", + "2100-06-14 00:00:00", + "2100-06-19 00:00:00", + "2100-06-20 00:00:00", + "2100-06-26 00:00:00", + "2100-06-27 00:00:00", + "2100-07-03 00:00:00", + "2100-07-04 00:00:00", + "2100-07-10 00:00:00", + "2100-07-11 00:00:00", + "2100-07-17 00:00:00", + "2100-07-18 00:00:00", + "2100-07-24 00:00:00", + "2100-07-25 00:00:00", + "2100-07-31 00:00:00", + "2100-08-01 00:00:00", + "2100-08-07 00:00:00", + "2100-08-08 00:00:00", + "2100-08-14 00:00:00", + "2100-08-15 00:00:00", + "2100-08-21 00:00:00", + "2100-08-22 00:00:00", + "2100-08-28 00:00:00", + "2100-08-29 00:00:00", + "2100-09-04 00:00:00", + "2100-09-05 00:00:00", + "2100-09-11 00:00:00", + "2100-09-12 00:00:00", + "2100-09-18 00:00:00", + "2100-09-19 00:00:00", + "2100-09-20 00:00:00", + "2100-09-25 00:00:00", + "2100-10-01 00:00:00", + "2100-10-02 00:00:00", + "2100-10-03 00:00:00", + "2100-10-04 00:00:00", + "2100-10-05 00:00:00", + "2100-10-06 00:00:00", + "2100-10-07 00:00:00", + "2100-10-10 00:00:00", + "2100-10-16 00:00:00", + "2100-10-17 00:00:00", + "2100-10-23 00:00:00", + "2100-10-24 00:00:00", + "2100-10-30 00:00:00", + "2100-10-31 00:00:00", + "2100-11-06 00:00:00", + "2100-11-07 00:00:00", + "2100-11-13 00:00:00", + "2100-11-14 00:00:00", + "2100-11-20 00:00:00", + "2100-11-21 00:00:00", + "2100-11-27 00:00:00", + "2100-11-28 00:00:00", + "2100-12-04 00:00:00", + "2100-12-05 00:00:00", + "2100-12-11 00:00:00", + "2100-12-12 00:00:00", + "2100-12-18 00:00:00", + "2100-12-19 00:00:00", + "2100-12-25 00:00:00", + "2100-12-26 00:00:00", + "2101-01-01 00:00:00", + "2101-01-02 00:00:00", + "2101-01-08 00:00:00", + "2101-01-09 00:00:00", + "2101-01-15 00:00:00", + "2101-01-16 00:00:00", + "2101-01-22 00:00:00", + "2101-01-23 00:00:00", + "2101-01-29 00:00:00", + "2101-01-30 00:00:00", + "2101-02-05 00:00:00", + "2101-02-06 00:00:00", + "2101-02-12 00:00:00", + "2101-02-13 00:00:00", + "2101-02-19 00:00:00", + "2101-02-20 00:00:00", + "2101-02-26 00:00:00", + "2101-02-27 00:00:00", + "2101-03-05 00:00:00", + "2101-03-06 00:00:00", + "2101-03-12 00:00:00", + "2101-03-13 00:00:00", + "2101-03-19 00:00:00", + "2101-03-20 00:00:00", + "2101-03-26 00:00:00", + "2101-03-27 00:00:00", + "2101-04-02 00:00:00", + "2101-04-03 00:00:00", + "2101-04-09 00:00:00", + "2101-04-10 00:00:00", + "2101-04-16 00:00:00", + "2101-04-17 00:00:00", + "2101-04-23 00:00:00", + "2101-04-24 00:00:00", + "2101-04-30 00:00:00", + "2101-05-01 00:00:00", + "2101-05-07 00:00:00", + "2101-05-08 00:00:00", + "2101-05-14 00:00:00", + "2101-05-15 00:00:00", + "2101-05-21 00:00:00", + "2101-05-22 00:00:00", + "2101-05-28 00:00:00", + "2101-05-29 00:00:00", + "2101-06-04 00:00:00", + "2101-06-05 00:00:00", + "2101-06-11 00:00:00", + "2101-06-12 00:00:00", + "2101-06-18 00:00:00", + "2101-06-19 00:00:00", + "2101-06-25 00:00:00", + "2101-06-26 00:00:00", + "2101-07-02 00:00:00", + "2101-07-03 00:00:00", + "2101-07-09 00:00:00", + "2101-07-10 00:00:00", + "2101-07-16 00:00:00", + "2101-07-17 00:00:00", + "2101-07-23 00:00:00", + "2101-07-24 00:00:00", + "2101-07-30 00:00:00", + "2101-07-31 00:00:00", + "2101-08-06 00:00:00", + "2101-08-07 00:00:00", + "2101-08-13 00:00:00", + "2101-08-14 00:00:00", + "2101-08-20 00:00:00", + "2101-08-21 00:00:00", + "2101-08-27 00:00:00", + "2101-08-28 00:00:00", + "2101-09-03 00:00:00", + "2101-09-04 00:00:00", + "2101-09-10 00:00:00", + "2101-09-11 00:00:00", + "2101-09-17 00:00:00", + "2101-09-18 00:00:00", + "2101-09-24 00:00:00", + "2101-09-25 00:00:00", + "2101-10-01 00:00:00", + "2101-10-02 00:00:00", + "2101-10-08 00:00:00", + "2101-10-09 00:00:00", + "2101-10-15 00:00:00", + "2101-10-16 00:00:00", + "2101-10-22 00:00:00", + "2101-10-23 00:00:00", + "2101-10-29 00:00:00", + "2101-10-30 00:00:00", + "2101-11-05 00:00:00", + "2101-11-06 00:00:00", + "2101-11-12 00:00:00", + "2101-11-13 00:00:00", + "2101-11-19 00:00:00", + "2101-11-20 00:00:00", + "2101-11-26 00:00:00", + "2101-11-27 00:00:00", + "2101-12-03 00:00:00", + "2101-12-04 00:00:00", + "2101-12-10 00:00:00", + "2101-12-11 00:00:00", + "2101-12-17 00:00:00", + "2101-12-18 00:00:00", + "2101-12-24 00:00:00", + "2101-12-25 00:00:00", + "2101-12-31 00:00:00", + "2102-01-01 00:00:00", + "2102-01-07 00:00:00", + "2102-01-08 00:00:00", + "2102-01-14 00:00:00", + "2102-01-15 00:00:00", + "2102-01-21 00:00:00", + "2102-01-22 00:00:00", + "2102-01-28 00:00:00", + "2102-01-29 00:00:00", + "2102-02-04 00:00:00", + "2102-02-05 00:00:00", + "2102-02-11 00:00:00", + "2102-02-12 00:00:00", + "2102-02-18 00:00:00", + "2102-02-19 00:00:00", + "2102-02-25 00:00:00", + "2102-02-26 00:00:00", + "2102-03-04 00:00:00", + "2102-03-05 00:00:00", + "2102-03-11 00:00:00", + "2102-03-12 00:00:00", + "2102-03-18 00:00:00", + "2102-03-19 00:00:00", + "2102-03-25 00:00:00", + "2102-03-26 00:00:00", + "2102-04-01 00:00:00", + "2102-04-02 00:00:00", + "2102-04-08 00:00:00", + "2102-04-09 00:00:00", + "2102-04-15 00:00:00", + "2102-04-16 00:00:00", + "2102-04-22 00:00:00", + "2102-04-23 00:00:00", + "2102-04-29 00:00:00", + "2102-04-30 00:00:00", + "2102-05-06 00:00:00", + "2102-05-07 00:00:00", + "2102-05-13 00:00:00", + "2102-05-14 00:00:00", + "2102-05-20 00:00:00", + "2102-05-21 00:00:00", + "2102-05-27 00:00:00", + "2102-05-28 00:00:00", + "2102-06-03 00:00:00", + "2102-06-04 00:00:00", + "2102-06-10 00:00:00", + "2102-06-11 00:00:00", + "2102-06-17 00:00:00", + "2102-06-18 00:00:00", + "2102-06-24 00:00:00", + "2102-06-25 00:00:00", + "2102-07-01 00:00:00", + "2102-07-02 00:00:00", + "2102-07-08 00:00:00", + "2102-07-09 00:00:00", + "2102-07-15 00:00:00", + "2102-07-16 00:00:00", + "2102-07-22 00:00:00", + "2102-07-23 00:00:00", + "2102-07-29 00:00:00", + "2102-07-30 00:00:00", + "2102-08-05 00:00:00", + "2102-08-06 00:00:00", + "2102-08-12 00:00:00", + "2102-08-13 00:00:00", + "2102-08-19 00:00:00", + "2102-08-20 00:00:00", + "2102-08-26 00:00:00", + "2102-08-27 00:00:00", + "2102-09-02 00:00:00", + "2102-09-03 00:00:00", + "2102-09-09 00:00:00", + "2102-09-10 00:00:00", + "2102-09-16 00:00:00", + "2102-09-17 00:00:00", + "2102-09-23 00:00:00", + "2102-09-24 00:00:00", + "2102-09-30 00:00:00", + "2102-10-01 00:00:00", + "2102-10-07 00:00:00", + "2102-10-08 00:00:00", + "2102-10-14 00:00:00", + "2102-10-15 00:00:00", + "2102-10-21 00:00:00", + "2102-10-22 00:00:00", + "2102-10-28 00:00:00", + "2102-10-29 00:00:00", + "2102-11-04 00:00:00", + "2102-11-05 00:00:00", + "2102-11-11 00:00:00", + "2102-11-12 00:00:00", + "2102-11-18 00:00:00", + "2102-11-19 00:00:00", + "2102-11-25 00:00:00", + "2102-11-26 00:00:00", + "2102-12-02 00:00:00", + "2102-12-03 00:00:00", + "2102-12-09 00:00:00", + "2102-12-10 00:00:00", + "2102-12-16 00:00:00", + "2102-12-17 00:00:00", + "2102-12-23 00:00:00", + "2102-12-24 00:00:00", + "2102-12-30 00:00:00", + "2102-12-31 00:00:00", + "2103-01-06 00:00:00", + "2103-01-07 00:00:00", + "2103-01-13 00:00:00", + "2103-01-14 00:00:00", + "2103-01-20 00:00:00", + "2103-01-21 00:00:00", + "2103-01-27 00:00:00", + "2103-01-28 00:00:00", + "2103-02-03 00:00:00", + "2103-02-04 00:00:00", + "2103-02-10 00:00:00", + "2103-02-11 00:00:00", + "2103-02-17 00:00:00", + "2103-02-18 00:00:00", + "2103-02-24 00:00:00", + "2103-02-25 00:00:00", + "2103-03-03 00:00:00", + "2103-03-04 00:00:00", + "2103-03-10 00:00:00", + "2103-03-11 00:00:00", + "2103-03-17 00:00:00", + "2103-03-18 00:00:00", + "2103-03-24 00:00:00", + "2103-03-25 00:00:00", + "2103-03-31 00:00:00", + "2103-04-01 00:00:00", + "2103-04-07 00:00:00", + "2103-04-08 00:00:00", + "2103-04-14 00:00:00", + "2103-04-15 00:00:00", + "2103-04-21 00:00:00", + "2103-04-22 00:00:00", + "2103-04-28 00:00:00", + "2103-04-29 00:00:00", + "2103-05-05 00:00:00", + "2103-05-06 00:00:00", + "2103-05-12 00:00:00", + "2103-05-13 00:00:00", + "2103-05-19 00:00:00", + "2103-05-20 00:00:00", + "2103-05-26 00:00:00", + "2103-05-27 00:00:00", + "2103-06-02 00:00:00", + "2103-06-03 00:00:00", + "2103-06-09 00:00:00", + "2103-06-10 00:00:00", + "2103-06-16 00:00:00", + "2103-06-17 00:00:00", + "2103-06-23 00:00:00", + "2103-06-24 00:00:00", + "2103-06-30 00:00:00", + "2103-07-01 00:00:00", + "2103-07-07 00:00:00", + "2103-07-08 00:00:00", + "2103-07-14 00:00:00", + "2103-07-15 00:00:00", + "2103-07-21 00:00:00", + "2103-07-22 00:00:00", + "2103-07-28 00:00:00", + "2103-07-29 00:00:00", + "2103-08-04 00:00:00", + "2103-08-05 00:00:00", + "2103-08-11 00:00:00", + "2103-08-12 00:00:00", + "2103-08-18 00:00:00", + "2103-08-19 00:00:00", + "2103-08-25 00:00:00", + "2103-08-26 00:00:00", + "2103-09-01 00:00:00", + "2103-09-02 00:00:00", + "2103-09-08 00:00:00", + "2103-09-09 00:00:00", + "2103-09-15 00:00:00", + "2103-09-16 00:00:00", + "2103-09-22 00:00:00", + "2103-09-23 00:00:00", + "2103-09-29 00:00:00", + "2103-09-30 00:00:00", + "2103-10-06 00:00:00", + "2103-10-07 00:00:00", + "2103-10-13 00:00:00", + "2103-10-14 00:00:00", + "2103-10-20 00:00:00", + "2103-10-21 00:00:00", + "2103-10-27 00:00:00", + "2103-10-28 00:00:00", + "2103-11-03 00:00:00", + "2103-11-04 00:00:00", + "2103-11-10 00:00:00", + "2103-11-11 00:00:00", + "2103-11-17 00:00:00", + "2103-11-18 00:00:00", + "2103-11-24 00:00:00", + "2103-11-25 00:00:00", + "2103-12-01 00:00:00", + "2103-12-02 00:00:00", + "2103-12-08 00:00:00", + "2103-12-09 00:00:00", + "2103-12-15 00:00:00", + "2103-12-16 00:00:00", + "2103-12-22 00:00:00", + "2103-12-23 00:00:00", + "2103-12-29 00:00:00", + "2103-12-30 00:00:00", + "2104-01-05 00:00:00", + "2104-01-06 00:00:00", + "2104-01-12 00:00:00", + "2104-01-13 00:00:00", + "2104-01-19 00:00:00", + "2104-01-20 00:00:00", + "2104-01-26 00:00:00", + "2104-01-27 00:00:00", + "2104-02-02 00:00:00", + "2104-02-03 00:00:00", + "2104-02-09 00:00:00", + "2104-02-10 00:00:00", + "2104-02-16 00:00:00", + "2104-02-17 00:00:00", + "2104-02-23 00:00:00", + "2104-02-24 00:00:00", + "2104-03-01 00:00:00", + "2104-03-02 00:00:00", + "2104-03-08 00:00:00", + "2104-03-09 00:00:00", + "2104-03-15 00:00:00", + "2104-03-16 00:00:00", + "2104-03-22 00:00:00", + "2104-03-23 00:00:00", + "2104-03-29 00:00:00", + "2104-03-30 00:00:00", + "2104-04-05 00:00:00", + "2104-04-06 00:00:00", + "2104-04-12 00:00:00", + "2104-04-13 00:00:00", + "2104-04-19 00:00:00", + "2104-04-20 00:00:00", + "2104-04-26 00:00:00", + "2104-04-27 00:00:00", + "2104-05-03 00:00:00", + "2104-05-04 00:00:00", + "2104-05-10 00:00:00", + "2104-05-11 00:00:00", + "2104-05-17 00:00:00", + "2104-05-18 00:00:00", + "2104-05-24 00:00:00", + "2104-05-25 00:00:00", + "2104-05-31 00:00:00", + "2104-06-01 00:00:00", + "2104-06-07 00:00:00", + "2104-06-08 00:00:00", + "2104-06-14 00:00:00", + "2104-06-15 00:00:00", + "2104-06-21 00:00:00", + "2104-06-22 00:00:00", + "2104-06-28 00:00:00", + "2104-06-29 00:00:00", + "2104-07-05 00:00:00", + "2104-07-06 00:00:00", + "2104-07-12 00:00:00", + "2104-07-13 00:00:00", + "2104-07-19 00:00:00", + "2104-07-20 00:00:00", + "2104-07-26 00:00:00", + "2104-07-27 00:00:00", + "2104-08-02 00:00:00", + "2104-08-03 00:00:00", + "2104-08-09 00:00:00", + "2104-08-10 00:00:00", + "2104-08-16 00:00:00", + "2104-08-17 00:00:00", + "2104-08-23 00:00:00", + "2104-08-24 00:00:00", + "2104-08-30 00:00:00", + "2104-08-31 00:00:00", + "2104-09-06 00:00:00", + "2104-09-07 00:00:00", + "2104-09-13 00:00:00", + "2104-09-14 00:00:00", + "2104-09-20 00:00:00", + "2104-09-21 00:00:00", + "2104-09-27 00:00:00", + "2104-09-28 00:00:00", + "2104-10-04 00:00:00", + "2104-10-05 00:00:00", + "2104-10-11 00:00:00", + "2104-10-12 00:00:00", + "2104-10-18 00:00:00", + "2104-10-19 00:00:00", + "2104-10-25 00:00:00", + "2104-10-26 00:00:00", + "2104-11-01 00:00:00", + "2104-11-02 00:00:00", + "2104-11-08 00:00:00", + "2104-11-09 00:00:00", + "2104-11-15 00:00:00", + "2104-11-16 00:00:00", + "2104-11-22 00:00:00", + "2104-11-23 00:00:00", + "2104-11-29 00:00:00", + "2104-11-30 00:00:00", + "2104-12-06 00:00:00", + "2104-12-07 00:00:00", + "2104-12-13 00:00:00", + "2104-12-14 00:00:00", + "2104-12-20 00:00:00", + "2104-12-21 00:00:00", + "2104-12-27 00:00:00", + "2104-12-28 00:00:00", + "2105-01-03 00:00:00", + "2105-01-04 00:00:00", + "2105-01-10 00:00:00", + "2105-01-11 00:00:00", + "2105-01-17 00:00:00", + "2105-01-18 00:00:00", + "2105-01-24 00:00:00", + "2105-01-25 00:00:00", + "2105-01-31 00:00:00", + "2105-02-01 00:00:00", + "2105-02-07 00:00:00", + "2105-02-08 00:00:00", + "2105-02-14 00:00:00", + "2105-02-15 00:00:00", + "2105-02-21 00:00:00", + "2105-02-22 00:00:00", + "2105-02-28 00:00:00", + "2105-03-01 00:00:00", + "2105-03-07 00:00:00", + "2105-03-08 00:00:00", + "2105-03-14 00:00:00", + "2105-03-15 00:00:00", + "2105-03-21 00:00:00", + "2105-03-22 00:00:00", + "2105-03-28 00:00:00", + "2105-03-29 00:00:00", + "2105-04-04 00:00:00", + "2105-04-05 00:00:00", + "2105-04-11 00:00:00", + "2105-04-12 00:00:00", + "2105-04-18 00:00:00", + "2105-04-19 00:00:00", + "2105-04-25 00:00:00", + "2105-04-26 00:00:00", + "2105-05-02 00:00:00", + "2105-05-03 00:00:00", + "2105-05-09 00:00:00", + "2105-05-10 00:00:00", + "2105-05-16 00:00:00", + "2105-05-17 00:00:00", + "2105-05-23 00:00:00", + "2105-05-24 00:00:00", + "2105-05-30 00:00:00", + "2105-05-31 00:00:00", + "2105-06-06 00:00:00", + "2105-06-07 00:00:00", + "2105-06-13 00:00:00", + "2105-06-14 00:00:00", + "2105-06-20 00:00:00", + "2105-06-21 00:00:00", + "2105-06-27 00:00:00", + "2105-06-28 00:00:00", + "2105-07-04 00:00:00", + "2105-07-05 00:00:00", + "2105-07-11 00:00:00", + "2105-07-12 00:00:00", + "2105-07-18 00:00:00", + "2105-07-19 00:00:00", + "2105-07-25 00:00:00", + "2105-07-26 00:00:00", + "2105-08-01 00:00:00", + "2105-08-02 00:00:00", + "2105-08-08 00:00:00", + "2105-08-09 00:00:00", + "2105-08-15 00:00:00", + "2105-08-16 00:00:00", + "2105-08-22 00:00:00", + "2105-08-23 00:00:00", + "2105-08-29 00:00:00", + "2105-08-30 00:00:00", + "2105-09-05 00:00:00", + "2105-09-06 00:00:00", + "2105-09-12 00:00:00", + "2105-09-13 00:00:00", + "2105-09-19 00:00:00", + "2105-09-20 00:00:00", + "2105-09-26 00:00:00", + "2105-09-27 00:00:00", + "2105-10-03 00:00:00", + "2105-10-04 00:00:00", + "2105-10-10 00:00:00", + "2105-10-11 00:00:00", + "2105-10-17 00:00:00", + "2105-10-18 00:00:00", + "2105-10-24 00:00:00", + "2105-10-25 00:00:00", + "2105-10-31 00:00:00", + "2105-11-01 00:00:00", + "2105-11-07 00:00:00", + "2105-11-08 00:00:00", + "2105-11-14 00:00:00", + "2105-11-15 00:00:00", + "2105-11-21 00:00:00", + "2105-11-22 00:00:00", + "2105-11-28 00:00:00", + "2105-11-29 00:00:00", + "2105-12-05 00:00:00", + "2105-12-06 00:00:00", + "2105-12-12 00:00:00", + "2105-12-13 00:00:00", + "2105-12-19 00:00:00", + "2105-12-20 00:00:00", + "2105-12-26 00:00:00", + "2105-12-27 00:00:00", + "2106-01-02 00:00:00", + "2106-01-03 00:00:00", + "2106-01-09 00:00:00", + "2106-01-10 00:00:00", + "2106-01-16 00:00:00", + "2106-01-17 00:00:00", + "2106-01-23 00:00:00", + "2106-01-24 00:00:00", + "2106-01-30 00:00:00", + "2106-01-31 00:00:00", + "2106-02-06 00:00:00", + "2106-02-07 00:00:00", + "2106-02-13 00:00:00", + "2106-02-14 00:00:00", + "2106-02-20 00:00:00", + "2106-02-21 00:00:00", + "2106-02-27 00:00:00", + "2106-02-28 00:00:00", + "2106-03-06 00:00:00", + "2106-03-07 00:00:00", + "2106-03-13 00:00:00", + "2106-03-14 00:00:00", + "2106-03-20 00:00:00", + "2106-03-21 00:00:00", + "2106-03-27 00:00:00", + "2106-03-28 00:00:00", + "2106-04-03 00:00:00", + "2106-04-04 00:00:00", + "2106-04-10 00:00:00", + "2106-04-11 00:00:00", + "2106-04-17 00:00:00", + "2106-04-18 00:00:00", + "2106-04-24 00:00:00", + "2106-04-25 00:00:00", + "2106-05-01 00:00:00", + "2106-05-02 00:00:00", + "2106-05-08 00:00:00", + "2106-05-09 00:00:00", + "2106-05-15 00:00:00", + "2106-05-16 00:00:00", + "2106-05-22 00:00:00", + "2106-05-23 00:00:00", + "2106-05-29 00:00:00", + "2106-05-30 00:00:00", + "2106-06-05 00:00:00", + "2106-06-06 00:00:00", + "2106-06-12 00:00:00", + "2106-06-13 00:00:00", + "2106-06-19 00:00:00", + "2106-06-20 00:00:00", + "2106-06-26 00:00:00", + "2106-06-27 00:00:00", + "2106-07-03 00:00:00", + "2106-07-04 00:00:00", + "2106-07-10 00:00:00", + "2106-07-11 00:00:00", + "2106-07-17 00:00:00", + "2106-07-18 00:00:00", + "2106-07-24 00:00:00", + "2106-07-25 00:00:00", + "2106-07-31 00:00:00", + "2106-08-01 00:00:00", + "2106-08-07 00:00:00", + "2106-08-08 00:00:00", + "2106-08-14 00:00:00", + "2106-08-15 00:00:00", + "2106-08-21 00:00:00", + "2106-08-22 00:00:00", + "2106-08-28 00:00:00", + "2106-08-29 00:00:00", + "2106-09-04 00:00:00", + "2106-09-05 00:00:00", + "2106-09-11 00:00:00", + "2106-09-12 00:00:00", + "2106-09-18 00:00:00", + "2106-09-19 00:00:00", + "2106-09-25 00:00:00", + "2106-09-26 00:00:00", + "2106-10-02 00:00:00", + "2106-10-03 00:00:00", + "2106-10-09 00:00:00", + "2106-10-10 00:00:00", + "2106-10-16 00:00:00", + "2106-10-17 00:00:00", + "2106-10-23 00:00:00", + "2106-10-24 00:00:00", + "2106-10-30 00:00:00", + "2106-10-31 00:00:00", + "2106-11-06 00:00:00", + "2106-11-07 00:00:00", + "2106-11-13 00:00:00", + "2106-11-14 00:00:00", + "2106-11-20 00:00:00", + "2106-11-21 00:00:00", + "2106-11-27 00:00:00", + "2106-11-28 00:00:00", + "2106-12-04 00:00:00", + "2106-12-05 00:00:00", + "2106-12-11 00:00:00", + "2106-12-12 00:00:00", + "2106-12-18 00:00:00", + "2106-12-19 00:00:00", + "2106-12-25 00:00:00", + "2106-12-26 00:00:00", + "2107-01-01 00:00:00", + "2107-01-02 00:00:00", + "2107-01-08 00:00:00", + "2107-01-09 00:00:00", + "2107-01-15 00:00:00", + "2107-01-16 00:00:00", + "2107-01-22 00:00:00", + "2107-01-23 00:00:00", + "2107-01-29 00:00:00", + "2107-01-30 00:00:00", + "2107-02-05 00:00:00", + "2107-02-06 00:00:00", + "2107-02-12 00:00:00", + "2107-02-13 00:00:00", + "2107-02-19 00:00:00", + "2107-02-20 00:00:00", + "2107-02-26 00:00:00", + "2107-02-27 00:00:00", + "2107-03-05 00:00:00", + "2107-03-06 00:00:00", + "2107-03-12 00:00:00", + "2107-03-13 00:00:00", + "2107-03-19 00:00:00", + "2107-03-20 00:00:00", + "2107-03-26 00:00:00", + "2107-03-27 00:00:00", + "2107-04-02 00:00:00", + "2107-04-03 00:00:00", + "2107-04-09 00:00:00", + "2107-04-10 00:00:00", + "2107-04-16 00:00:00", + "2107-04-17 00:00:00", + "2107-04-23 00:00:00", + "2107-04-24 00:00:00", + "2107-04-30 00:00:00", + "2107-05-01 00:00:00", + "2107-05-07 00:00:00", + "2107-05-08 00:00:00", + "2107-05-14 00:00:00", + "2107-05-15 00:00:00", + "2107-05-21 00:00:00", + "2107-05-22 00:00:00", + "2107-05-28 00:00:00", + "2107-05-29 00:00:00", + "2107-06-04 00:00:00", + "2107-06-05 00:00:00", + "2107-06-11 00:00:00", + "2107-06-12 00:00:00", + "2107-06-18 00:00:00", + "2107-06-19 00:00:00", + "2107-06-25 00:00:00", + "2107-06-26 00:00:00", + "2107-07-02 00:00:00", + "2107-07-03 00:00:00", + "2107-07-09 00:00:00", + "2107-07-10 00:00:00", + "2107-07-16 00:00:00", + "2107-07-17 00:00:00", + "2107-07-23 00:00:00", + "2107-07-24 00:00:00", + "2107-07-30 00:00:00", + "2107-07-31 00:00:00", + "2107-08-06 00:00:00", + "2107-08-07 00:00:00", + "2107-08-13 00:00:00", + "2107-08-14 00:00:00", + "2107-08-20 00:00:00", + "2107-08-21 00:00:00", + "2107-08-27 00:00:00", + "2107-08-28 00:00:00", + "2107-09-03 00:00:00", + "2107-09-04 00:00:00", + "2107-09-10 00:00:00", + "2107-09-11 00:00:00", + "2107-09-17 00:00:00", + "2107-09-18 00:00:00", + "2107-09-24 00:00:00", + "2107-09-25 00:00:00", + "2107-10-01 00:00:00", + "2107-10-02 00:00:00", + "2107-10-08 00:00:00", + "2107-10-09 00:00:00", + "2107-10-15 00:00:00", + "2107-10-16 00:00:00", + "2107-10-22 00:00:00", + "2107-10-23 00:00:00", + "2107-10-29 00:00:00", + "2107-10-30 00:00:00", + "2107-11-05 00:00:00", + "2107-11-06 00:00:00", + "2107-11-12 00:00:00", + "2107-11-13 00:00:00", + "2107-11-19 00:00:00", + "2107-11-20 00:00:00", + "2107-11-26 00:00:00", + "2107-11-27 00:00:00", + "2107-12-03 00:00:00", + "2107-12-04 00:00:00", + "2107-12-10 00:00:00", + "2107-12-11 00:00:00", + "2107-12-17 00:00:00", + "2107-12-18 00:00:00", + "2107-12-24 00:00:00", + "2107-12-25 00:00:00", + "2107-12-31 00:00:00", + "2108-01-01 00:00:00", + "2108-01-07 00:00:00", + "2108-01-08 00:00:00", + "2108-01-14 00:00:00", + "2108-01-15 00:00:00", + "2108-01-21 00:00:00", + "2108-01-22 00:00:00", + "2108-01-28 00:00:00", + "2108-01-29 00:00:00", + "2108-02-04 00:00:00", + "2108-02-05 00:00:00", + "2108-02-11 00:00:00", + "2108-02-12 00:00:00", + "2108-02-18 00:00:00", + "2108-02-19 00:00:00", + "2108-02-25 00:00:00", + "2108-02-26 00:00:00", + "2108-03-03 00:00:00", + "2108-03-04 00:00:00", + "2108-03-10 00:00:00", + "2108-03-11 00:00:00", + "2108-03-17 00:00:00", + "2108-03-18 00:00:00", + "2108-03-24 00:00:00", + "2108-03-25 00:00:00", + "2108-03-31 00:00:00", + "2108-04-01 00:00:00", + "2108-04-07 00:00:00", + "2108-04-08 00:00:00", + "2108-04-14 00:00:00", + "2108-04-15 00:00:00", + "2108-04-21 00:00:00", + "2108-04-22 00:00:00", + "2108-04-28 00:00:00", + "2108-04-29 00:00:00", + "2108-05-05 00:00:00", + "2108-05-06 00:00:00", + "2108-05-12 00:00:00", + "2108-05-13 00:00:00", + "2108-05-19 00:00:00", + "2108-05-20 00:00:00", + "2108-05-26 00:00:00", + "2108-05-27 00:00:00", + "2108-06-02 00:00:00", + "2108-06-03 00:00:00", + "2108-06-09 00:00:00", + "2108-06-10 00:00:00", + "2108-06-16 00:00:00", + "2108-06-17 00:00:00", + "2108-06-23 00:00:00", + "2108-06-24 00:00:00", + "2108-06-30 00:00:00", + "2108-07-01 00:00:00", + "2108-07-07 00:00:00", + "2108-07-08 00:00:00", + "2108-07-14 00:00:00", + "2108-07-15 00:00:00", + "2108-07-21 00:00:00", + "2108-07-22 00:00:00", + "2108-07-28 00:00:00", + "2108-07-29 00:00:00", + "2108-08-04 00:00:00", + "2108-08-05 00:00:00", + "2108-08-11 00:00:00", + "2108-08-12 00:00:00", + "2108-08-18 00:00:00", + "2108-08-19 00:00:00", + "2108-08-25 00:00:00", + "2108-08-26 00:00:00", + "2108-09-01 00:00:00", + "2108-09-02 00:00:00", + "2108-09-08 00:00:00", + "2108-09-09 00:00:00", + "2108-09-15 00:00:00", + "2108-09-16 00:00:00", + "2108-09-22 00:00:00", + "2108-09-23 00:00:00", + "2108-09-29 00:00:00", + "2108-09-30 00:00:00", + "2108-10-06 00:00:00", + "2108-10-07 00:00:00", + "2108-10-13 00:00:00", + "2108-10-14 00:00:00", + "2108-10-20 00:00:00", + "2108-10-21 00:00:00", + "2108-10-27 00:00:00", + "2108-10-28 00:00:00", + "2108-11-03 00:00:00", + "2108-11-04 00:00:00", + "2108-11-10 00:00:00", + "2108-11-11 00:00:00", + "2108-11-17 00:00:00", + "2108-11-18 00:00:00", + "2108-11-24 00:00:00", + "2108-11-25 00:00:00", + "2108-12-01 00:00:00", + "2108-12-02 00:00:00", + "2108-12-08 00:00:00", + "2108-12-09 00:00:00", + "2108-12-15 00:00:00", + "2108-12-16 00:00:00", + "2108-12-22 00:00:00", + "2108-12-23 00:00:00", + "2108-12-29 00:00:00", + "2108-12-30 00:00:00", + "2109-01-05 00:00:00", + "2109-01-06 00:00:00", + "2109-01-12 00:00:00", + "2109-01-13 00:00:00", + "2109-01-19 00:00:00", + "2109-01-20 00:00:00", + "2109-01-26 00:00:00", + "2109-01-27 00:00:00", + "2109-02-02 00:00:00", + "2109-02-03 00:00:00", + "2109-02-09 00:00:00", + "2109-02-10 00:00:00", + "2109-02-16 00:00:00", + "2109-02-17 00:00:00", + "2109-02-23 00:00:00", + "2109-02-24 00:00:00", + "2109-03-02 00:00:00", + "2109-03-03 00:00:00", + "2109-03-09 00:00:00", + "2109-03-10 00:00:00", + "2109-03-16 00:00:00", + "2109-03-17 00:00:00", + "2109-03-23 00:00:00", + "2109-03-24 00:00:00", + "2109-03-30 00:00:00", + "2109-03-31 00:00:00", + "2109-04-06 00:00:00", + "2109-04-07 00:00:00", + "2109-04-13 00:00:00", + "2109-04-14 00:00:00", + "2109-04-20 00:00:00", + "2109-04-21 00:00:00", + "2109-04-27 00:00:00", + "2109-04-28 00:00:00", + "2109-05-04 00:00:00", + "2109-05-05 00:00:00", + "2109-05-11 00:00:00", + "2109-05-12 00:00:00", + "2109-05-18 00:00:00", + "2109-05-19 00:00:00", + "2109-05-25 00:00:00", + "2109-05-26 00:00:00", + "2109-06-01 00:00:00", + "2109-06-02 00:00:00", + "2109-06-08 00:00:00", + "2109-06-09 00:00:00", + "2109-06-15 00:00:00", + "2109-06-16 00:00:00", + "2109-06-22 00:00:00", + "2109-06-23 00:00:00", + "2109-06-29 00:00:00", + "2109-06-30 00:00:00", + "2109-07-06 00:00:00", + "2109-07-07 00:00:00", + "2109-07-13 00:00:00", + "2109-07-14 00:00:00", + "2109-07-20 00:00:00", + "2109-07-21 00:00:00", + "2109-07-27 00:00:00", + "2109-07-28 00:00:00", + "2109-08-03 00:00:00", + "2109-08-04 00:00:00", + "2109-08-10 00:00:00", + "2109-08-11 00:00:00", + "2109-08-17 00:00:00", + "2109-08-18 00:00:00", + "2109-08-24 00:00:00", + "2109-08-25 00:00:00", + "2109-08-31 00:00:00", + "2109-09-01 00:00:00", + "2109-09-07 00:00:00", + "2109-09-08 00:00:00", + "2109-09-14 00:00:00", + "2109-09-15 00:00:00", + "2109-09-21 00:00:00", + "2109-09-22 00:00:00", + "2109-09-28 00:00:00", + "2109-09-29 00:00:00", + "2109-10-05 00:00:00", + "2109-10-06 00:00:00", + "2109-10-12 00:00:00", + "2109-10-13 00:00:00", + "2109-10-19 00:00:00", + "2109-10-20 00:00:00", + "2109-10-26 00:00:00", + "2109-10-27 00:00:00", + "2109-11-02 00:00:00", + "2109-11-03 00:00:00", + "2109-11-09 00:00:00", + "2109-11-10 00:00:00", + "2109-11-16 00:00:00", + "2109-11-17 00:00:00", + "2109-11-23 00:00:00", + "2109-11-24 00:00:00", + "2109-11-30 00:00:00", + "2109-12-01 00:00:00", + "2109-12-07 00:00:00", + "2109-12-08 00:00:00", + "2109-12-14 00:00:00", + "2109-12-15 00:00:00", + "2109-12-21 00:00:00", + "2109-12-22 00:00:00", + "2109-12-28 00:00:00", + "2109-12-29 00:00:00", + "2110-01-04 00:00:00", + "2110-01-05 00:00:00", + "2110-01-11 00:00:00", + "2110-01-12 00:00:00", + "2110-01-18 00:00:00", + "2110-01-19 00:00:00", + "2110-01-25 00:00:00", + "2110-01-26 00:00:00", + "2110-02-01 00:00:00", + "2110-02-02 00:00:00", + "2110-02-08 00:00:00", + "2110-02-09 00:00:00", + "2110-02-15 00:00:00", + "2110-02-16 00:00:00", + "2110-02-22 00:00:00", + "2110-02-23 00:00:00", + "2110-03-01 00:00:00", + "2110-03-02 00:00:00", + "2110-03-08 00:00:00", + "2110-03-09 00:00:00", + "2110-03-15 00:00:00", + "2110-03-16 00:00:00", + "2110-03-22 00:00:00", + "2110-03-23 00:00:00", + "2110-03-29 00:00:00", + "2110-03-30 00:00:00", + "2110-04-05 00:00:00", + "2110-04-06 00:00:00", + "2110-04-12 00:00:00", + "2110-04-13 00:00:00", + "2110-04-19 00:00:00", + "2110-04-20 00:00:00", + "2110-04-26 00:00:00", + "2110-04-27 00:00:00", + "2110-05-03 00:00:00", + "2110-05-04 00:00:00", + "2110-05-10 00:00:00", + "2110-05-11 00:00:00", + "2110-05-17 00:00:00", + "2110-05-18 00:00:00", + "2110-05-24 00:00:00", + "2110-05-25 00:00:00", + "2110-05-31 00:00:00", + "2110-06-01 00:00:00", + "2110-06-07 00:00:00", + "2110-06-08 00:00:00", + "2110-06-14 00:00:00", + "2110-06-15 00:00:00", + "2110-06-21 00:00:00", + "2110-06-22 00:00:00", + "2110-06-28 00:00:00", + "2110-06-29 00:00:00", + "2110-07-05 00:00:00", + "2110-07-06 00:00:00", + "2110-07-12 00:00:00", + "2110-07-13 00:00:00", + "2110-07-19 00:00:00", + "2110-07-20 00:00:00", + "2110-07-26 00:00:00", + "2110-07-27 00:00:00", + "2110-08-02 00:00:00", + "2110-08-03 00:00:00", + "2110-08-09 00:00:00", + "2110-08-10 00:00:00", + "2110-08-16 00:00:00", + "2110-08-17 00:00:00", + "2110-08-23 00:00:00", + "2110-08-24 00:00:00", + "2110-08-30 00:00:00", + "2110-08-31 00:00:00", + "2110-09-06 00:00:00", + "2110-09-07 00:00:00", + "2110-09-13 00:00:00", + "2110-09-14 00:00:00", + "2110-09-20 00:00:00", + "2110-09-21 00:00:00", + "2110-09-27 00:00:00", + "2110-09-28 00:00:00", + "2110-10-04 00:00:00", + "2110-10-05 00:00:00", + "2110-10-11 00:00:00", + "2110-10-12 00:00:00", + "2110-10-18 00:00:00", + "2110-10-19 00:00:00", + "2110-10-25 00:00:00", + "2110-10-26 00:00:00", + "2110-11-01 00:00:00", + "2110-11-02 00:00:00", + "2110-11-08 00:00:00", + "2110-11-09 00:00:00", + "2110-11-15 00:00:00", + "2110-11-16 00:00:00", + "2110-11-22 00:00:00", + "2110-11-23 00:00:00", + "2110-11-29 00:00:00", + "2110-11-30 00:00:00", + "2110-12-06 00:00:00", + "2110-12-07 00:00:00", + "2110-12-13 00:00:00", + "2110-12-14 00:00:00", + "2110-12-20 00:00:00", + "2110-12-21 00:00:00", + "2110-12-27 00:00:00", + "2110-12-28 00:00:00", + "2111-01-03 00:00:00", + "2111-01-04 00:00:00", + "2111-01-10 00:00:00", + "2111-01-11 00:00:00", + "2111-01-17 00:00:00", + "2111-01-18 00:00:00", + "2111-01-24 00:00:00", + "2111-01-25 00:00:00", + "2111-01-31 00:00:00", + "2111-02-01 00:00:00", + "2111-02-07 00:00:00", + "2111-02-08 00:00:00", + "2111-02-14 00:00:00", + "2111-02-15 00:00:00", + "2111-02-21 00:00:00", + "2111-02-22 00:00:00", + "2111-02-28 00:00:00", + "2111-03-01 00:00:00", + "2111-03-07 00:00:00", + "2111-03-08 00:00:00", + "2111-03-14 00:00:00", + "2111-03-15 00:00:00", + "2111-03-21 00:00:00", + "2111-03-22 00:00:00", + "2111-03-28 00:00:00", + "2111-03-29 00:00:00", + "2111-04-04 00:00:00", + "2111-04-05 00:00:00", + "2111-04-11 00:00:00", + "2111-04-12 00:00:00", + "2111-04-18 00:00:00", + "2111-04-19 00:00:00", + "2111-04-25 00:00:00", + "2111-04-26 00:00:00", + "2111-05-02 00:00:00", + "2111-05-03 00:00:00", + "2111-05-09 00:00:00", + "2111-05-10 00:00:00", + "2111-05-16 00:00:00", + "2111-05-17 00:00:00", + "2111-05-23 00:00:00", + "2111-05-24 00:00:00", + "2111-05-30 00:00:00", + "2111-05-31 00:00:00", + "2111-06-06 00:00:00", + "2111-06-07 00:00:00", + "2111-06-13 00:00:00", + "2111-06-14 00:00:00", + "2111-06-20 00:00:00", + "2111-06-21 00:00:00", + "2111-06-27 00:00:00", + "2111-06-28 00:00:00", + "2111-07-04 00:00:00", + "2111-07-05 00:00:00", + "2111-07-11 00:00:00", + "2111-07-12 00:00:00", + "2111-07-18 00:00:00", + "2111-07-19 00:00:00", + "2111-07-25 00:00:00", + "2111-07-26 00:00:00", + "2111-08-01 00:00:00", + "2111-08-02 00:00:00", + "2111-08-08 00:00:00", + "2111-08-09 00:00:00", + "2111-08-15 00:00:00", + "2111-08-16 00:00:00", + "2111-08-22 00:00:00", + "2111-08-23 00:00:00", + "2111-08-29 00:00:00", + "2111-08-30 00:00:00", + "2111-09-05 00:00:00", + "2111-09-06 00:00:00", + "2111-09-12 00:00:00", + "2111-09-13 00:00:00", + "2111-09-19 00:00:00", + "2111-09-20 00:00:00", + "2111-09-26 00:00:00", + "2111-09-27 00:00:00", + "2111-10-03 00:00:00", + "2111-10-04 00:00:00", + "2111-10-10 00:00:00", + "2111-10-11 00:00:00", + "2111-10-17 00:00:00", + "2111-10-18 00:00:00", + "2111-10-24 00:00:00", + "2111-10-25 00:00:00", + "2111-10-31 00:00:00", + "2111-11-01 00:00:00", + "2111-11-07 00:00:00", + "2111-11-08 00:00:00", + "2111-11-14 00:00:00", + "2111-11-15 00:00:00", + "2111-11-21 00:00:00", + "2111-11-22 00:00:00", + "2111-11-28 00:00:00", + "2111-11-29 00:00:00", + "2111-12-05 00:00:00", + "2111-12-06 00:00:00", + "2111-12-12 00:00:00", + "2111-12-13 00:00:00", + "2111-12-19 00:00:00", + "2111-12-20 00:00:00", + "2111-12-26 00:00:00", + "2111-12-27 00:00:00", + "2112-01-02 00:00:00", + "2112-01-03 00:00:00", + "2112-01-09 00:00:00", + "2112-01-10 00:00:00", + "2112-01-16 00:00:00", + "2112-01-17 00:00:00", + "2112-01-23 00:00:00", + "2112-01-24 00:00:00", + "2112-01-30 00:00:00", + "2112-01-31 00:00:00", + "2112-02-06 00:00:00", + "2112-02-07 00:00:00", + "2112-02-13 00:00:00", + "2112-02-14 00:00:00", + "2112-02-20 00:00:00", + "2112-02-21 00:00:00", + "2112-02-27 00:00:00", + "2112-02-28 00:00:00", + "2112-03-05 00:00:00", + "2112-03-06 00:00:00", + "2112-03-12 00:00:00", + "2112-03-13 00:00:00", + "2112-03-19 00:00:00", + "2112-03-20 00:00:00", + "2112-03-26 00:00:00", + "2112-03-27 00:00:00", + "2112-04-02 00:00:00", + "2112-04-03 00:00:00", + "2112-04-09 00:00:00", + "2112-04-10 00:00:00", + "2112-04-16 00:00:00", + "2112-04-17 00:00:00", + "2112-04-23 00:00:00", + "2112-04-24 00:00:00", + "2112-04-30 00:00:00", + "2112-05-01 00:00:00", + "2112-05-07 00:00:00", + "2112-05-08 00:00:00", + "2112-05-14 00:00:00", + "2112-05-15 00:00:00", + "2112-05-21 00:00:00", + "2112-05-22 00:00:00", + "2112-05-28 00:00:00", + "2112-05-29 00:00:00", + "2112-06-04 00:00:00", + "2112-06-05 00:00:00", + "2112-06-11 00:00:00", + "2112-06-12 00:00:00", + "2112-06-18 00:00:00", + "2112-06-19 00:00:00", + "2112-06-25 00:00:00", + "2112-06-26 00:00:00", + "2112-07-02 00:00:00", + "2112-07-03 00:00:00", + "2112-07-09 00:00:00", + "2112-07-10 00:00:00", + "2112-07-16 00:00:00", + "2112-07-17 00:00:00", + "2112-07-23 00:00:00", + "2112-07-24 00:00:00", + "2112-07-30 00:00:00", + "2112-07-31 00:00:00", + "2112-08-06 00:00:00", + "2112-08-07 00:00:00", + "2112-08-13 00:00:00", + "2112-08-14 00:00:00", + "2112-08-20 00:00:00", + "2112-08-21 00:00:00", + "2112-08-27 00:00:00", + "2112-08-28 00:00:00", + "2112-09-03 00:00:00", + "2112-09-04 00:00:00", + "2112-09-10 00:00:00", + "2112-09-11 00:00:00", + "2112-09-17 00:00:00", + "2112-09-18 00:00:00", + "2112-09-24 00:00:00", + "2112-09-25 00:00:00", + "2112-10-01 00:00:00", + "2112-10-02 00:00:00", + "2112-10-08 00:00:00", + "2112-10-09 00:00:00", + "2112-10-15 00:00:00", + "2112-10-16 00:00:00", + "2112-10-22 00:00:00", + "2112-10-23 00:00:00", + "2112-10-29 00:00:00", + "2112-10-30 00:00:00", + "2112-11-05 00:00:00", + "2112-11-06 00:00:00", + "2112-11-12 00:00:00", + "2112-11-13 00:00:00", + "2112-11-19 00:00:00", + "2112-11-20 00:00:00", + "2112-11-26 00:00:00", + "2112-11-27 00:00:00", + "2112-12-03 00:00:00", + "2112-12-04 00:00:00", + "2112-12-10 00:00:00", + "2112-12-11 00:00:00", + "2112-12-17 00:00:00", + "2112-12-18 00:00:00", + "2112-12-24 00:00:00", + "2112-12-25 00:00:00", + "2112-12-31 00:00:00", + "2113-01-01 00:00:00", + "2113-01-07 00:00:00", + "2113-01-08 00:00:00", + "2113-01-14 00:00:00", + "2113-01-15 00:00:00", + "2113-01-21 00:00:00", + "2113-01-22 00:00:00", + "2113-01-28 00:00:00", + "2113-01-29 00:00:00", + "2113-02-04 00:00:00", + "2113-02-05 00:00:00", + "2113-02-11 00:00:00", + "2113-02-12 00:00:00", + "2113-02-18 00:00:00", + "2113-02-19 00:00:00", + "2113-02-25 00:00:00", + "2113-02-26 00:00:00", + "2113-03-04 00:00:00", + "2113-03-05 00:00:00", + "2113-03-11 00:00:00", + "2113-03-12 00:00:00", + "2113-03-18 00:00:00", + "2113-03-19 00:00:00", + "2113-03-25 00:00:00", + "2113-03-26 00:00:00", + "2113-04-01 00:00:00", + "2113-04-02 00:00:00", + "2113-04-08 00:00:00", + "2113-04-09 00:00:00", + "2113-04-15 00:00:00", + "2113-04-16 00:00:00", + "2113-04-22 00:00:00", + "2113-04-23 00:00:00", + "2113-04-29 00:00:00", + "2113-04-30 00:00:00", + "2113-05-06 00:00:00", + "2113-05-07 00:00:00", + "2113-05-13 00:00:00", + "2113-05-14 00:00:00", + "2113-05-20 00:00:00", + "2113-05-21 00:00:00", + "2113-05-27 00:00:00", + "2113-05-28 00:00:00", + "2113-06-03 00:00:00", + "2113-06-04 00:00:00", + "2113-06-10 00:00:00", + "2113-06-11 00:00:00", + "2113-06-17 00:00:00", + "2113-06-18 00:00:00", + "2113-06-24 00:00:00", + "2113-06-25 00:00:00", + "2113-07-01 00:00:00", + "2113-07-02 00:00:00", + "2113-07-08 00:00:00", + "2113-07-09 00:00:00", + "2113-07-15 00:00:00", + "2113-07-16 00:00:00", + "2113-07-22 00:00:00", + "2113-07-23 00:00:00", + "2113-07-29 00:00:00", + "2113-07-30 00:00:00", + "2113-08-05 00:00:00", + "2113-08-06 00:00:00", + "2113-08-12 00:00:00", + "2113-08-13 00:00:00", + "2113-08-19 00:00:00", + "2113-08-20 00:00:00", + "2113-08-26 00:00:00", + "2113-08-27 00:00:00", + "2113-09-02 00:00:00", + "2113-09-03 00:00:00", + "2113-09-09 00:00:00", + "2113-09-10 00:00:00", + "2113-09-16 00:00:00", + "2113-09-17 00:00:00", + "2113-09-23 00:00:00", + "2113-09-24 00:00:00", + "2113-09-30 00:00:00", + "2113-10-01 00:00:00", + "2113-10-07 00:00:00", + "2113-10-08 00:00:00", + "2113-10-14 00:00:00", + "2113-10-15 00:00:00", + "2113-10-21 00:00:00", + "2113-10-22 00:00:00", + "2113-10-28 00:00:00", + "2113-10-29 00:00:00", + "2113-11-04 00:00:00", + "2113-11-05 00:00:00", + "2113-11-11 00:00:00", + "2113-11-12 00:00:00", + "2113-11-18 00:00:00", + "2113-11-19 00:00:00", + "2113-11-25 00:00:00", + "2113-11-26 00:00:00", + "2113-12-02 00:00:00", + "2113-12-03 00:00:00", + "2113-12-09 00:00:00", + "2113-12-10 00:00:00", + "2113-12-16 00:00:00", + "2113-12-17 00:00:00", + "2113-12-23 00:00:00", + "2113-12-24 00:00:00", + "2113-12-30 00:00:00", + "2113-12-31 00:00:00", + "2114-01-06 00:00:00", + "2114-01-07 00:00:00", + "2114-01-13 00:00:00", + "2114-01-14 00:00:00", + "2114-01-20 00:00:00", + "2114-01-21 00:00:00", + "2114-01-27 00:00:00", + "2114-01-28 00:00:00", + "2114-02-03 00:00:00", + "2114-02-04 00:00:00", + "2114-02-10 00:00:00", + "2114-02-11 00:00:00", + "2114-02-17 00:00:00", + "2114-02-18 00:00:00", + "2114-02-24 00:00:00", + "2114-02-25 00:00:00", + "2114-03-03 00:00:00", + "2114-03-04 00:00:00", + "2114-03-10 00:00:00", + "2114-03-11 00:00:00", + "2114-03-17 00:00:00", + "2114-03-18 00:00:00", + "2114-03-24 00:00:00", + "2114-03-25 00:00:00", + "2114-03-31 00:00:00", + "2114-04-01 00:00:00", + "2114-04-07 00:00:00", + "2114-04-08 00:00:00", + "2114-04-14 00:00:00", + "2114-04-15 00:00:00", + "2114-04-21 00:00:00", + "2114-04-22 00:00:00", + "2114-04-28 00:00:00", + "2114-04-29 00:00:00", + "2114-05-05 00:00:00", + "2114-05-06 00:00:00", + "2114-05-12 00:00:00", + "2114-05-13 00:00:00", + "2114-05-19 00:00:00", + "2114-05-20 00:00:00", + "2114-05-26 00:00:00", + "2114-05-27 00:00:00", + "2114-06-02 00:00:00", + "2114-06-03 00:00:00", + "2114-06-09 00:00:00", + "2114-06-10 00:00:00", + "2114-06-16 00:00:00", + "2114-06-17 00:00:00", + "2114-06-23 00:00:00", + "2114-06-24 00:00:00", + "2114-06-30 00:00:00", + "2114-07-01 00:00:00", + "2114-07-07 00:00:00", + "2114-07-08 00:00:00", + "2114-07-14 00:00:00", + "2114-07-15 00:00:00", + "2114-07-21 00:00:00", + "2114-07-22 00:00:00", + "2114-07-28 00:00:00", + "2114-07-29 00:00:00", + "2114-08-04 00:00:00", + "2114-08-05 00:00:00", + "2114-08-11 00:00:00", + "2114-08-12 00:00:00", + "2114-08-18 00:00:00", + "2114-08-19 00:00:00", + "2114-08-25 00:00:00", + "2114-08-26 00:00:00", + "2114-09-01 00:00:00", + "2114-09-02 00:00:00", + "2114-09-08 00:00:00", + "2114-09-09 00:00:00", + "2114-09-15 00:00:00", + "2114-09-16 00:00:00", + "2114-09-22 00:00:00", + "2114-09-23 00:00:00", + "2114-09-29 00:00:00", + "2114-09-30 00:00:00", + "2114-10-06 00:00:00", + "2114-10-07 00:00:00", + "2114-10-13 00:00:00", + "2114-10-14 00:00:00", + "2114-10-20 00:00:00", + "2114-10-21 00:00:00", + "2114-10-27 00:00:00", + "2114-10-28 00:00:00", + "2114-11-03 00:00:00", + "2114-11-04 00:00:00", + "2114-11-10 00:00:00", + "2114-11-11 00:00:00", + "2114-11-17 00:00:00", + "2114-11-18 00:00:00", + "2114-11-24 00:00:00", + "2114-11-25 00:00:00", + "2114-12-01 00:00:00", + "2114-12-02 00:00:00", + "2114-12-08 00:00:00", + "2114-12-09 00:00:00", + "2114-12-15 00:00:00", + "2114-12-16 00:00:00", + "2114-12-22 00:00:00", + "2114-12-23 00:00:00", + "2114-12-29 00:00:00", + "2114-12-30 00:00:00", + "2115-01-05 00:00:00", + "2115-01-06 00:00:00", + "2115-01-12 00:00:00", + "2115-01-13 00:00:00", + "2115-01-19 00:00:00", + "2115-01-20 00:00:00", + "2115-01-26 00:00:00", + "2115-01-27 00:00:00", + "2115-02-02 00:00:00", + "2115-02-03 00:00:00", + "2115-02-09 00:00:00", + "2115-02-10 00:00:00", + "2115-02-16 00:00:00", + "2115-02-17 00:00:00", + "2115-02-23 00:00:00", + "2115-02-24 00:00:00", + "2115-03-02 00:00:00", + "2115-03-03 00:00:00", + "2115-03-09 00:00:00", + "2115-03-10 00:00:00", + "2115-03-16 00:00:00", + "2115-03-17 00:00:00", + "2115-03-23 00:00:00", + "2115-03-24 00:00:00", + "2115-03-30 00:00:00", + "2115-03-31 00:00:00", + "2115-04-06 00:00:00", + "2115-04-07 00:00:00", + "2115-04-13 00:00:00", + "2115-04-14 00:00:00", + "2115-04-20 00:00:00", + "2115-04-21 00:00:00", + "2115-04-27 00:00:00", + "2115-04-28 00:00:00", + "2115-05-04 00:00:00", + "2115-05-05 00:00:00", + "2115-05-11 00:00:00", + "2115-05-12 00:00:00", + "2115-05-18 00:00:00", + "2115-05-19 00:00:00", + "2115-05-25 00:00:00", + "2115-05-26 00:00:00", + "2115-06-01 00:00:00", + "2115-06-02 00:00:00", + "2115-06-08 00:00:00", + "2115-06-09 00:00:00", + "2115-06-15 00:00:00", + "2115-06-16 00:00:00", + "2115-06-22 00:00:00", + "2115-06-23 00:00:00", + "2115-06-29 00:00:00", + "2115-06-30 00:00:00", + "2115-07-06 00:00:00", + "2115-07-07 00:00:00", + "2115-07-13 00:00:00", + "2115-07-14 00:00:00", + "2115-07-20 00:00:00", + "2115-07-21 00:00:00", + "2115-07-27 00:00:00", + "2115-07-28 00:00:00", + "2115-08-03 00:00:00", + "2115-08-04 00:00:00", + "2115-08-10 00:00:00", + "2115-08-11 00:00:00", + "2115-08-17 00:00:00", + "2115-08-18 00:00:00", + "2115-08-24 00:00:00", + "2115-08-25 00:00:00", + "2115-08-31 00:00:00", + "2115-09-01 00:00:00", + "2115-09-07 00:00:00", + "2115-09-08 00:00:00", + "2115-09-14 00:00:00", + "2115-09-15 00:00:00", + "2115-09-21 00:00:00", + "2115-09-22 00:00:00", + "2115-09-28 00:00:00", + "2115-09-29 00:00:00", + "2115-10-05 00:00:00", + "2115-10-06 00:00:00", + "2115-10-12 00:00:00", + "2115-10-13 00:00:00", + "2115-10-19 00:00:00", + "2115-10-20 00:00:00", + "2115-10-26 00:00:00", + "2115-10-27 00:00:00", + "2115-11-02 00:00:00", + "2115-11-03 00:00:00", + "2115-11-09 00:00:00", + "2115-11-10 00:00:00", + "2115-11-16 00:00:00", + "2115-11-17 00:00:00", + "2115-11-23 00:00:00", + "2115-11-24 00:00:00", + "2115-11-30 00:00:00", + "2115-12-01 00:00:00", + "2115-12-07 00:00:00", + "2115-12-08 00:00:00", + "2115-12-14 00:00:00", + "2115-12-15 00:00:00", + "2115-12-21 00:00:00", + "2115-12-22 00:00:00", + "2115-12-28 00:00:00", + "2115-12-29 00:00:00", + "2116-01-04 00:00:00", + "2116-01-05 00:00:00", + "2116-01-11 00:00:00", + "2116-01-12 00:00:00", + "2116-01-18 00:00:00", + "2116-01-19 00:00:00", + "2116-01-25 00:00:00", + "2116-01-26 00:00:00", + "2116-02-01 00:00:00", + "2116-02-02 00:00:00", + "2116-02-08 00:00:00", + "2116-02-09 00:00:00", + "2116-02-15 00:00:00", + "2116-02-16 00:00:00", + "2116-02-22 00:00:00", + "2116-02-23 00:00:00", + "2116-02-29 00:00:00", + "2116-03-01 00:00:00", + "2116-03-07 00:00:00", + "2116-03-08 00:00:00", + "2116-03-14 00:00:00", + "2116-03-15 00:00:00", + "2116-03-21 00:00:00", + "2116-03-22 00:00:00", + "2116-03-28 00:00:00", + "2116-03-29 00:00:00", + "2116-04-04 00:00:00", + "2116-04-05 00:00:00", + "2116-04-11 00:00:00", + "2116-04-12 00:00:00", + "2116-04-18 00:00:00", + "2116-04-19 00:00:00", + "2116-04-25 00:00:00", + "2116-04-26 00:00:00", + "2116-05-02 00:00:00", + "2116-05-03 00:00:00", + "2116-05-09 00:00:00", + "2116-05-10 00:00:00", + "2116-05-16 00:00:00", + "2116-05-17 00:00:00", + "2116-05-23 00:00:00", + "2116-05-24 00:00:00", + "2116-05-30 00:00:00", + "2116-05-31 00:00:00", + "2116-06-06 00:00:00", + "2116-06-07 00:00:00", + "2116-06-13 00:00:00", + "2116-06-14 00:00:00", + "2116-06-20 00:00:00", + "2116-06-21 00:00:00", + "2116-06-27 00:00:00", + "2116-06-28 00:00:00", + "2116-07-04 00:00:00", + "2116-07-05 00:00:00", + "2116-07-11 00:00:00", + "2116-07-12 00:00:00", + "2116-07-18 00:00:00", + "2116-07-19 00:00:00", + "2116-07-25 00:00:00", + "2116-07-26 00:00:00", + "2116-08-01 00:00:00", + "2116-08-02 00:00:00", + "2116-08-08 00:00:00", + "2116-08-09 00:00:00", + "2116-08-15 00:00:00", + "2116-08-16 00:00:00", + "2116-08-22 00:00:00", + "2116-08-23 00:00:00", + "2116-08-29 00:00:00", + "2116-08-30 00:00:00", + "2116-09-05 00:00:00", + "2116-09-06 00:00:00", + "2116-09-12 00:00:00", + "2116-09-13 00:00:00", + "2116-09-19 00:00:00", + "2116-09-20 00:00:00", + "2116-09-26 00:00:00", + "2116-09-27 00:00:00", + "2116-10-03 00:00:00", + "2116-10-04 00:00:00", + "2116-10-10 00:00:00", + "2116-10-11 00:00:00", + "2116-10-17 00:00:00", + "2116-10-18 00:00:00", + "2116-10-24 00:00:00", + "2116-10-25 00:00:00", + "2116-10-31 00:00:00", + "2116-11-01 00:00:00", + "2116-11-07 00:00:00", + "2116-11-08 00:00:00", + "2116-11-14 00:00:00", + "2116-11-15 00:00:00", + "2116-11-21 00:00:00", + "2116-11-22 00:00:00", + "2116-11-28 00:00:00", + "2116-11-29 00:00:00", + "2116-12-05 00:00:00", + "2116-12-06 00:00:00", + "2116-12-12 00:00:00", + "2116-12-13 00:00:00", + "2116-12-19 00:00:00", + "2116-12-20 00:00:00", + "2116-12-26 00:00:00", + "2116-12-27 00:00:00", + "2117-01-02 00:00:00", + "2117-01-03 00:00:00", + "2117-01-09 00:00:00", + "2117-01-10 00:00:00", + "2117-01-16 00:00:00", + "2117-01-17 00:00:00", + "2117-01-23 00:00:00", + "2117-01-24 00:00:00", + "2117-01-30 00:00:00", + "2117-01-31 00:00:00", + "2117-02-06 00:00:00", + "2117-02-07 00:00:00", + "2117-02-13 00:00:00", + "2117-02-14 00:00:00", + "2117-02-20 00:00:00", + "2117-02-21 00:00:00", + "2117-02-27 00:00:00", + "2117-02-28 00:00:00", + "2117-03-06 00:00:00", + "2117-03-07 00:00:00", + "2117-03-13 00:00:00", + "2117-03-14 00:00:00", + "2117-03-20 00:00:00", + "2117-03-21 00:00:00", + "2117-03-27 00:00:00", + "2117-03-28 00:00:00", + "2117-04-03 00:00:00", + "2117-04-04 00:00:00", + "2117-04-10 00:00:00", + "2117-04-11 00:00:00", + "2117-04-17 00:00:00", + "2117-04-18 00:00:00", + "2117-04-24 00:00:00", + "2117-04-25 00:00:00", + "2117-05-01 00:00:00", + "2117-05-02 00:00:00", + "2117-05-08 00:00:00", + "2117-05-09 00:00:00", + "2117-05-15 00:00:00", + "2117-05-16 00:00:00", + "2117-05-22 00:00:00", + "2117-05-23 00:00:00", + "2117-05-29 00:00:00", + "2117-05-30 00:00:00", + "2117-06-05 00:00:00", + "2117-06-06 00:00:00", + "2117-06-12 00:00:00", + "2117-06-13 00:00:00", + "2117-06-19 00:00:00", + "2117-06-20 00:00:00", + "2117-06-26 00:00:00", + "2117-06-27 00:00:00", + "2117-07-03 00:00:00", + "2117-07-04 00:00:00", + "2117-07-10 00:00:00", + "2117-07-11 00:00:00", + "2117-07-17 00:00:00", + "2117-07-18 00:00:00", + "2117-07-24 00:00:00", + "2117-07-25 00:00:00", + "2117-07-31 00:00:00", + "2117-08-01 00:00:00", + "2117-08-07 00:00:00", + "2117-08-08 00:00:00", + "2117-08-14 00:00:00", + "2117-08-15 00:00:00", + "2117-08-21 00:00:00", + "2117-08-22 00:00:00", + "2117-08-28 00:00:00", + "2117-08-29 00:00:00", + "2117-09-04 00:00:00", + "2117-09-05 00:00:00", + "2117-09-11 00:00:00", + "2117-09-12 00:00:00", + "2117-09-18 00:00:00", + "2117-09-19 00:00:00", + "2117-09-25 00:00:00", + "2117-09-26 00:00:00", + "2117-10-02 00:00:00", + "2117-10-03 00:00:00", + "2117-10-09 00:00:00", + "2117-10-10 00:00:00", + "2117-10-16 00:00:00", + "2117-10-17 00:00:00", + "2117-10-23 00:00:00", + "2117-10-24 00:00:00", + "2117-10-30 00:00:00", + "2117-10-31 00:00:00", + "2117-11-06 00:00:00", + "2117-11-07 00:00:00", + "2117-11-13 00:00:00", + "2117-11-14 00:00:00", + "2117-11-20 00:00:00", + "2117-11-21 00:00:00", + "2117-11-27 00:00:00", + "2117-11-28 00:00:00", + "2117-12-04 00:00:00", + "2117-12-05 00:00:00", + "2117-12-11 00:00:00", + "2117-12-12 00:00:00", + "2117-12-18 00:00:00", + "2117-12-19 00:00:00", + "2117-12-25 00:00:00", + "2117-12-26 00:00:00", + "2118-01-01 00:00:00", + "2118-01-02 00:00:00", + "2118-01-08 00:00:00", + "2118-01-09 00:00:00", + "2118-01-15 00:00:00", + "2118-01-16 00:00:00", + "2118-01-22 00:00:00", + "2118-01-23 00:00:00", + "2118-01-29 00:00:00", + "2118-01-30 00:00:00", + "2118-02-05 00:00:00", + "2118-02-06 00:00:00", + "2118-02-12 00:00:00", + "2118-02-13 00:00:00", + "2118-02-19 00:00:00", + "2118-02-20 00:00:00", + "2118-02-26 00:00:00", + "2118-02-27 00:00:00", + "2118-03-05 00:00:00", + "2118-03-06 00:00:00", + "2118-03-12 00:00:00", + "2118-03-13 00:00:00", + "2118-03-19 00:00:00", + "2118-03-20 00:00:00", + "2118-03-26 00:00:00", + "2118-03-27 00:00:00", + "2118-04-02 00:00:00", + "2118-04-03 00:00:00", + "2118-04-09 00:00:00", + "2118-04-10 00:00:00", + "2118-04-16 00:00:00", + "2118-04-17 00:00:00", + "2118-04-23 00:00:00", + "2118-04-24 00:00:00", + "2118-04-30 00:00:00", + "2118-05-01 00:00:00", + "2118-05-07 00:00:00", + "2118-05-08 00:00:00", + "2118-05-14 00:00:00", + "2118-05-15 00:00:00", + "2118-05-21 00:00:00", + "2118-05-22 00:00:00", + "2118-05-28 00:00:00", + "2118-05-29 00:00:00", + "2118-06-04 00:00:00", + "2118-06-05 00:00:00", + "2118-06-11 00:00:00", + "2118-06-12 00:00:00", + "2118-06-18 00:00:00", + "2118-06-19 00:00:00", + "2118-06-25 00:00:00", + "2118-06-26 00:00:00", + "2118-07-02 00:00:00", + "2118-07-03 00:00:00", + "2118-07-09 00:00:00", + "2118-07-10 00:00:00", + "2118-07-16 00:00:00", + "2118-07-17 00:00:00", + "2118-07-23 00:00:00", + "2118-07-24 00:00:00", + "2118-07-30 00:00:00", + "2118-07-31 00:00:00", + "2118-08-06 00:00:00", + "2118-08-07 00:00:00", + "2118-08-13 00:00:00", + "2118-08-14 00:00:00", + "2118-08-20 00:00:00", + "2118-08-21 00:00:00", + "2118-08-27 00:00:00", + "2118-08-28 00:00:00", + "2118-09-03 00:00:00", + "2118-09-04 00:00:00", + "2118-09-10 00:00:00", + "2118-09-11 00:00:00", + "2118-09-17 00:00:00", + "2118-09-18 00:00:00", + "2118-09-24 00:00:00", + "2118-09-25 00:00:00", + "2118-10-01 00:00:00", + "2118-10-02 00:00:00", + "2118-10-08 00:00:00", + "2118-10-09 00:00:00", + "2118-10-15 00:00:00", + "2118-10-16 00:00:00", + "2118-10-22 00:00:00", + "2118-10-23 00:00:00", + "2118-10-29 00:00:00", + "2118-10-30 00:00:00", + "2118-11-05 00:00:00", + "2118-11-06 00:00:00", + "2118-11-12 00:00:00", + "2118-11-13 00:00:00", + "2118-11-19 00:00:00", + "2118-11-20 00:00:00", + "2118-11-26 00:00:00", + "2118-11-27 00:00:00", + "2118-12-03 00:00:00", + "2118-12-04 00:00:00", + "2118-12-10 00:00:00", + "2118-12-11 00:00:00", + "2118-12-17 00:00:00", + "2118-12-18 00:00:00", + "2118-12-24 00:00:00", + "2118-12-25 00:00:00", + "2118-12-31 00:00:00", + "2119-01-01 00:00:00", + "2119-01-07 00:00:00", + "2119-01-08 00:00:00", + "2119-01-14 00:00:00", + "2119-01-15 00:00:00", + "2119-01-21 00:00:00", + "2119-01-22 00:00:00", + "2119-01-28 00:00:00", + "2119-01-29 00:00:00", + "2119-02-04 00:00:00", + "2119-02-05 00:00:00", + "2119-02-11 00:00:00", + "2119-02-12 00:00:00", + "2119-02-18 00:00:00", + "2119-02-19 00:00:00", + "2119-02-25 00:00:00", + "2119-02-26 00:00:00", + "2119-03-04 00:00:00", + "2119-03-05 00:00:00", + "2119-03-11 00:00:00", + "2119-03-12 00:00:00", + "2119-03-18 00:00:00", + "2119-03-19 00:00:00", + "2119-03-25 00:00:00", + "2119-03-26 00:00:00", + "2119-04-01 00:00:00", + "2119-04-02 00:00:00", + "2119-04-08 00:00:00", + "2119-04-09 00:00:00", + "2119-04-15 00:00:00", + "2119-04-16 00:00:00", + "2119-04-22 00:00:00", + "2119-04-23 00:00:00", + "2119-04-29 00:00:00", + "2119-04-30 00:00:00", + "2119-05-06 00:00:00", + "2119-05-07 00:00:00", + "2119-05-13 00:00:00", + "2119-05-14 00:00:00", + "2119-05-20 00:00:00", + "2119-05-21 00:00:00", + "2119-05-27 00:00:00", + "2119-05-28 00:00:00", + "2119-06-03 00:00:00", + "2119-06-04 00:00:00", + "2119-06-10 00:00:00", + "2119-06-11 00:00:00", + "2119-06-17 00:00:00", + "2119-06-18 00:00:00", + "2119-06-24 00:00:00", + "2119-06-25 00:00:00", + "2119-07-01 00:00:00", + "2119-07-02 00:00:00", + "2119-07-08 00:00:00", + "2119-07-09 00:00:00", + "2119-07-15 00:00:00", + "2119-07-16 00:00:00", + "2119-07-22 00:00:00", + "2119-07-23 00:00:00", + "2119-07-29 00:00:00", + "2119-07-30 00:00:00", + "2119-08-05 00:00:00", + "2119-08-06 00:00:00", + "2119-08-12 00:00:00", + "2119-08-13 00:00:00", + "2119-08-19 00:00:00", + "2119-08-20 00:00:00", + "2119-08-26 00:00:00", + "2119-08-27 00:00:00", + "2119-09-02 00:00:00", + "2119-09-03 00:00:00", + "2119-09-09 00:00:00", + "2119-09-10 00:00:00", + "2119-09-16 00:00:00", + "2119-09-17 00:00:00", + "2119-09-23 00:00:00", + "2119-09-24 00:00:00", + "2119-09-30 00:00:00", + "2119-10-01 00:00:00", + "2119-10-07 00:00:00", + "2119-10-08 00:00:00", + "2119-10-14 00:00:00", + "2119-10-15 00:00:00", + "2119-10-21 00:00:00", + "2119-10-22 00:00:00", + "2119-10-28 00:00:00", + "2119-10-29 00:00:00", + "2119-11-04 00:00:00", + "2119-11-05 00:00:00", + "2119-11-11 00:00:00", + "2119-11-12 00:00:00", + "2119-11-18 00:00:00", + "2119-11-19 00:00:00", + "2119-11-25 00:00:00", + "2119-11-26 00:00:00", + "2119-12-02 00:00:00", + "2119-12-03 00:00:00", + "2119-12-09 00:00:00", + "2119-12-10 00:00:00", + "2119-12-16 00:00:00", + "2119-12-17 00:00:00", + "2119-12-23 00:00:00", + "2119-12-24 00:00:00", + "2119-12-30 00:00:00", + "2119-12-31 00:00:00", + "2120-01-06 00:00:00", + "2120-01-07 00:00:00", + "2120-01-13 00:00:00", + "2120-01-14 00:00:00", + "2120-01-20 00:00:00", + "2120-01-21 00:00:00", + "2120-01-27 00:00:00", + "2120-01-28 00:00:00", + "2120-02-03 00:00:00", + "2120-02-04 00:00:00", + "2120-02-10 00:00:00", + "2120-02-11 00:00:00", + "2120-02-17 00:00:00", + "2120-02-18 00:00:00", + "2120-02-24 00:00:00", + "2120-02-25 00:00:00", + "2120-03-02 00:00:00", + "2120-03-03 00:00:00", + "2120-03-09 00:00:00", + "2120-03-10 00:00:00", + "2120-03-16 00:00:00", + "2120-03-17 00:00:00", + "2120-03-23 00:00:00", + "2120-03-24 00:00:00", + "2120-03-30 00:00:00", + "2120-03-31 00:00:00", + "2120-04-06 00:00:00", + "2120-04-07 00:00:00", + "2120-04-13 00:00:00", + "2120-04-14 00:00:00", + "2120-04-20 00:00:00", + "2120-04-21 00:00:00", + "2120-04-27 00:00:00", + "2120-04-28 00:00:00", + "2120-05-04 00:00:00", + "2120-05-05 00:00:00", + "2120-05-11 00:00:00", + "2120-05-12 00:00:00", + "2120-05-18 00:00:00", + "2120-05-19 00:00:00", + "2120-05-25 00:00:00", + "2120-05-26 00:00:00", + "2120-06-01 00:00:00", + "2120-06-02 00:00:00", + "2120-06-08 00:00:00", + "2120-06-09 00:00:00", + "2120-06-15 00:00:00", + "2120-06-16 00:00:00", + "2120-06-22 00:00:00", + "2120-06-23 00:00:00", + "2120-06-29 00:00:00", + "2120-06-30 00:00:00", + "2120-07-06 00:00:00", + "2120-07-07 00:00:00", + "2120-07-13 00:00:00", + "2120-07-14 00:00:00", + "2120-07-20 00:00:00", + "2120-07-21 00:00:00", + "2120-07-27 00:00:00", + "2120-07-28 00:00:00", + "2120-08-03 00:00:00", + "2120-08-04 00:00:00", + "2120-08-10 00:00:00", + "2120-08-11 00:00:00", + "2120-08-17 00:00:00", + "2120-08-18 00:00:00", + "2120-08-24 00:00:00", + "2120-08-25 00:00:00", + "2120-08-31 00:00:00", + "2120-09-01 00:00:00", + "2120-09-07 00:00:00", + "2120-09-08 00:00:00", + "2120-09-14 00:00:00", + "2120-09-15 00:00:00", + "2120-09-21 00:00:00", + "2120-09-22 00:00:00", + "2120-09-28 00:00:00", + "2120-09-29 00:00:00", + "2120-10-05 00:00:00", + "2120-10-06 00:00:00", + "2120-10-12 00:00:00", + "2120-10-13 00:00:00", + "2120-10-19 00:00:00", + "2120-10-20 00:00:00", + "2120-10-26 00:00:00", + "2120-10-27 00:00:00", + "2120-11-02 00:00:00", + "2120-11-03 00:00:00", + "2120-11-09 00:00:00", + "2120-11-10 00:00:00", + "2120-11-16 00:00:00", + "2120-11-17 00:00:00", + "2120-11-23 00:00:00", + "2120-11-24 00:00:00", + "2120-11-30 00:00:00", + "2120-12-01 00:00:00", + "2120-12-07 00:00:00", + "2120-12-08 00:00:00", + "2120-12-14 00:00:00", + "2120-12-15 00:00:00", + "2120-12-21 00:00:00", + "2120-12-22 00:00:00", + "2120-12-28 00:00:00", + "2120-12-29 00:00:00", + "2121-01-04 00:00:00", + "2121-01-05 00:00:00", + "2121-01-11 00:00:00", + "2121-01-12 00:00:00", + "2121-01-18 00:00:00", + "2121-01-19 00:00:00", + "2121-01-25 00:00:00", + "2121-01-26 00:00:00", + "2121-02-01 00:00:00", + "2121-02-02 00:00:00", + "2121-02-08 00:00:00", + "2121-02-09 00:00:00", + "2121-02-15 00:00:00", + "2121-02-16 00:00:00", + "2121-02-22 00:00:00", + "2121-02-23 00:00:00", + "2121-03-01 00:00:00", + "2121-03-02 00:00:00", + "2121-03-08 00:00:00", + "2121-03-09 00:00:00", + "2121-03-15 00:00:00", + "2121-03-16 00:00:00", + "2121-03-22 00:00:00", + "2121-03-23 00:00:00", + "2121-03-29 00:00:00", + "2121-03-30 00:00:00", + "2121-04-05 00:00:00", + "2121-04-06 00:00:00", + "2121-04-12 00:00:00", + "2121-04-13 00:00:00", + "2121-04-19 00:00:00", + "2121-04-20 00:00:00", + "2121-04-26 00:00:00", + "2121-04-27 00:00:00", + "2121-05-03 00:00:00", + "2121-05-04 00:00:00", + "2121-05-10 00:00:00", + "2121-05-11 00:00:00", + "2121-05-17 00:00:00", + "2121-05-18 00:00:00", + "2121-05-24 00:00:00", + "2121-05-25 00:00:00", + "2121-05-31 00:00:00", + "2121-06-01 00:00:00", + "2121-06-07 00:00:00", + "2121-06-08 00:00:00", + "2121-06-14 00:00:00", + "2121-06-15 00:00:00", + "2121-06-21 00:00:00", + "2121-06-22 00:00:00", + "2121-06-28 00:00:00", + "2121-06-29 00:00:00", + "2121-07-05 00:00:00", + "2121-07-06 00:00:00", + "2121-07-12 00:00:00", + "2121-07-13 00:00:00", + "2121-07-19 00:00:00", + "2121-07-20 00:00:00", + "2121-07-26 00:00:00", + "2121-07-27 00:00:00", + "2121-08-02 00:00:00", + "2121-08-03 00:00:00", + "2121-08-09 00:00:00", + "2121-08-10 00:00:00", + "2121-08-16 00:00:00", + "2121-08-17 00:00:00", + "2121-08-23 00:00:00", + "2121-08-24 00:00:00", + "2121-08-30 00:00:00", + "2121-08-31 00:00:00", + "2121-09-06 00:00:00", + "2121-09-07 00:00:00", + "2121-09-13 00:00:00", + "2121-09-14 00:00:00", + "2121-09-20 00:00:00", + "2121-09-21 00:00:00", + "2121-09-27 00:00:00", + "2121-09-28 00:00:00", + "2121-10-04 00:00:00", + "2121-10-05 00:00:00", + "2121-10-11 00:00:00", + "2121-10-12 00:00:00", + "2121-10-18 00:00:00", + "2121-10-19 00:00:00", + "2121-10-25 00:00:00", + "2121-10-26 00:00:00", + "2121-11-01 00:00:00", + "2121-11-02 00:00:00", + "2121-11-08 00:00:00", + "2121-11-09 00:00:00", + "2121-11-15 00:00:00", + "2121-11-16 00:00:00", + "2121-11-22 00:00:00", + "2121-11-23 00:00:00", + "2121-11-29 00:00:00", + "2121-11-30 00:00:00", + "2121-12-06 00:00:00", + "2121-12-07 00:00:00", + "2121-12-13 00:00:00", + "2121-12-14 00:00:00", + "2121-12-20 00:00:00", + "2121-12-21 00:00:00", + "2121-12-27 00:00:00", + "2121-12-28 00:00:00", + "2122-01-03 00:00:00", + "2122-01-04 00:00:00", + "2122-01-10 00:00:00", + "2122-01-11 00:00:00", + "2122-01-17 00:00:00", + "2122-01-18 00:00:00", + "2122-01-24 00:00:00", + "2122-01-25 00:00:00", + "2122-01-31 00:00:00", + "2122-02-01 00:00:00", + "2122-02-07 00:00:00", + "2122-02-08 00:00:00", + "2122-02-14 00:00:00", + "2122-02-15 00:00:00", + "2122-02-21 00:00:00", + "2122-02-22 00:00:00", + "2122-02-28 00:00:00", + "2122-03-01 00:00:00", + "2122-03-07 00:00:00", + "2122-03-08 00:00:00", + "2122-03-14 00:00:00", + "2122-03-15 00:00:00", + "2122-03-21 00:00:00", + "2122-03-22 00:00:00", + "2122-03-28 00:00:00", + "2122-03-29 00:00:00", + "2122-04-04 00:00:00", + "2122-04-05 00:00:00", + "2122-04-11 00:00:00", + "2122-04-12 00:00:00", + "2122-04-18 00:00:00", + "2122-04-19 00:00:00", + "2122-04-25 00:00:00", + "2122-04-26 00:00:00", + "2122-05-02 00:00:00", + "2122-05-03 00:00:00", + "2122-05-09 00:00:00", + "2122-05-10 00:00:00", + "2122-05-16 00:00:00", + "2122-05-17 00:00:00", + "2122-05-23 00:00:00", + "2122-05-24 00:00:00", + "2122-05-30 00:00:00", + "2122-05-31 00:00:00", + "2122-06-06 00:00:00", + "2122-06-07 00:00:00", + "2122-06-13 00:00:00", + "2122-06-14 00:00:00", + "2122-06-20 00:00:00", + "2122-06-21 00:00:00", + "2122-06-27 00:00:00", + "2122-06-28 00:00:00", + "2122-07-04 00:00:00", + "2122-07-05 00:00:00", + "2122-07-11 00:00:00", + "2122-07-12 00:00:00", + "2122-07-18 00:00:00", + "2122-07-19 00:00:00", + "2122-07-25 00:00:00", + "2122-07-26 00:00:00", + "2122-08-01 00:00:00", + "2122-08-02 00:00:00", + "2122-08-08 00:00:00", + "2122-08-09 00:00:00", + "2122-08-15 00:00:00", + "2122-08-16 00:00:00", + "2122-08-22 00:00:00", + "2122-08-23 00:00:00", + "2122-08-29 00:00:00", + "2122-08-30 00:00:00", + "2122-09-05 00:00:00", + "2122-09-06 00:00:00", + "2122-09-12 00:00:00", + "2122-09-13 00:00:00", + "2122-09-19 00:00:00", + "2122-09-20 00:00:00", + "2122-09-26 00:00:00", + "2122-09-27 00:00:00", + "2122-10-03 00:00:00", + "2122-10-04 00:00:00", + "2122-10-10 00:00:00", + "2122-10-11 00:00:00", + "2122-10-17 00:00:00", + "2122-10-18 00:00:00", + "2122-10-24 00:00:00", + "2122-10-25 00:00:00", + "2122-10-31 00:00:00", + "2122-11-01 00:00:00", + "2122-11-07 00:00:00", + "2122-11-08 00:00:00", + "2122-11-14 00:00:00", + "2122-11-15 00:00:00", + "2122-11-21 00:00:00", + "2122-11-22 00:00:00", + "2122-11-28 00:00:00", + "2122-11-29 00:00:00", + "2122-12-05 00:00:00", + "2122-12-06 00:00:00", + "2122-12-12 00:00:00", + "2122-12-13 00:00:00", + "2122-12-19 00:00:00", + "2122-12-20 00:00:00", + "2122-12-26 00:00:00", + "2122-12-27 00:00:00", + "2123-01-02 00:00:00", + "2123-01-03 00:00:00", + "2123-01-09 00:00:00", + "2123-01-10 00:00:00", + "2123-01-16 00:00:00", + "2123-01-17 00:00:00", + "2123-01-23 00:00:00", + "2123-01-24 00:00:00", + "2123-01-30 00:00:00", + "2123-01-31 00:00:00", + "2123-02-06 00:00:00", + "2123-02-07 00:00:00", + "2123-02-13 00:00:00", + "2123-02-14 00:00:00", + "2123-02-20 00:00:00", + "2123-02-21 00:00:00", + "2123-02-27 00:00:00", + "2123-02-28 00:00:00", + "2123-03-06 00:00:00", + "2123-03-07 00:00:00", + "2123-03-13 00:00:00", + "2123-03-14 00:00:00", + "2123-03-20 00:00:00", + "2123-03-21 00:00:00", + "2123-03-27 00:00:00", + "2123-03-28 00:00:00", + "2123-04-03 00:00:00", + "2123-04-04 00:00:00", + "2123-04-10 00:00:00", + "2123-04-11 00:00:00", + "2123-04-17 00:00:00", + "2123-04-18 00:00:00", + "2123-04-24 00:00:00", + "2123-04-25 00:00:00", + "2123-05-01 00:00:00", + "2123-05-02 00:00:00", + "2123-05-08 00:00:00", + "2123-05-09 00:00:00", + "2123-05-15 00:00:00", + "2123-05-16 00:00:00", + "2123-05-22 00:00:00", + "2123-05-23 00:00:00", + "2123-05-29 00:00:00", + "2123-05-30 00:00:00", + "2123-06-05 00:00:00", + "2123-06-06 00:00:00", + "2123-06-12 00:00:00", + "2123-06-13 00:00:00", + "2123-06-19 00:00:00", + "2123-06-20 00:00:00", + "2123-06-26 00:00:00", + "2123-06-27 00:00:00", + "2123-07-03 00:00:00", + "2123-07-04 00:00:00", + "2123-07-10 00:00:00", + "2123-07-11 00:00:00", + "2123-07-17 00:00:00", + "2123-07-18 00:00:00", + "2123-07-24 00:00:00", + "2123-07-25 00:00:00", + "2123-07-31 00:00:00", + "2123-08-01 00:00:00", + "2123-08-07 00:00:00", + "2123-08-08 00:00:00", + "2123-08-14 00:00:00", + "2123-08-15 00:00:00", + "2123-08-21 00:00:00", + "2123-08-22 00:00:00", + "2123-08-28 00:00:00", + "2123-08-29 00:00:00", + "2123-09-04 00:00:00", + "2123-09-05 00:00:00", + "2123-09-11 00:00:00", + "2123-09-12 00:00:00", + "2123-09-18 00:00:00", + "2123-09-19 00:00:00", + "2123-09-25 00:00:00", + "2123-09-26 00:00:00", + "2123-10-02 00:00:00", + "2123-10-03 00:00:00", + "2123-10-09 00:00:00", + "2123-10-10 00:00:00", + "2123-10-16 00:00:00", + "2123-10-17 00:00:00", + "2123-10-23 00:00:00", + "2123-10-24 00:00:00", + "2123-10-30 00:00:00", + "2123-10-31 00:00:00", + "2123-11-06 00:00:00", + "2123-11-07 00:00:00", + "2123-11-13 00:00:00", + "2123-11-14 00:00:00", + "2123-11-20 00:00:00", + "2123-11-21 00:00:00", + "2123-11-27 00:00:00", + "2123-11-28 00:00:00", + "2123-12-04 00:00:00", + "2123-12-05 00:00:00", + "2123-12-11 00:00:00", + "2123-12-12 00:00:00", + "2123-12-18 00:00:00", + "2123-12-19 00:00:00", + "2123-12-25 00:00:00", + "2123-12-26 00:00:00", + "2124-01-01 00:00:00", + "2124-01-02 00:00:00", + "2124-01-08 00:00:00", + "2124-01-09 00:00:00", + "2124-01-15 00:00:00", + "2124-01-16 00:00:00", + "2124-01-22 00:00:00", + "2124-01-23 00:00:00", + "2124-01-29 00:00:00", + "2124-01-30 00:00:00", + "2124-02-05 00:00:00", + "2124-02-06 00:00:00", + "2124-02-12 00:00:00", + "2124-02-13 00:00:00", + "2124-02-19 00:00:00", + "2124-02-20 00:00:00", + "2124-02-26 00:00:00", + "2124-02-27 00:00:00", + "2124-03-04 00:00:00", + "2124-03-05 00:00:00", + "2124-03-11 00:00:00", + "2124-03-12 00:00:00", + "2124-03-18 00:00:00", + "2124-03-19 00:00:00", + "2124-03-25 00:00:00", + "2124-03-26 00:00:00", + "2124-04-01 00:00:00", + "2124-04-02 00:00:00", + "2124-04-08 00:00:00", + "2124-04-09 00:00:00", + "2124-04-15 00:00:00", + "2124-04-16 00:00:00", + "2124-04-22 00:00:00", + "2124-04-23 00:00:00", + "2124-04-29 00:00:00", + "2124-04-30 00:00:00", + "2124-05-06 00:00:00", + "2124-05-07 00:00:00", + "2124-05-13 00:00:00", + "2124-05-14 00:00:00", + "2124-05-20 00:00:00", + "2124-05-21 00:00:00", + "2124-05-27 00:00:00", + "2124-05-28 00:00:00", + "2124-06-03 00:00:00", + "2124-06-04 00:00:00", + "2124-06-10 00:00:00", + "2124-06-11 00:00:00", + "2124-06-17 00:00:00", + "2124-06-18 00:00:00", + "2124-06-24 00:00:00", + "2124-06-25 00:00:00", + "2124-07-01 00:00:00", + "2124-07-02 00:00:00", + "2124-07-08 00:00:00", + "2124-07-09 00:00:00", + "2124-07-15 00:00:00", + "2124-07-16 00:00:00", + "2124-07-22 00:00:00", + "2124-07-23 00:00:00", + "2124-07-29 00:00:00", + "2124-07-30 00:00:00", + "2124-08-05 00:00:00", + "2124-08-06 00:00:00", + "2124-08-12 00:00:00", + "2124-08-13 00:00:00", + "2124-08-19 00:00:00", + "2124-08-20 00:00:00", + "2124-08-26 00:00:00", + "2124-08-27 00:00:00", + "2124-09-02 00:00:00", + "2124-09-03 00:00:00", + "2124-09-09 00:00:00", + "2124-09-10 00:00:00", + "2124-09-16 00:00:00", + "2124-09-17 00:00:00", + "2124-09-23 00:00:00", + "2124-09-24 00:00:00", + "2124-09-30 00:00:00", + "2124-10-01 00:00:00", + "2124-10-07 00:00:00", + "2124-10-08 00:00:00", + "2124-10-14 00:00:00", + "2124-10-15 00:00:00", + "2124-10-21 00:00:00", + "2124-10-22 00:00:00", + "2124-10-28 00:00:00", + "2124-10-29 00:00:00", + "2124-11-04 00:00:00", + "2124-11-05 00:00:00", + "2124-11-11 00:00:00", + "2124-11-12 00:00:00", + "2124-11-18 00:00:00", + "2124-11-19 00:00:00", + "2124-11-25 00:00:00", + "2124-11-26 00:00:00", + "2124-12-02 00:00:00", + "2124-12-03 00:00:00", + "2124-12-09 00:00:00", + "2124-12-10 00:00:00", + "2124-12-16 00:00:00", + "2124-12-17 00:00:00", + "2124-12-23 00:00:00", + "2124-12-24 00:00:00", + "2124-12-30 00:00:00", + "2124-12-31 00:00:00", + "2125-01-06 00:00:00", + "2125-01-07 00:00:00", + "2125-01-13 00:00:00", + "2125-01-14 00:00:00", + "2125-01-20 00:00:00", + "2125-01-21 00:00:00", + "2125-01-27 00:00:00", + "2125-01-28 00:00:00", + "2125-02-03 00:00:00", + "2125-02-04 00:00:00", + "2125-02-10 00:00:00", + "2125-02-11 00:00:00", + "2125-02-17 00:00:00", + "2125-02-18 00:00:00", + "2125-02-24 00:00:00", + "2125-02-25 00:00:00", + "2125-03-03 00:00:00", + "2125-03-04 00:00:00", + "2125-03-10 00:00:00", + "2125-03-11 00:00:00", + "2125-03-17 00:00:00", + "2125-03-18 00:00:00", + "2125-03-24 00:00:00", + "2125-03-25 00:00:00", + "2125-03-31 00:00:00", + "2125-04-01 00:00:00", + "2125-04-07 00:00:00", + "2125-04-08 00:00:00", + "2125-04-14 00:00:00", + "2125-04-15 00:00:00", + "2125-04-21 00:00:00", + "2125-04-22 00:00:00", + "2125-04-28 00:00:00", + "2125-04-29 00:00:00", + "2125-05-05 00:00:00", + "2125-05-06 00:00:00", + "2125-05-12 00:00:00", + "2125-05-13 00:00:00", + "2125-05-19 00:00:00", + "2125-05-20 00:00:00", + "2125-05-26 00:00:00", + "2125-05-27 00:00:00", + "2125-06-02 00:00:00", + "2125-06-03 00:00:00", + "2125-06-09 00:00:00", + "2125-06-10 00:00:00", + "2125-06-16 00:00:00", + "2125-06-17 00:00:00", + "2125-06-23 00:00:00", + "2125-06-24 00:00:00", + "2125-06-30 00:00:00", + "2125-07-01 00:00:00", + "2125-07-07 00:00:00", + "2125-07-08 00:00:00", + "2125-07-14 00:00:00", + "2125-07-15 00:00:00", + "2125-07-21 00:00:00", + "2125-07-22 00:00:00", + "2125-07-28 00:00:00", + "2125-07-29 00:00:00", + "2125-08-04 00:00:00", + "2125-08-05 00:00:00", + "2125-08-11 00:00:00", + "2125-08-12 00:00:00", + "2125-08-18 00:00:00", + "2125-08-19 00:00:00", + "2125-08-25 00:00:00", + "2125-08-26 00:00:00", + "2125-09-01 00:00:00", + "2125-09-02 00:00:00", + "2125-09-08 00:00:00", + "2125-09-09 00:00:00", + "2125-09-15 00:00:00", + "2125-09-16 00:00:00", + "2125-09-22 00:00:00", + "2125-09-23 00:00:00", + "2125-09-29 00:00:00", + "2125-09-30 00:00:00", + "2125-10-06 00:00:00", + "2125-10-07 00:00:00", + "2125-10-13 00:00:00", + "2125-10-14 00:00:00", + "2125-10-20 00:00:00", + "2125-10-21 00:00:00", + "2125-10-27 00:00:00", + "2125-10-28 00:00:00", + "2125-11-03 00:00:00", + "2125-11-04 00:00:00", + "2125-11-10 00:00:00", + "2125-11-11 00:00:00", + "2125-11-17 00:00:00", + "2125-11-18 00:00:00", + "2125-11-24 00:00:00", + "2125-11-25 00:00:00", + "2125-12-01 00:00:00", + "2125-12-02 00:00:00", + "2125-12-08 00:00:00", + "2125-12-09 00:00:00", + "2125-12-15 00:00:00", + "2125-12-16 00:00:00", + "2125-12-22 00:00:00", + "2125-12-23 00:00:00", + "2125-12-29 00:00:00", + "2125-12-30 00:00:00", +]; diff --git a/rust/scheduling/calendars/named/bjs_script.py b/rust/scheduling/calendars/named/bjs_script.py new file mode 100644 index 000000000..11f67eaa2 --- /dev/null +++ b/rust/scheduling/calendars/named/bjs_script.py @@ -0,0 +1,1350 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + +from datetime import datetime, timedelta + +import pandas as pd +from pandas.tseries.holiday import ( + AbstractHolidayCalendar, + Holiday, +) +from pandas.tseries.offsets import CustomBusinessDay + +""" +The Chinese holiday system is quite complex. This script focuses on 2025 and later. + +Most holidays are defined relative to lunar or solar events whose dates must be known or tabulated +in advance. Some of the data here is collected versus external, cited sources. + +A system of bridging and repaying holidays is in force meaning generic week masks cannot be +applied becuase some Saturdays or Sundays will be official work days. + +Regulation in 2025 aimed to reduce the number of "owed" days but these still exist throughout the +year. + +For each holiday this script aims to return a list of holiday dates and a list of compensation +days, if required. + +""" + + +def weekday_mask( + weekdays: list[int], years: tuple[int, int], exclude: list[datetime] +) -> list[datetime]: + iterate = datetime(years[0], month=1, day=1) + end = datetime(years[1], month=12, day=31) + holidays = [] + while iterate < end: + if iterate.weekday() in weekdays and iterate not in exclude: + holidays.append( + Holiday( + f"Weekday Mask {iterate.strftime('yymmdd')}", + year=iterate.year, + month=iterate.month, + day=iterate.day, + ) + ) + iterate = iterate + timedelta(days=1) + return holidays + + +def new_years_holidays(year: int) -> list[datetime]: + dt = datetime(year=year, month=1, day=1) + if dt.weekday() in [3, 4, 5]: + # Th, Fr, Sa roll forwards + idx = 0 + elif dt.weekday() in [0, 1]: + # Mo, Tu roll backwards + idx = -2 + elif dt.weekday() in [2]: + # We is single day + return [dt] + elif dt.weekday() in [6]: + # Su roll backwards + idx = -1 + return [dt + timedelta(days=i) for i in range(idx, idx + 3)] + + +def new_years_compensations(year: int) -> list[datetime]: + dt = datetime(year=year, month=1, day=1) + if dt.weekday() in [0, 2, 4, 5, 6]: + return [] + elif dt.weekday() in [1]: + return [datetime(year=year - 1, month=12, day=29)] + else: + return [datetime(year=year, month=1, day=4)] + + +# parsed with re: from https://taiwan-database.net/PDFs/WTFpdf23.pdf +lunar_new_year_dates = [ + "1800-01-25", + "1801-02-13", + "1802-02-03", + "1803-01-23", + "1804-02-11", + "1805-01-31", + "1806-02-18", + "1807-02-07", + "1808-01-28", + "1809-02-14", + "1810-02-04", + "1811-01-25", + "1812-02-13", + "1813-02-01", + "1814-01-21", + "1815-02-09", + "1816-01-29", + "1817-02-16", + "1818-02-05", + "1819-01-26", + "1820-02-14", + "1821-02-03", + "1822-01-23", + "1823-02-11", + "1824-01-31", + "1825-02-18", + "1826-02-07", + "1827-01-27", + "1828-02-15", + "1829-02-04", + "1830-01-25", + "1831-02-13", + "1832-02-02", + "1833-02-20", + "1834-02-09", + "1835-01-29", + "1836-02-17", + "1837-02-05", + "1838-01-26", + "1839-02-14", + "1840-02-03", + "1841-01-23", + "1842-02-10", + "1843-01-30", + "1844-02-18", + "1845-02-07", + "1846-01-27", + "1847-02-15", + "1848-02-05", + "1849-01-24", + "1850-02-12", + "1851-02-01", + "1852-02-20", + "1853-02-08", + "1854-01-29", + "1855-02-17", + "1856-02-06", + "1857-01-26", + "1858-02-14", + "1859-02-03", + "1860-01-23", + "1861-02-10", + "1862-01-30", + "1863-02-18", + "1864-02-08", + "1865-01-27", + "1866-02-15", + "1867-02-05", + "1868-01-25", + "1869-02-11", + "1870-01-31", + "1871-02-19", + "1872-02-09", + "1873-01-29", + "1874-02-17", + "1875-02-06", + "1876-01-26", + "1877-02-13", + "1878-02-02", + "1879-01-22", + "1880-02-10", + "1881-01-30", + "1882-02-18", + "1883-02-08", + "1884-01-28", + "1885-02-15", + "1886-02-04", + "1887-01-24", + "1888-02-12", + "1889-01-31", + "1890-01-21", + "1891-02-09", + "1892-01-30", + "1893-02-17", + "1894-02-06", + "1895-01-26", + "1896-02-13", + "1897-02-02", + "1898-01-22", + "1899-02-10", + "1900-01-31", + "1901-02-19", + "1902-02-08", + "1903-01-29", + "1904-02-16", + "1905-02-04", + "1906-01-25", + "1907-02-13", + "1908-02-02", + "1909-01-22", + "1910-02-10", + "1911-01-30", + "1912-02-18", + "1913-02-06", + "1914-01-26", + "1915-02-14", + "1916-02-03", + "1917-01-23", + "1918-02-11", + "1919-02-01", + "1920-02-20", + "1921-02-08", + "1922-01-28", + "1923-02-16", + "1924-02-05", + "1925-01-24", + "1926-02-13", + "1927-02-02", + "1928-01-23", + "1929-02-10", + "1930-01-30", + "1931-02-17", + "1932-02-06", + "1933-01-26", + "1934-02-14", + "1935-02-04", + "1936-01-24", + "1937-02-11", + "1938-01-31", + "1939-02-19", + "1940-02-08", + "1941-01-27", + "1942-02-15", + "1943-02-05", + "1944-01-25", + "1945-02-13", + "1946-02-02", + "1947-01-22", + "1948-02-10", + "1949-01-29", + "1950-02-17", + "1951-02-06", + "1952-01-27", + "1953-02-14", + "1954-02-03", + "1955-01-24", + "1956-02-12", + "1957-01-31", + "1958-02-18", + "1959-02-08", + "1960-01-28", + "1961-02-15", + "1962-02-05", + "1963-01-25", + "1964-02-13", + "1965-02-02", + "1966-01-21", + "1967-02-09", + "1968-01-30", + "1969-02-17", + "1970-02-06", + "1971-01-27", + "1972-02-15", + "1973-02-03", + "1974-01-23", + "1975-02-11", + "1976-01-31", + "1977-02-18", + "1978-02-07", + "1979-01-28", + "1980-02-16", + "1981-02-05", + "1982-01-25", + "1983-02-13", + "1984-02-02", + "1985-02-20", + "1986-02-09", + "1987-01-29", + "1988-02-17", + "1989-02-06", + "1990-01-27", + "1991-02-15", + "1992-02-04", + "1993-01-23", + "1994-02-10", + "1995-01-31", + "1996-02-19", + "1997-02-07", + "1998-01-28", + "1999-02-16", + "2000-02-05", + "2001-01-24", + "2002-02-12", + "2003-02-01", + "2004-01-22", + "2005-02-09", + "2006-01-29", + "2007-02-18", + "2008-02-07", + "2009-01-26", + "2010-02-14", + "2011-02-03", + "2012-01-23", + "2013-02-10", + "2014-01-31", + "2015-02-19", + "2016-02-08", + "2017-01-28", + "2018-02-16", + "2019-02-05", + "2020-01-25", + "2021-02-12", + "2022-02-01", + "2023-01-22", + "2024-02-10", + "2025-01-29", + "2026-02-17", + "2027-02-06", + "2028-01-26", + "2029-02-13", + "2030-02-02", + "2031-01-23", + "2032-02-11", + "2033-01-31", + "2034-02-19", + "2035-02-08", + "2036-01-28", + "2037-02-15", + "2038-02-04", + "2039-01-24", + "2040-02-12", + "2041-02-01", + "2042-01-22", + "2043-02-10", + "2044-01-30", + "2045-02-17", + "2046-02-06", + "2047-01-26", + "2048-02-14", + "2049-02-02", + "2050-01-23", + "2051-02-11", + "2052-02-01", + "2053-02-19", + "2054-02-08", + "2055-01-28", + "2056-02-15", + "2057-02-04", + "2058-01-24", + "2059-02-12", + "2060-02-02", + "2061-01-21", + "2062-02-09", + "2063-01-29", + "2064-02-17", + "2065-02-05", + "2066-01-26", + "2067-02-14", + "2068-02-03", + "2069-01-23", + "2070-02-11", + "2071-01-31", + "2072-02-19", + "2073-02-07", + "2074-01-27", + "2075-02-15", + "2076-02-05", + "2077-01-24", + "2078-02-12", + "2079-02-02", + "2080-01-22", + "2081-02-09", + "2082-01-29", + "2083-02-17", + "2084-02-06", + "2085-01-26", + "2086-02-14", + "2087-02-03", + "2088-01-24", + "2089-02-10", + "2090-01-30", + "2091-02-18", + "2092-02-07", + "2093-01-27", + "2094-02-15", + "2095-02-05", + "2096-01-25", + "2097-02-12", + "2098-02-01", + "2099-01-21", + "2100-02-09", +] +lunar_new_year_dict = { + k + 1800: datetime.strptime(v, "%Y-%m-%d") for k, v in enumerate(lunar_new_year_dates) +} + + +def lunar_new_year_holidays(year: int) -> list[datetime]: + try: + dt = lunar_new_year_dict[year] + except KeyError: + return [] + + if dt.weekday() in [0, 2, 3, 4, 5, 6]: + idx = (-1, 7) + elif dt.weekday() in [1]: + idx = (-2, 7) + + return [dt + timedelta(days=i) for i in range(*idx)] + + +def lunar_new_year_compensations(year: int) -> list[datetime]: + try: + dt = lunar_new_year_dict[year] + except KeyError: + return [] + + if dt.weekday() in [0]: + # previous and post saturday + return [dt + timedelta(days=-2), dt + timedelta(days=12)] + elif dt.weekday() in [1]: + # previous and post saturday + return [dt + timedelta(days=-3), dt + timedelta(days=11)] + elif dt.weekday() in [2]: + # previous Sunday and post saturday + return [dt + timedelta(days=-3), dt + timedelta(days=10)] + elif dt.weekday() in [3]: + # previous Sunday and post saturday + return [dt + timedelta(days=-4), dt + timedelta(days=9)] + elif dt.weekday() in [4]: + return [dt + timedelta(days=-5), dt + timedelta(days=8)] + elif dt.weekday() in [5]: + return [dt + timedelta(days=-6), dt + timedelta(days=7)] + elif dt.weekday() in [6]: + return [dt + timedelta(days=-7), dt + timedelta(days=7)] + + +# parsed with re: from https://taiwan-database.net/PDFs/WTFpdf23.pdf +dragon_boat_days = [ + "1900-06-01", + "1901-06-20", + "1902-06-10", + "1903-05-31", + "1904-06-18", + "1905-06-07", + "1906-06-26", + "1907-06-15", + "1908-06-03", + "1909-06-22", + "1910-06-11", + "1911-06-01", + "1912-06-19", + "1913-06-09", + "1914-05-29", + "1915-06-17", + "1916-06-05", + "1917-06-23", + "1918-06-13", + "1919-06-02", + "1920-06-20", + "1921-06-10", + "1922-05-31", + "1923-06-18", + "1924-06-06", + "1925-06-25", + "1926-06-14", + "1927-06-04", + "1928-06-22", + "1929-06-11", + "1930-06-01", + "1931-06-20", + "1932-06-08", + "1933-05-28", + "1934-06-16", + "1935-06-05", + "1936-06-23", + "1937-06-12", + "1938-06-02", + "1939-06-21", + "1940-06-10", + "1941-05-30", + "1942-06-18", + "1943-06-07", + "1944-06-25", + "1945-06-14", + "1946-06-04", + "1947-06-23", + "1948-06-11", + "1949-06-01", + "1950-06-19", + "1951-06-09", + "1952-05-28", + "1953-06-15", + "1954-06-05", + "1955-06-24", + "1956-06-13", + "1957-06-02", + "1958-06-21", + "1959-06-10", + "1960-05-29", + "1961-06-17", + "1962-06-06", + "1963-06-25", + "1964-06-14", + "1965-06-04", + "1966-06-23", + "1967-06-12", + "1968-05-31", + "1969-06-19", + "1970-06-08", + "1971-05-28", + "1972-06-15", + "1973-06-05", + "1974-06-24", + "1975-06-14", + "1976-06-02", + "1977-06-21", + "1978-06-10", + "1979-05-30", + "1980-06-17", + "1981-06-06", + "1982-06-25", + "1983-06-15", + "1984-06-04", + "1985-06-22", + "1986-06-11", + "1987-05-31", + "1988-06-18", + "1989-06-08", + "1990-05-28", + "1991-06-16", + "1992-06-05", + "1993-06-24", + "1994-06-13", + "1995-06-02", + "1996-06-20", + "1997-06-09", + "1998-05-30", + "1999-06-18", + "2000-06-06", + "2001-06-25", + "2002-06-15", + "2003-06-04", + "2004-06-22", + "2005-06-11", + "2006-05-31", + "2007-06-19", + "2008-06-08", + "2009-05-28", + "2010-06-16", + "2011-06-06", + "2012-06-23", + "2013-06-13", + "2014-06-02", + "2015-06-20", + "2016-06-09", + "2017-05-30", + "2018-06-18", + "2019-06-07", + "2020-06-25", + "2021-06-14", + "2022-06-03", + "2023-06-22", + "2024-06-10", + "2025-05-31", + "2026-06-19", + "2027-06-09", + "2028-05-28", + "2029-06-16", + "2030-06-05", + "2031-06-24", + "2032-06-12", + "2033-06-01", + "2034-06-20", + "2035-06-10", + "2036-05-30", + "2037-06-18", + "2038-06-07", + "2039-05-27", + "2040-06-14", + "2041-06-03", + "2042-06-22", + "2043-06-11", + "2044-05-31", + "2045-06-19", + "2046-06-08", + "2047-05-29", + "2048-06-15", + "2049-06-04", + "2050-06-23", + "2051-06-13", + "2052-06-01", + "2053-06-20", + "2054-06-10", + "2055-05-30", + "2056-06-17", + "2057-06-06", + "2058-06-25", + "2059-06-14", + "2060-06-03", + "2061-06-22", + "2062-06-11", + "2063-06-01", + "2064-06-19", + "2065-06-08", + "2066-05-28", + "2067-06-16", + "2068-06-04", + "2069-06-23", + "2070-06-13", + "2071-06-02", + "2072-06-20", + "2073-06-10", + "2074-05-30", + "2075-06-17", + "2076-06-06", + "2077-06-24", + "2078-06-14", + "2079-06-04", + "2080-06-22", + "2081-06-11", + "2082-06-01", + "2083-06-19", + "2084-06-07", + "2085-05-27", + "2086-06-15", + "2087-06-05", + "2088-06-23", + "2089-06-13", + "2090-06-02", + "2091-06-21", + "2092-06-09", + "2093-05-29", + "2094-06-17", + "2095-06-06", + "2096-06-24", + "2097-06-14", + "2098-06-04", + "2099-06-23", + "2100-06-12", +] +dragon_boat_dict = { + k + 1900: datetime.strptime(v, "%Y-%m-%d") for k, v in enumerate(dragon_boat_days) +} + + +def three_day_holidays(dt: datetime) -> list[datetime]: + if dt.weekday() in [3, 4]: + # holidays on the weekend after + return [dt + timedelta(days=i) for i in range(3)] + elif dt.weekday() in [0, 1]: + # holidays on the weekend before + return [dt + timedelta(days=i) for i in range(-2, 1)] + elif dt.weekday() in [2]: + # only one mid-week holiday day + return [dt + timedelta(days=i) for i in range(1)] + elif dt.weekday() in [5]: + # sat, sun and mon + start = 0 + elif dt.weekday() in [6]: + # sat, sun, mon + start = -1 + return [dt + timedelta(days=i) for i in range(start, start + 3)] + + +def three_day_compensations(dt: datetime) -> list[datetime]: + if dt.weekday() in [1]: + # compensate by preceding Su + return [dt + timedelta(days=-9)] + if dt.weekday() in [3]: + # following Su + return [dt + timedelta(days=10)] + else: + return [] + + +def dragon_boat_holidays(year: int) -> list[datetime]: + try: + dt = dragon_boat_dict[year] + except KeyError: + return [] + + return three_day_holidays(dt) + + +def dragon_boat_compensations(year: int) -> list[datetime]: + try: + dt = dragon_boat_dict[year] + except KeyError: + return [] + + return three_day_compensations(dt) + + +vernal_equinox_date = [ + "1970-03-21", + "1971-03-21", + "1972-03-20", + "1973-03-20", + "1974-03-21", + "1975-03-21", + "1976-03-20", + "1977-03-20", + "1978-03-20", + "1979-03-21", + "1980-03-20", + "1981-03-20", + "1982-03-20", + "1983-03-21", + "1984-03-20", + "1985-03-20", + "1986-03-20", + "1987-03-21", + "1988-03-20", + "1989-03-20", + "1990-03-20", + "1991-03-21", + "1992-03-20", + "1993-03-20", + "1994-03-20", + "1995-03-21", + "1996-03-20", + "1997-03-20", + "1998-03-20", + "1999-03-21", + "2000-03-20", + "2001-03-20", + "2002-03-20", + "2003-03-21", + "2004-03-20", + "2005-03-20", + "2006-03-20", + "2007-03-21", + "2008-03-20", + "2009-03-20", + "2010-03-20", + "2011-03-20", + "2012-03-20", + "2013-03-20", + "2014-03-20", + "2015-03-20", + "2016-03-21", # Manual edit + "2017-03-20", + "2018-03-21", # Manual edit + "2019-03-20", + "2020-03-20", + "2021-03-21", # Manual edit + "2022-03-21", # Manual edit + "2023-03-21", # Manual edit + "2024-03-20", + "2025-03-20", + "2026-03-20", + "2027-03-20", + "2028-03-20", + "2029-03-20", + "2030-03-20", + "2031-03-20", + "2032-03-20", + "2033-03-20", + "2034-03-20", + "2035-03-20", + "2036-03-20", + "2037-03-20", + "2038-03-20", + "2039-03-20", + "2040-03-20", + "2041-03-20", + "2042-03-20", + "2043-03-20", + "2044-03-19", + "2045-03-20", + "2046-03-20", + "2047-03-20", + "2048-03-19", + "2049-03-20", + "2050-03-20", + "2051-03-20", + "2052-03-19", + "2053-03-20", + "2054-03-20", + "2055-03-20", + "2056-03-19", + "2057-03-20", + "2058-03-20", + "2059-03-20", + "2060-03-19", + "2061-03-20", + "2062-03-20", + "2063-03-20", + "2064-03-19", + "2065-03-20", + "2066-03-20", + "2067-03-20", + "2068-03-19", + "2069-03-20", + "2070-03-20", + "2071-03-20", + "2072-03-19", + "2073-03-20", + "2074-03-20", + "2075-03-20", + "2076-03-19", + "2077-03-19", + "2078-03-20", + "2079-03-20", + "2080-03-19", + "2081-03-19", + "2082-03-20", + "2083-03-20", + "2084-03-19", + "2085-03-19", + "2086-03-20", + "2087-03-20", + "2088-03-19", + "2089-03-19", + "2090-03-20", + "2091-03-20", + "2092-03-19", + "2093-03-19", + "2094-03-20", + "2095-03-20", + "2096-03-19", + "2097-03-19", + "2098-03-20", + "2099-03-20", + "2100-03-20", + "2101-03-20", + "2102-03-21", + "2103-03-21", + "2104-03-20", + "2105-03-20", + "2106-03-21", + "2107-03-21", + "2108-03-20", + "2109-03-20", + "2110-03-20", + "2111-03-21", + "2112-03-20", + "2113-03-20", + "2114-03-20", + "2115-03-21", + "2116-03-20", + "2117-03-20", + "2118-03-20", + "2119-03-21", + "2120-03-20", + "2121-03-20", + "2122-03-20", + "2123-03-21", + "2124-03-20", + "2125-03-20", + "2126-03-20", + "2127-03-21", + "2128-03-20", + "2129-03-20", + "2130-03-20", + "2131-03-21", + "2132-03-20", + "2133-03-20", + "2134-03-20", + "2135-03-21", + "2136-03-20", + "2137-03-20", + "2138-03-20", + "2139-03-20", + "2140-03-20", + "2141-03-20", + "2142-03-20", + "2143-03-20", + "2144-03-20", + "2145-03-20", + "2146-03-20", + "2147-03-20", + "2148-03-20", + "2149-03-20", + "2150-03-20", + "2151-03-20", + "2152-03-20", + "2153-03-20", + "2154-03-20", + "2155-03-20", + "2156-03-20", + "2157-03-20", + "2158-03-20", + "2159-03-20", + "2160-03-20", + "2161-03-20", + "2162-03-20", + "2163-03-20", + "2164-03-20", + "2165-03-20", + "2166-03-20", + "2167-03-20", + "2168-03-20", + "2169-03-20", + "2170-03-20", + "2171-03-20", + "2172-03-19", + "2173-03-20", + "2174-03-20", + "2175-03-20", + "2176-03-19", + "2177-03-20", + "2178-03-20", + "2179-03-20", + "2180-03-19", + "2181-03-20", + "2182-03-20", + "2183-03-20", + "2184-03-19", + "2185-03-20", + "2186-03-20", + "2187-03-20", + "2188-03-19", + "2189-03-20", + "2190-03-20", + "2191-03-20", + "2192-03-19", + "2193-03-20", + "2194-03-20", + "2195-03-20", + "2196-03-19", + "2197-03-20", + "2198-03-20", + "2199-03-20", + "2200-03-20", +] +vernal_equinox_dict = { + k + 1970: datetime.strptime(v, "%Y-%m-%d") for k, v in enumerate(vernal_equinox_date) +} + +mid_autumn_festival_dates = [ + "1900-09-08", + "1901-09-27", + "1902-09-16", + "1903-10-05", + "1904-09-24", + "1905-09-13", + "1906-10-02", + "1907-09-22", + "1908-09-10", + "1909-09-28", + "1910-09-18", + "1911-10-06", + "1912-09-25", + "1913-09-15", + "1914-10-04", + "1915-09-23", + "1916-09-12", + "1917-09-30", + "1918-09-19", + "1919-10-08", + "1920-09-26", + "1921-09-16", + "1922-10-05", + "1923-09-25", + "1924-09-13", + "1925-10-02", + "1926-09-21", + "1927-09-10", + "1928-09-28", + "1929-09-17", + "1930-10-06", + "1931-09-26", + "1932-09-15", + "1933-10-04", + "1934-09-23", + "1935-09-12", + "1936-09-30", + "1937-09-18", + "1938-10-08", + "1939-09-27", + "1940-09-16", + "1941-10-05", + "1942-09-24", + "1943-09-14", + "1944-10-01", + "1945-09-20", + "1946-09-10", + "1947-09-29", + "1948-09-17", + "1949-10-06", + "1950-09-26", + "1951-09-15", + "1952-10-03", + "1953-09-22", + "1954-09-11", + "1955-09-30", + "1956-09-19", + "1957-09-08", + "1958-09-27", + "1959-09-17", + "1960-10-05", + "1961-09-24", + "1962-09-13", + "1963-10-02", + "1964-09-20", + "1965-09-10", + "1966-09-29", + "1967-09-18", + "1968-10-06", + "1969-09-26", + "1970-09-15", + "1971-10-03", + "1972-09-22", + "1973-09-11", + "1974-09-30", + "1975-09-20", + "1976-09-08", + "1977-09-27", + "1978-09-17", + "1979-10-05", + "1980-09-23", + "1981-09-12", + "1982-10-01", + "1983-09-21", + "1984-09-10", + "1985-09-29", + "1986-09-18", + "1987-10-07", + "1988-09-25", + "1989-09-14", + "1990-10-03", + "1991-09-22", + "1992-09-11", + "1993-09-30", + "1994-09-20", + "1995-09-09", + "1996-09-27", + "1997-09-16", + "1998-10-05", + "1999-09-24", + "2000-09-12", + "2001-10-01", + "2002-09-21", + "2003-09-11", + "2004-09-28", + "2005-09-18", + "2006-10-06", + "2007-09-25", + "2008-09-14", + "2009-10-03", + "2010-09-22", + "2011-09-12", + "2012-09-30", + "2013-09-19", + "2014-09-08", + "2015-09-27", + "2016-09-15", + "2017-10-04", + "2018-09-24", + "2019-09-13", + "2020-10-01", + "2021-09-21", + "2022-09-10", + "2023-09-29", + "2024-09-17", + "2025-10-06", + "2026-09-25", + "2027-09-15", + "2028-10-03", + "2029-09-22", + "2030-09-12", + "2031-10-01", + "2032-09-19", + "2033-09-08", + "2034-09-27", + "2035-09-16", + "2036-10-04", + "2037-09-24", + "2038-09-13", + "2039-10-02", + "2040-09-20", + "2041-09-10", + "2042-09-28", + "2043-09-17", + "2044-10-05", + "2045-09-25", + "2046-09-15", + "2047-10-04", + "2048-09-22", + "2049-09-11", + "2050-09-30", + "2051-09-19", + "2052-09-07", + "2053-09-26", + "2054-09-16", + "2055-10-05", + "2056-09-24", + "2057-09-13", + "2058-10-02", + "2059-09-21", + "2060-09-09", + "2061-09-28", + "2062-09-17", + "2063-10-06", + "2064-09-25", + "2065-09-15", + "2066-10-03", + "2067-09-23", + "2068-09-11", + "2069-09-29", + "2070-09-19", + "2071-09-08", + "2072-09-26", + "2073-09-16", + "2074-10-05", + "2075-09-24", + "2076-09-12", + "2077-10-01", + "2078-09-20", + "2079-09-10", + "2080-09-28", + "2081-09-17", + "2082-10-06", + "2083-09-26", + "2084-09-14", + "2085-10-03", + "2086-09-22", + "2087-09-11", + "2088-09-29", + "2089-09-18", + "2090-09-08", + "2091-09-27", + "2092-09-16", + "2093-10-05", + "2094-09-24", + "2095-09-13", + "2096-09-30", + "2097-09-20", + "2098-09-09", + "2099-09-29", + "2100-09-18", +] +mid_autumn_dict = { + k + 1900: datetime.strptime(v, "%Y-%m-%d") for k, v in enumerate(mid_autumn_festival_dates) +} + + +def tomb_sweeping_holidays(year: int) -> list[datetime]: + try: + dt = vernal_equinox_dict[year] + except KeyError: + return [] + # add 15 days to get to the holiday + return three_day_holidays(dt + timedelta(days=15)) + + +def tomb_sweeping_compensations(year: int) -> list[datetime]: + try: + dt = vernal_equinox_dict[year] + except KeyError: + return [] + # add 15 days to get to the holiday + return three_day_compensations(dt + timedelta(days=15)) + + +def mid_autumn_holidays(year: int) -> list[datetime]: + try: + dt = mid_autumn_dict[year] + except KeyError: + return [] + + return three_day_holidays(dt) + + +def mid_autumn_compensations(year: int) -> list[datetime]: + try: + dt = mid_autumn_dict[year] + except KeyError: + return [] + + return three_day_compensations(dt) + + +def labour_day_holidays(year: int) -> list[datetime]: + # golden 5 day holiday + dt = datetime(year=year, month=5, day=1) + + if dt.weekday() == 0: + idx = (-2, 3) + elif dt.weekday() == 1: + idx = (-3, 2) + elif dt.weekday() == 2: + idx = (0, 2) + elif dt.weekday() == 3 or dt.weekday() == 4 or dt.weekday() == 5: + idx = (0, 5) + elif dt.weekday() == 6: + idx = (-1, 4) + + return [dt + timedelta(days=i) for i in range(*idx)] + + +def labour_day_compensations(year: int) -> list[datetime]: + dt = datetime(year=year, month=5, day=1) + + if dt.weekday() == 0: + # following Su + return [dt + timedelta(days=6)] + elif dt.weekday() == 1: + # Previous Sa + return [dt + timedelta(days=-3)] + elif dt.weekday() in [2]: + # no compensation for Wednesday + return [] + elif dt.weekday() in [3]: + # Previous Su + return [dt + timedelta(days=-4)] + elif dt.weekday() in [4]: + # Following Sa + return [dt + timedelta(days=8)] + elif dt.weekday() in [5]: + # Following Su + return [dt + timedelta(days=8)] + elif dt.weekday() in [6]: + # Following Su + return [dt + timedelta(days=7)] + + +def national_day_holidays(year: int) -> list[datetime]: + return [datetime(year=year, month=10, day=1) + timedelta(days=i) for i in range(7)] + + +def national_day_compensations(year: int) -> list[datetime]: + dt = datetime(year=year, month=10, day=1) + + if dt.weekday() == 0: + return [dt + timedelta(days=-2), dt + timedelta(days=12)] + if dt.weekday() == 1: + return [dt + timedelta(days=-2), dt + timedelta(days=11)] + if dt.weekday() == 2: + return [dt + timedelta(days=-3), dt + timedelta(days=10)] + if dt.weekday() == 3: + return [dt + timedelta(days=-4), dt + timedelta(days=9)] + if dt.weekday() == 4: + return [dt + timedelta(days=-5), dt + timedelta(days=8)] + if dt.weekday() == 5: + return [dt + timedelta(days=-6), dt + timedelta(days=8)] + if dt.weekday() == 6: + return [dt + timedelta(days=-7), dt + timedelta(days=7)] + + +def national_day_and_mid_autumn_holidays(year: int) -> list[datetime]: + # broad stroke approximations to merge National holiday and Mid Autumn overlaps + mu_holidays = mid_autumn_holidays(year) + nat_holidays = national_day_holidays(year) + + if mu_holidays[-1] <= nat_holidays[-1] and mu_holidays[0] >= nat_holidays[0]: + # then mu holidays are contained within nat holidays so extend + return nat_holidays + [datetime(year=year, month=10, day=8)] + else: + return mu_holidays + nat_holidays + + +def national_day_and_mid_autumn_compensations(year: int) -> list[datetime]: + # broad stroke approximations to merge National holiday and Mid Autumn overlaps + mu_holidays = mid_autumn_holidays(year) + nat_holidays = national_day_holidays(year) + mu_compensations = mid_autumn_compensations(year) # can only be at most 1 date + nat_compensations = national_day_compensations(year) # will be 2 dates + + if len(mu_compensations) > 0 and mu_compensations in nat_holidays: + mu_compensations = [mu_compensations[0] - timedelta(days=7)] + + if nat_compensations[0] in mu_holidays: + nat_compensations[0] = nat_compensations[0] - timedelta(days=7) + + return mu_compensations + nat_compensations + + +def apply_years(years: tuple[int, int], func) -> list[datetime]: + h = [] + for year in range(years[0], years[1] + 1): + h.extend(func(year)) + return h + + +def apply_years_H(years: tuple[int, int], func) -> list[Holiday]: + return [ + Holiday("Date: {_.strftime('%Y-%m-%d')}", year=_.year, month=_.month, day=_.day) + for _ in apply_years(years, func) + ] + + +COMPENSATIONS = [ + *apply_years((2025, 2100), new_years_compensations), + *apply_years((2025, 2100), lunar_new_year_compensations), + *apply_years((2025, 2100), dragon_boat_compensations), + *apply_years((2025, 2100), tomb_sweeping_compensations), + *apply_years((2025, 2100), labour_day_compensations), + *apply_years((2025, 2100), national_day_and_mid_autumn_compensations), +] + +RULES = [ + # these provide a custom saturday sunday weekmask but add back specific trading days at weekend + *weekday_mask(weekdays=[5, 6], years=(1970, 2125), exclude=COMPENSATIONS), + *apply_years_H((2025, 2100), new_years_holidays), + *apply_years_H((2025, 2100), lunar_new_year_holidays), + *apply_years_H((2025, 2100), dragon_boat_holidays), + *apply_years_H((2025, 2100), tomb_sweeping_holidays), + *apply_years_H((2025, 2100), labour_day_holidays), + *apply_years_H((2025, 2100), national_day_and_mid_autumn_holidays), +] + +CALENDAR = CustomBusinessDay( # type: ignore[call-arg] + calendar=AbstractHolidayCalendar(rules=RULES), + weekmask="Mon Tue Wed Thu Fri Sat Sun", +) + +### RUN THE SCRIPT TO EXPORT HOLIDAY LIST +ts = pd.to_datetime(CALENDAR.holidays) +strings = ['"' + _.strftime("%Y-%m-%d %H:%M:%S") + '"' for _ in ts] +line = ",\n".join(list(dict.fromkeys(strings))) +print(line) + + +# [ +# datetime(2022, 1, 29), +# datetime(2022, 1, 30), +# datetime(2022, 4, 2), +# datetime(2022, 4, 24), +# datetime(2022, 5, 7), +# datetime(2022, 10, 8), +# datetime(2022, 10, 9), +# datetime(2022, 12, 31), +# datetime(2023, 1, 28), +# datetime(2023, 1, 29), +# datetime(2023, 4, 23), +# datetime(2023, 5, 6), +# datetime(2023, 6, 25), +# datetime(2023, 10, 7), +# datetime(2023, 10, 8), +# datetime(2023, 12, 31), +# datetime(2024, 2, 4), +# datetime(2024, 2, 18), +# datetime(2024, 4, 7), +# datetime(2024, 4, 28), +# datetime(2024, 5, 11), +# datetime(2024, 9, 14), +# datetime(2024, 9, 29), +# datetime(2024, 10, 12), +# datetime(2025, 1, 26), +# datetime(2025, 2, 8), +# datetime(2025, 4, 27), +# datetime(2025, 9, 28), +# datetime(2025, 10, 11), +# datetime(2026, 1, 4), +# datetime(2026, 2, 14), +# datetime(2026, 2, 28), +# datetime(2026, 5, 9), +# datetime(2026, 9, 20), +# datetime(2026, 10, 10), +# ], diff --git a/rust/scheduling/calendars/named/bus.rs b/rust/scheduling/calendars/named/bus.rs index 3dd29a2d6..e7006719b 100644 --- a/rust/scheduling/calendars/named/bus.rs +++ b/rust/scheduling/calendars/named/bus.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a generic Western business weekday calendar without any specific holidays. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/fed.rs b/rust/scheduling/calendars/named/fed.rs index a50886f9e..cd382dd03 100644 --- a/rust/scheduling/calendars/named/fed.rs +++ b/rust/scheduling/calendars/named/fed.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a New York business day calendar, aligned with SOFR publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/fed_script.py b/rust/scheduling/calendars/named/fed_script.py index 753c57a6a..7e57efae0 100644 --- a/rust/scheduling/calendars/named/fed_script.py +++ b/rust/scheduling/calendars/named/fed_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + from datetime import datetime import pandas as pd diff --git a/rust/scheduling/calendars/named/ldn.rs b/rust/scheduling/calendars/named/ldn.rs index 6cf498364..d27e35e28 100644 --- a/rust/scheduling/calendars/named/ldn.rs +++ b/rust/scheduling/calendars/named/ldn.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a London business day holiday calendar, aligned with SONIA publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/ldn_script.py b/rust/scheduling/calendars/named/ldn_script.py index ff3436ce9..e78048f7e 100644 --- a/rust/scheduling/calendars/named/ldn_script.py +++ b/rust/scheduling/calendars/named/ldn_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + from datetime import datetime import pandas as pd diff --git a/rust/scheduling/calendars/named/mex.rs b/rust/scheduling/calendars/named/mex.rs index ac76c05d6..0522a7a4f 100644 --- a/rust/scheduling/calendars/named/mex.rs +++ b/rust/scheduling/calendars/named/mex.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a Mexico business day holiday calendar pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/mex_script.py b/rust/scheduling/calendars/named/mex_script.py index 17d346f84..004688723 100644 --- a/rust/scheduling/calendars/named/mex_script.py +++ b/rust/scheduling/calendars/named/mex_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + import pandas as pd from dateutil.relativedelta import MO from pandas.tseries.holiday import ( diff --git a/rust/scheduling/calendars/named/mod.rs b/rust/scheduling/calendars/named/mod.rs index 55cffd300..3715d9b9d 100644 --- a/rust/scheduling/calendars/named/mod.rs +++ b/rust/scheduling/calendars/named/mod.rs @@ -1,7 +1,20 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Static data for pre-existing named holiday calendars. //! pub mod all; +pub mod bjs; pub mod bus; pub mod fed; pub mod ldn; @@ -19,14 +32,14 @@ pub mod wlg; pub mod zur; use chrono::NaiveDateTime; -use pyo3::exceptions::PyValueError; -use pyo3::PyErr; use std::collections::HashMap; +use std::sync::LazyLock; -pub(crate) fn get_weekmask_by_name(name: &str) -> Result, PyErr> { - let hmap: HashMap<&str, &[u8]> = HashMap::from([ +pub(crate) static WEEKMASKS: LazyLock> = LazyLock::new(|| { + HashMap::from([ ("all", all::WEEKMASK), ("bus", bus::WEEKMASK), + ("bjs", bjs::WEEKMASK), ("nyc", nyc::WEEKMASK), ("fed", fed::WEEKMASK), ("tgt", tgt::WEEKMASK), @@ -41,20 +54,14 @@ pub(crate) fn get_weekmask_by_name(name: &str) -> Result, PyErr> { ("wlg", wlg::WEEKMASK), ("mum", mum::WEEKMASK), ("mex", mex::WEEKMASK), - ]); - match hmap.get(name) { - None => Err(PyValueError::new_err(format!( - "'{}' is not found in list of existing calendars.", - name - ))), - Some(value) => Ok(value.to_vec()), - } -} + ]) +}); -pub(crate) fn get_holidays_by_name(name: &str) -> Result, PyErr> { - let hmap: HashMap<&str, &[&str]> = HashMap::from([ +pub(crate) static HOLIDAYS: LazyLock>> = LazyLock::new(|| { + let temp = HashMap::<&str, &[&str]>::from([ ("all", all::HOLIDAYS), ("bus", bus::HOLIDAYS), + ("bjs", bjs::HOLIDAYS), ("nyc", nyc::HOLIDAYS), ("fed", fed::HOLIDAYS), ("tgt", tgt::HOLIDAYS), @@ -70,66 +77,18 @@ pub(crate) fn get_holidays_by_name(name: &str) -> Result, PyE ("mum", mum::HOLIDAYS), ("mex", mex::HOLIDAYS), ]); - match hmap.get(name) { - None => Err(PyValueError::new_err(format!( - "'{}' is not found in list of existing calendars.", - name - ))), - Some(value) => Ok(value - .iter() - .map(|x| NaiveDateTime::parse_from_str(x, "%Y-%m-%d %H:%M:%S").unwrap()) - .collect()), + let mut m: HashMap<&str, Vec> = HashMap::new(); + for (k, v) in temp.into_iter() { + m.insert( + k, + v.iter() + .map(|x| NaiveDateTime::parse_from_str(x, "%Y-%m-%d %H:%M:%S").unwrap()) + .collect(), + ); } -} - -// fn get_rules_by_name(name: &str) -> Result, PyErr> { -// let hmap: HashMap<&str, &[&str]> = HashMap::from([ -// ("all", all::RULES), -// ("bus", bus::RULES), -// ("nyc", nyc::RULES), -// ("fed", fed::RULES), -// ("tgt", tgt::RULES), -// ("ldn", ldn::RULES), -// ("stk", stk::RULES), -// ("osl", osl::RULES), -// ("zur", zur::RULES), -// ("tro", tro::RULES), -// ("tyo", tyo::RULES), -// ("syd", syd::RULES), -// ("nsw", nsw::RULES), -// ("wlg", wlg::RULES), -// ("mum", mum::RULES), -// ("mex", mex::RULES), -// ]); -// match hmap.get(name) { -// None => Err(PyValueError::new_err(format!( -// "'{}' is not found in list of existing calendars.", -// name -// ))), -// Some(value) => Ok(value.to_vec()), -// } -// } + m +}); // UNIT TESTS #[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_get_weekmask() { - let result = get_weekmask_by_name("bus").unwrap(); - assert_eq!(result, vec![5, 6]); - } - - #[test] - fn test_get_holidays() { - let result = get_holidays_by_name("bus").unwrap(); - assert_eq!(result, vec![]); - } - - // #[test] - // fn test_get_rules() { - // let result = get_rules_by_name("bus").unwrap(); - // assert_eq!(result, Vec::<&str>::new()); - // } -} +mod tests {} diff --git a/rust/scheduling/calendars/named/mum.rs b/rust/scheduling/calendars/named/mum.rs index a2145f29b..21afec308 100644 --- a/rust/scheduling/calendars/named/mum.rs +++ b/rust/scheduling/calendars/named/mum.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a New York business day calendar, aligned with SOFR publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/mum_script.py b/rust/scheduling/calendars/named/mum_script.py index e94780435..efcbc35c7 100644 --- a/rust/scheduling/calendars/named/mum_script.py +++ b/rust/scheduling/calendars/named/mum_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + import pandas as pd from pandas.tseries.holiday import ( AbstractHolidayCalendar, diff --git a/rust/scheduling/calendars/named/nsw.rs b/rust/scheduling/calendars/named/nsw.rs index d4f2e1812..cabfca060 100644 --- a/rust/scheduling/calendars/named/nsw.rs +++ b/rust/scheduling/calendars/named/nsw.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a Sydney business day calendar, aligned with AONIA publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/nsw_script.py b/rust/scheduling/calendars/named/nsw_script.py index 2c6d0557f..06790ca94 100644 --- a/rust/scheduling/calendars/named/nsw_script.py +++ b/rust/scheduling/calendars/named/nsw_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + import pandas as pd from dateutil.relativedelta import MO from pandas.tseries.holiday import ( diff --git a/rust/scheduling/calendars/named/nyc.rs b/rust/scheduling/calendars/named/nyc.rs index 17ec6ffae..655c597a7 100644 --- a/rust/scheduling/calendars/named/nyc.rs +++ b/rust/scheduling/calendars/named/nyc.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a New York business day calendar, aligned with SOFR publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/nyc_script.py b/rust/scheduling/calendars/named/nyc_script.py index 74e7c7975..d45018616 100644 --- a/rust/scheduling/calendars/named/nyc_script.py +++ b/rust/scheduling/calendars/named/nyc_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + from datetime import datetime import pandas as pd diff --git a/rust/scheduling/calendars/named/osl.rs b/rust/scheduling/calendars/named/osl.rs index b0dbd1e9c..a4ce5bb25 100644 --- a/rust/scheduling/calendars/named/osl.rs +++ b/rust/scheduling/calendars/named/osl.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define an Oslo business day calendar, aligned with NOWA publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/osl_script.py b/rust/scheduling/calendars/named/osl_script.py index b38654004..4eb8fa039 100644 --- a/rust/scheduling/calendars/named/osl_script.py +++ b/rust/scheduling/calendars/named/osl_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + import pandas as pd from pandas.tseries.holiday import ( AbstractHolidayCalendar, diff --git a/rust/scheduling/calendars/named/stk.rs b/rust/scheduling/calendars/named/stk.rs index 82fe5be80..4e73b9e69 100644 --- a/rust/scheduling/calendars/named/stk.rs +++ b/rust/scheduling/calendars/named/stk.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a Stockholm business day calendar, aligned with SWESTR publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/stk_script.py b/rust/scheduling/calendars/named/stk_script.py index 39a605e3a..343aab7e9 100644 --- a/rust/scheduling/calendars/named/stk_script.py +++ b/rust/scheduling/calendars/named/stk_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + import pandas as pd from pandas.tseries.holiday import FR, AbstractHolidayCalendar, DateOffset, Holiday from pandas.tseries.offsets import CustomBusinessDay, Day, Easter diff --git a/rust/scheduling/calendars/named/syd.rs b/rust/scheduling/calendars/named/syd.rs index e46f52913..1ef647f78 100644 --- a/rust/scheduling/calendars/named/syd.rs +++ b/rust/scheduling/calendars/named/syd.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a Sydney business day calendar, aligned with AONIA publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/syd_script.py b/rust/scheduling/calendars/named/syd_script.py index ea882db85..893ff70fa 100644 --- a/rust/scheduling/calendars/named/syd_script.py +++ b/rust/scheduling/calendars/named/syd_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + import pandas as pd from dateutil.relativedelta import MO from pandas.tseries.holiday import ( diff --git a/rust/scheduling/calendars/named/tgt.rs b/rust/scheduling/calendars/named/tgt.rs index e82024977..3ee61cdf7 100644 --- a/rust/scheduling/calendars/named/tgt.rs +++ b/rust/scheduling/calendars/named/tgt.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a European Target holiday calendar, aligned with ESTR publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/tgt_script.py b/rust/scheduling/calendars/named/tgt_script.py index fc617c118..9de421a15 100644 --- a/rust/scheduling/calendars/named/tgt_script.py +++ b/rust/scheduling/calendars/named/tgt_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + import pandas as pd from pandas.tseries.holiday import ( AbstractHolidayCalendar, diff --git a/rust/scheduling/calendars/named/tro.rs b/rust/scheduling/calendars/named/tro.rs index dc81b5b67..610f1bab9 100644 --- a/rust/scheduling/calendars/named/tro.rs +++ b/rust/scheduling/calendars/named/tro.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a Toronto business day calendar, aligned with CORRA publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/tro_script.py b/rust/scheduling/calendars/named/tro_script.py index 4e6fd4423..7a52ae4c4 100644 --- a/rust/scheduling/calendars/named/tro_script.py +++ b/rust/scheduling/calendars/named/tro_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + from datetime import datetime import pandas as pd diff --git a/rust/scheduling/calendars/named/tyo.rs b/rust/scheduling/calendars/named/tyo.rs index 6da6e1770..480d391c6 100644 --- a/rust/scheduling/calendars/named/tyo.rs +++ b/rust/scheduling/calendars/named/tyo.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a Tokyo business day calendar, aligned with TONA publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/tyo_script.py b/rust/scheduling/calendars/named/tyo_script.py index af0cf6026..926f9708a 100644 --- a/rust/scheduling/calendars/named/tyo_script.py +++ b/rust/scheduling/calendars/named/tyo_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + from datetime import datetime, timedelta import pandas as pd diff --git a/rust/scheduling/calendars/named/wlg.rs b/rust/scheduling/calendars/named/wlg.rs index 4d95da907..ef1762279 100644 --- a/rust/scheduling/calendars/named/wlg.rs +++ b/rust/scheduling/calendars/named/wlg.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a Wellington business day calendar, aligned with NZD rate publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/wlg_script.py b/rust/scheduling/calendars/named/wlg_script.py index 139910d88..91fb8e996 100644 --- a/rust/scheduling/calendars/named/wlg_script.py +++ b/rust/scheduling/calendars/named/wlg_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + from datetime import datetime, timedelta import pandas as pd diff --git a/rust/scheduling/calendars/named/zur.rs b/rust/scheduling/calendars/named/zur.rs index 6840705e6..f5aad6d77 100644 --- a/rust/scheduling/calendars/named/zur.rs +++ b/rust/scheduling/calendars/named/zur.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Define a Zurich business day calendar, aligned with SARON publication. pub const WEEKMASK: &[u8] = &[5, 6]; // Saturday and Sunday weekend diff --git a/rust/scheduling/calendars/named/zur_script.py b/rust/scheduling/calendars/named/zur_script.py index 75b12479f..8e2f996b3 100644 --- a/rust/scheduling/calendars/named/zur_script.py +++ b/rust/scheduling/calendars/named/zur_script.py @@ -1,3 +1,14 @@ +# SPDX-License-Identifier: LicenseRef-Rateslib-Dual +# +# Copyright (c) 2026 Siffrorna Technology Limited +# +# Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +# Source-available, not open source. +# +# See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +# and/or contact info (at) rateslib (dot) com +#################################################################################################### + import pandas as pd from pandas.tseries.holiday import ( AbstractHolidayCalendar, diff --git a/rust/scheduling/calendars/named_cal.rs b/rust/scheduling/calendars/named_cal.rs index 57d1efc2e..fbec5950b 100644 --- a/rust/scheduling/calendars/named_cal.rs +++ b/rust/scheduling/calendars/named_cal.rs @@ -1,18 +1,62 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use chrono::prelude::*; use pyo3::exceptions::PyValueError; use pyo3::{pyclass, PyErr}; use serde::{Deserialize, Serialize}; +use std::sync::Arc; use crate::scheduling::{Cal, CalendarAdjustment, DateRoll, UnionCal}; +#[derive(Clone, Debug)] +pub(crate) enum CalWrapper { + Cal(Cal), + UnionCal(UnionCal), +} + +impl DateRoll for CalWrapper { + fn is_weekday(&self, date: &NaiveDateTime) -> bool { + match self { + CalWrapper::Cal(c) => c.is_weekday(date), + CalWrapper::UnionCal(c) => c.is_weekday(date), + } + } + + fn is_holiday(&self, date: &NaiveDateTime) -> bool { + match self { + CalWrapper::Cal(c) => c.is_holiday(date), + CalWrapper::UnionCal(c) => c.is_holiday(date), + } + } + + fn is_settlement(&self, date: &NaiveDateTime) -> bool { + match self { + CalWrapper::Cal(c) => c.is_settlement(date), + CalWrapper::UnionCal(c) => c.is_settlement(date), + } + } +} + +impl CalendarAdjustment for CalWrapper {} + /// A wrapper for a UnionCal struct specified by a string representation. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(from = "NamedCalDataModel")] pub struct NamedCal { pub name: String, #[serde(skip)] - pub union_cal: UnionCal, + pub(crate) inner: Arc, } #[derive(Deserialize)] @@ -35,11 +79,10 @@ impl NamedCal { /// /// # Examples /// ```rust - /// # use rateslib::scheduling::{NamedCal}; + /// # use rateslib::scheduling::{NamedCal, ndt, DateRoll}; /// let named_cal = NamedCal::try_new("ldn,tgt|fed"); /// # let named_cal = named_cal.unwrap(); - /// assert_eq!(named_cal.union_cal.calendars.len(), 2); - /// assert!(named_cal.union_cal.settlement_calendars.is_some()); + /// assert!(named_cal.is_bus_day(&ndt(2026, 2, 12))); /// ``` pub fn try_new(name: &str) -> Result { let name_ = name.to_lowercase(); @@ -52,20 +95,20 @@ impl NamedCal { let cals: Vec = parse_cals(parts[0])?; Ok(Self { name: name_, - union_cal: UnionCal { + inner: Arc::new(CalWrapper::UnionCal(UnionCal { calendars: cals, settlement_calendars: None, - }, + })), }) } else { let cals: Vec = parse_cals(parts[0])?; let settle_cals: Vec = parse_cals(parts[1])?; Ok(Self { name: name_, - union_cal: UnionCal { + inner: Arc::new(CalWrapper::UnionCal(UnionCal { calendars: cals, settlement_calendars: Some(settle_cals), - }, + })), }) } } @@ -73,15 +116,15 @@ impl NamedCal { impl DateRoll for NamedCal { fn is_weekday(&self, date: &NaiveDateTime) -> bool { - self.union_cal.is_weekday(date) + self.inner.is_weekday(date) } fn is_holiday(&self, date: &NaiveDateTime) -> bool { - self.union_cal.is_holiday(date) + self.inner.is_holiday(date) } fn is_settlement(&self, date: &NaiveDateTime) -> bool { - self.union_cal.is_settlement(date) + self.inner.is_settlement(date) } } @@ -95,15 +138,6 @@ fn parse_cals(name: &str) -> Result, PyErr> { Ok(cals) } -impl PartialEq for NamedCal -where - T: DateRoll, -{ - fn eq(&self, other: &T) -> bool { - self.union_cal.eq(other) - } -} - // UNIT TESTS #[cfg(test)] mod tests { diff --git a/rust/scheduling/calendars/union_cal.rs b/rust/scheduling/calendars/union_cal.rs index de6ef1f7f..1de285646 100644 --- a/rust/scheduling/calendars/union_cal.rs +++ b/rust/scheduling/calendars/union_cal.rs @@ -1,8 +1,21 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use chrono::prelude::*; -use pyo3::pyclass; +use pyo3::exceptions::PyKeyError; +use pyo3::{pyclass, PyErr}; use serde::{Deserialize, Serialize}; -use crate::scheduling::{ndt, Cal, CalendarAdjustment, DateRoll}; +use crate::scheduling::{Cal, CalWrapper, CalendarAdjustment, CalendarManager, DateRoll}; /// A business day calendar which is the potential union of multiple calendars. /// @@ -12,7 +25,7 @@ use crate::scheduling::{ndt, Cal, CalendarAdjustment, DateRoll}; /// - A **settleable day** is such if it is a *business day* in each one of the /// `settlement_calendars`, otherwise every calendar day is a *settleable day*. /// - A **settleable business day** is both a *business day* and a *settleable day*. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct UnionCal { /// A vector of [Cal] used to determine **business** days. @@ -39,6 +52,25 @@ impl UnionCal { settlement_calendars, } } + + /// Return a [`UnionCal`] specified by a pre-defined named identifier. + /// + /// # Examples + /// + /// ```rust + /// # use rateslib::scheduling::UnionCal; + /// let ldn_tgt_cal = UnionCal::try_from_name("ldn,tgt").unwrap(); + /// ``` + pub fn try_from_name(name: &str) -> Result { + let cm = CalendarManager::new(); + let named_cal = cm.get_with_insert(name)?; + match (*named_cal.inner).clone() { + CalWrapper::Cal(_) => Err(PyKeyError::new_err( + "`name` was key for a Cal not a UnionCal.", + )), + CalWrapper::UnionCal(cal) => Ok(cal), + } + } } impl DateRoll for UnionCal { @@ -59,28 +91,11 @@ impl DateRoll for UnionCal { impl CalendarAdjustment for UnionCal {} -impl PartialEq for UnionCal -where - T: DateRoll, -{ - fn eq(&self, other: &T) -> bool { - let cd1 = self - .cal_date_range(&ndt(1970, 1, 1), &ndt(2200, 12, 31)) - .unwrap(); - let cd2 = other - .cal_date_range(&ndt(1970, 1, 1), &ndt(2200, 12, 31)) - .unwrap(); - cd1.iter().zip(cd2.iter()).all(|(x, y)| { - self.is_bus_day(x) == other.is_bus_day(x) - && self.is_settlement(x) == other.is_settlement(y) - }) - } -} - // UNIT TESTS #[cfg(test)] mod tests { use super::*; + use crate::scheduling::ndt; fn fixture_hol_cal() -> Cal { let hols = vec![ndt(2015, 9, 5), ndt(2015, 9, 7)]; // Saturday and Monday diff --git a/rust/scheduling/convention.rs b/rust/scheduling/convention.rs index c7d87c2e4..c7c86216b 100644 --- a/rust/scheduling/convention.rs +++ b/rust/scheduling/convention.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use chrono::prelude::*; use chrono::Months; use pyo3::exceptions::PyValueError; @@ -10,7 +22,7 @@ use crate::scheduling::{ }; /// Specifier for day count conventions -#[pyclass(module = "rateslib.rs", eq, eq_int, hash, frozen)] +#[pyclass(module = "rateslib.rs", eq, eq_int, hash, frozen, from_py_object)] #[derive(Debug, Hash, Copy, Clone, Serialize, Deserialize, PartialEq)] pub enum Convention { /// Actual days in period divided by 365. diff --git a/rust/scheduling/frequency/frequency.rs b/rust/scheduling/frequency/frequency.rs index 4f5a33f8e..137cd351d 100644 --- a/rust/scheduling/frequency/frequency.rs +++ b/rust/scheduling/frequency/frequency.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::scheduling::{ndt, Adjuster, Cal, Calendar, DateRoll, RollDay}; use chrono::prelude::*; use chrono::Months; @@ -6,7 +18,7 @@ use pyo3::{pyclass, PyErr}; use serde::{Deserialize, Serialize}; /// Specifier for generating unadjusted scheduling periods. -#[pyclass(module = "rateslib.rs", eq)] +#[pyclass(module = "rateslib.rs", eq, from_py_object)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Frequency { /// A set number of business days, defined by a [`Calendar`], which can only align with a diff --git a/rust/scheduling/frequency/imm.rs b/rust/scheduling/frequency/imm.rs index fed4aeffb..059de8596 100644 --- a/rust/scheduling/frequency/imm.rs +++ b/rust/scheduling/frequency/imm.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + #![allow(non_camel_case_types)] use chrono::prelude::*; @@ -10,7 +22,7 @@ use std::cmp::{Eq, PartialEq}; use crate::scheduling::ndt; /// Specifier for IMM date definitions. -#[pyclass(module = "rateslib.rs", eq)] +#[pyclass(module = "rateslib.rs", eq, from_py_object)] #[derive(Debug, Copy, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum Imm { /// 3rd Wednesday of March, June, September and December. @@ -51,10 +63,12 @@ pub enum Imm { /// /// Commonly used by ASX 90 day NZD bank bill futures. Wed1_Post9 = 11, - /// End of any calendar month + /// End of any calendar month. Eom = 8, - /// February Leap days + /// February Leap days. Leap = 9, + /// Start of any calendar month. + Som = 12, } impl Imm { @@ -140,6 +154,13 @@ impl Imm { } Ok(date.unwrap().and_hms_opt(0, 0, 0).unwrap()) } + Imm::Som => { + let date = NaiveDate::from_ymd_opt(year, month, 1); + match date { + Some(d) => Ok(d.and_hms_opt(0, 0, 0).unwrap()), + None => return Err(PyValueError::new_err("`year` or `month` out of range.")), + } + } Imm::Leap => { if month != 2 { Err(PyValueError::new_err("Leap is only in `month`:2.")) @@ -196,6 +217,8 @@ mod tests { (Imm::Fri2, ndt(2024, 12, 13), true), (Imm::Wed1_Post9, ndt(2025, 9, 10), true), (Imm::Wed1_Post9, ndt(2026, 9, 16), true), + (Imm::Som, ndt(2025, 9, 1), true), + (Imm::Som, ndt(2026, 9, 16), false), ]; for option in options { assert_eq!(option.2, option.0.validate(&option.1)); @@ -210,6 +233,7 @@ mod tests { (Imm::Wed3, ndt(2024, 3, 21), ndt(2024, 4, 17)), (Imm::Day20_HU, ndt(2024, 3, 21), ndt(2024, 9, 20)), (Imm::Leap, ndt(2022, 1, 1), ndt(2024, 2, 29)), + (Imm::Som, ndt(2022, 1, 1), ndt(2022, 2, 1)), ]; for option in options { assert_eq!(option.2, option.0.next(&option.1)); @@ -229,6 +253,7 @@ mod tests { assert_eq!(ndt(2022, 4, 30), Imm::Eom.from_ym_opt(2022, 4).unwrap()); assert_eq!(ndt(2022, 3, 31), Imm::Eom.from_ym_opt(2022, 3).unwrap()); assert_eq!(ndt(2024, 2, 29), Imm::Leap.from_ym_opt(2024, 2).unwrap()); + assert_eq!(ndt(2024, 2, 1), Imm::Som.from_ym_opt(2024, 2).unwrap()); assert!(Imm::Leap.from_ym_opt(2022, 2).is_err()); } } diff --git a/rust/scheduling/frequency/mod.rs b/rust/scheduling/frequency/mod.rs index 3739c151d..ba067025f 100644 --- a/rust/scheduling/frequency/mod.rs +++ b/rust/scheduling/frequency/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + mod frequency; mod imm; mod rollday; diff --git a/rust/scheduling/frequency/rollday.rs b/rust/scheduling/frequency/rollday.rs index 6bfa6a6cb..1162c1e77 100644 --- a/rust/scheduling/frequency/rollday.rs +++ b/rust/scheduling/frequency/rollday.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use chrono::prelude::*; use indexmap::IndexSet; use pyo3::exceptions::PyValueError; @@ -8,7 +20,7 @@ use std::cmp::{Eq, PartialEq}; use crate::scheduling::{Adjuster, Adjustment, Calendar, Imm}; /// A roll-day used with a [`Frequency::Months`](crate::scheduling::Frequency) variant. -#[pyclass(module = "rateslib.rs", eq)] +#[pyclass(module = "rateslib.rs", eq, from_py_object)] #[derive(Debug, Copy, Hash, Clone, PartialEq, Eq, Deserialize, Serialize)] pub enum RollDay { /// A day of the month in [1, 31]. diff --git a/rust/scheduling/mod.rs b/rust/scheduling/mod.rs index 797b4a526..6f4de6220 100644 --- a/rust/scheduling/mod.rs +++ b/rust/scheduling/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Create a business day [`Calendar`], instrument [`Schedule`] and perform financial date manipulation. //! //! The purpose of this module is to provide objects which are capable of replicating all of the @@ -88,7 +100,7 @@ //! Adjuster::Actual{}, // payment_adjuster2 //! None, // payment_adjuster3 //! false, // eom -//! Some(StubInference::ShortFront), // stub_inference +//! StubInference::ShortFront, // stub_inference //! ); //! # let schedule = schedule.unwrap(); //! assert_eq!(schedule.frequency, Frequency::Months{number:3, roll: Some(RollDay::IMM())}); @@ -113,7 +125,7 @@ //! Adjuster::Actual{}, // payment_adjuster2 //! None, // payment_adjuster3 //! true, // eom -//! Some(StubInference::ShortFront), // stub_inference +//! StubInference::ShortFront, // stub_inference //! ); //! # let schedule = schedule.unwrap(); //! assert_eq!(schedule.frequency, Frequency::Months{number:3, roll: Some(RollDay::Day(31))}); @@ -130,12 +142,15 @@ mod serde; pub(crate) mod py; +pub(crate) use crate::scheduling::{ + calendars::CalWrapper, frequency::get_unadjusteds, py::PyAdjuster, +}; pub use crate::scheduling::{ calendars::{ - ndt, Adjuster, Adjustment, Cal, Calendar, CalendarAdjustment, DateRoll, NamedCal, UnionCal, + ndt, Adjuster, Adjustment, Cal, Calendar, CalendarAdjustment, CalendarManager, DateRoll, + NamedCal, UnionCal, }, convention::Convention, frequency::{Frequency, Imm, RollDay, Scheduling}, schedule::{Schedule, StubInference}, }; -pub(crate) use crate::scheduling::{frequency::get_unadjusteds, py::PyAdjuster}; diff --git a/rust/scheduling/py/adjuster.rs b/rust/scheduling/py/adjuster.rs index 09dba4eff..2d021ec1a 100644 --- a/rust/scheduling/py/adjuster.rs +++ b/rust/scheduling/py/adjuster.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Wrapper module to export to Python using pyo3 bindings. use crate::json::{DeserializedObj, JSON}; @@ -10,7 +22,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; /// Python wrapper for Adjuster to facilitate complex enum pickling. -#[pyclass(module = "rateslib.rs", name = "Adjuster", eq)] +#[pyclass(module = "rateslib.rs", name = "Adjuster", eq, from_py_object)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub(crate) enum PyAdjuster { #[pyo3(constructor = (_u8=0))] diff --git a/rust/scheduling/py/calendar.rs b/rust/scheduling/py/calendar.rs index ae59de601..d17de66e9 100644 --- a/rust/scheduling/py/calendar.rs +++ b/rust/scheduling/py/calendar.rs @@ -1,11 +1,23 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Wrapper module to export to Python using pyo3 bindings. use crate::json::json_py::DeserializedObj; use crate::json::JSON; use crate::scheduling::py::adjuster::get_roll_adjuster_from_str; use crate::scheduling::{ - Adjuster, Adjustment, Cal, Calendar, CalendarAdjustment, DateRoll, NamedCal, PyAdjuster, - RollDay, UnionCal, + Adjuster, Adjustment, Cal, CalWrapper, Calendar, CalendarAdjustment, CalendarManager, DateRoll, + NamedCal, PyAdjuster, RollDay, UnionCal, }; use chrono::NaiveDateTime; use indexmap::set::IndexSet; @@ -13,6 +25,84 @@ use pyo3::exceptions::PyValueError; use pyo3::prelude::*; use pyo3::types::PyType; use std::collections::HashSet; +use std::sync::Arc; + +#[pymethods] +impl CalendarManager { + /// Create a new calendar manager object. + /// + /// .. warning:: + /// + /// Use the ``calendars`` object specifically. It is not be necessary to create your + /// own calendar manager, which refers to the same underlying data on the heap. + /// + #[new] + fn new_py() -> Self { + CalendarManager::new() + } + + /// Add a :class:`~rateslib.scheduling.Cal` to the calendar manager. + /// + /// Parameters + /// ----------- + /// name: str + /// The name of the calendar to add, cannot use a comma (',') or pipe ('|') character. + /// calendar: Cal + /// The :class:`~rateslib.scheduling.Cal` object to add to the manager. + /// + /// Returns + /// -------- + /// None + #[pyo3(name = "add")] + fn add_py(&self, name: &str, calendar: Cal) -> PyResult<()> { + self.add(name, calendar) + } + + /// Pop a :class:`~rateslib.scheduling.Cal` or :class:`~rateslib.scheduling.UnionCal` + /// from the calendar manager. + /// + /// Parameters + /// ----------- + /// name: str + /// The name of the calendar to remove, which already exists in the manager. + /// + /// Returns + /// -------- + /// Cal, UnionCal + #[pyo3(name = "pop")] + pub fn pop_py(&self, name: &str) -> Result { + self.pop(name) + } + + /// Get a :class:`~rateslib.scheduling.NamedCal` from the calendar manager. + /// + /// Parameters + /// ----------- + /// name: str + /// The name of the calendar to lookup. + /// + /// Returns + /// -------- + /// NamedCal + #[pyo3(name = "get")] + pub fn get_py(&self, name: &str) -> Result { + self.get_with_insert(name) + } + + fn __contains__(&self, item: &str) -> bool { + self.contains_key(item) + } + + /// Get a list of calendar names in the map. + /// + /// Returns + /// -------- + /// list of str + #[pyo3(name = "keys")] + fn keys_py(&self) -> Vec { + self.keys() + } +} #[pymethods] impl Cal { @@ -348,6 +438,57 @@ impl Cal { self.cal_date_range(&start, &end) } + /// Return a string representation of a calendar under a legend. + /// + /// Parameters + /// ----------- + /// year: int + /// The year of the calendar to display. + /// month: int, optional + /// The optional month of the calendar to display. + /// + /// Returns + /// -------- + /// str + #[pyo3(name = "print", signature = (year, month = None))] + fn print_month_py(&self, year: i32, month: Option) -> PyResult { + match month { + Some(m) => Ok(self.print_month(year, m)), + None => Ok(self.print_year(year)), + } + } + + /// Return a string representation of a calendar compared to another. + /// + /// Parameters + /// ----------- + /// comparator: Cal, UnionCal, NamedCal + /// The secondary calendar to compare dates against. + /// year: int + /// The year of the calendar to display. + /// + /// Returns + /// -------- + /// str + /// + /// Examples + /// --------- + /// The following example highlights the differences between the FED and NYC calendars in 2026. + /// + /// .. ipython:: python + /// :suppress: + /// + /// from rateslib import get_calendar + /// + /// .. ipython:: python + /// + /// print(get_calendar("nyc").print_compare(get_calendar("fed"), 2026)) + /// + #[pyo3(name = "print_compare")] + fn print_compare_py(&self, comparator: Calendar, year: i32) -> PyResult { + Ok(self.print_compare(&comparator, year)) + } + // Pickling fn __getnewargs__(&self) -> PyResult<(Vec, Vec)> { Ok(( @@ -396,6 +537,21 @@ impl UnionCal { Ok(UnionCal::new(calendars, settlement_calendars)) } + /// Create a new *UnionCal* object from simple string name. + /// Parameters + /// ---------- + /// name: str + /// The string identifier for the calendar to load. + /// + /// Returns + /// ------- + /// UnionCal + #[classmethod] + #[pyo3(name = "from_name")] + fn from_name_py(_cls: &Bound<'_, PyType>, name: String) -> PyResult { + UnionCal::try_from_name(&name) + } + /// A list of specifically provided non-business days. #[getter] fn holidays(&self) -> PyResult> { @@ -566,6 +722,57 @@ impl UnionCal { self.cal_date_range(&start, &end) } + /// Return a string representation of a calendar under a legend. + /// + /// Parameters + /// ----------- + /// year: int + /// The year of the calendar to display. + /// month: int, optional + /// The optional month of the calendar to display. + /// + /// Returns + /// -------- + /// str + #[pyo3(name = "print", signature = (year, month = None))] + fn print_month_py(&self, year: i32, month: Option) -> PyResult { + match month { + Some(m) => Ok(self.print_month(year, m)), + None => Ok(self.print_year(year)), + } + } + + /// Return a string representation of a calendar compared to another. + /// + /// Parameters + /// ----------- + /// comparator: Cal, UnionCal, NamedCal + /// The secondary calendar to compare dates against. + /// year: int + /// The year of the calendar to display. + /// + /// Returns + /// -------- + /// str + /// + /// Examples + /// --------- + /// The following example highlights the differences between the FED and NYC calendars in 2026. + /// + /// .. ipython:: python + /// :suppress: + /// + /// from rateslib import get_calendar + /// + /// .. ipython:: python + /// + /// print(get_calendar("nyc").print_compare(get_calendar("fed"), 2026)) + /// + #[pyo3(name = "print_compare")] + fn print_compare_py(&self, comparator: Calendar, year: i32) -> PyResult { + Ok(self.print_compare(&comparator, year)) + } + // Pickling fn __getnewargs__(&self) -> PyResult<(Vec, Option>)> { Ok((self.calendars.clone(), self.settlement_calendars.clone())) @@ -611,13 +818,19 @@ impl NamedCal { /// A list of specifically provided non-business days. #[getter] fn holidays(&self) -> PyResult> { - self.union_cal.holidays() + match &*self.inner { + CalWrapper::Cal(c) => c.holidays(), + CalWrapper::UnionCal(c) => c.holidays(), + } } /// A list of days in the week defined as weekends. #[getter] fn week_mask(&self) -> PyResult> { - self.union_cal.week_mask() + match &*self.inner { + CalWrapper::Cal(c) => c.week_mask(), + CalWrapper::UnionCal(c) => c.week_mask(), + } } /// The string identifier for this constructed calendar. @@ -626,10 +839,27 @@ impl NamedCal { self.name.clone() } - /// The wrapped :class:`~rateslib.scheduling.UnionCal` object. + /// The wrapped :class:`~rateslib.scheduling.UnionCal` or :class:`~rateslib.scheduling.Cal` object. #[getter] - fn union_cal(&self) -> UnionCal { - self.union_cal.clone() + fn inner(&self) -> Calendar { + match (*self.inner).clone() { + CalWrapper::Cal(c) => Calendar::Cal(c), + CalWrapper::UnionCal(c) => Calendar::UnionCal(c), + } + } + + /// Check whether the memory allocation of the calendar object matches that of another. + /// + /// Parameters + /// ----------- + /// other: NamedCal + /// The other :class:`~rateslib.scheduling.NamedCal` to test memory allocation against. + /// + /// Returns + /// -------- + /// bool + fn inner_ptr_eq(&self, other: NamedCal) -> bool { + Arc::ptr_eq(&self.inner, &other.inner) } /// Return whether the `date` is a business day. @@ -769,6 +999,57 @@ impl NamedCal { self.cal_date_range(&start, &end) } + /// Return a string representation of a calendar under a legend. + /// + /// Parameters + /// ----------- + /// year: int + /// The year of the calendar to display. + /// month: int, optional + /// The optional month of the calendar to display. + /// + /// Returns + /// -------- + /// str + #[pyo3(name = "print", signature = (year, month = None))] + fn print_month_py(&self, year: i32, month: Option) -> PyResult { + match month { + Some(m) => Ok(self.print_month(year, m)), + None => Ok(self.print_year(year)), + } + } + + /// Return a string representation of a calendar compared to another. + /// + /// Parameters + /// ----------- + /// comparator: Cal, UnionCal, NamedCal + /// The secondary calendar to compare dates against. + /// year: int + /// The year of the calendar to display. + /// + /// Returns + /// -------- + /// str + /// + /// Examples + /// --------- + /// The following example highlights the differences between the FED and NYC calendars in 2026. + /// + /// .. ipython:: python + /// :suppress: + /// + /// from rateslib import get_calendar + /// + /// .. ipython:: python + /// + /// print(get_calendar("nyc").print_compare(get_calendar("fed"), 2026)) + /// + #[pyo3(name = "print_compare")] + fn print_compare_py(&self, comparator: Calendar, year: i32) -> PyResult { + Ok(self.print_compare(&comparator, year)) + } + // Pickling fn __getnewargs__(&self) -> PyResult<(String,)> { Ok((self.name.clone(),)) diff --git a/rust/scheduling/py/convention.rs b/rust/scheduling/py/convention.rs index 04064409c..c4d0dc237 100644 --- a/rust/scheduling/py/convention.rs +++ b/rust/scheduling/py/convention.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::json::{DeserializedObj, JSON}; use crate::scheduling::{Adjuster, Calendar, Convention, Frequency, PyAdjuster}; use chrono::prelude::*; diff --git a/rust/scheduling/py/frequency.rs b/rust/scheduling/py/frequency.rs index 3b36225aa..6092d28ed 100644 --- a/rust/scheduling/py/frequency.rs +++ b/rust/scheduling/py/frequency.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::json::{DeserializedObj, JSON}; use crate::scheduling::calendars::Calendar; use crate::scheduling::frequency::{Frequency, RollDay, Scheduling}; @@ -151,6 +163,28 @@ impl Frequency { self.try_uregular(&ueffective, &utermination) } + /// Check whether two unadjusted dates define a regular unadjusted schedule. + /// + /// Parameters + /// ---------- + /// ueffective: datetime + /// The unadjusted effective date of the schedule. If this is not a valid unadjusted + /// date aligned with the Frequency then it will raise. + /// utermination: datetime + /// The unadjusted termination date of the frequency period. If this is not a valid + /// unadjusted date aligned with the Frequency then it will raise. + /// + /// Returns + /// ------- + /// bool + #[pyo3(name = "is_uregular")] + fn is_uregular_py(&self, ueffective: NaiveDateTime, utermination: NaiveDateTime) -> bool { + match self.try_uregular(&ueffective, &utermination) { + Err(_) => false, + Ok(_) => true, + } + } + /// Infer an unadjusted stub date from given schedule endpoints. /// /// Parameters diff --git a/rust/scheduling/py/imm.rs b/rust/scheduling/py/imm.rs index 090308a90..0b2027f16 100644 --- a/rust/scheduling/py/imm.rs +++ b/rust/scheduling/py/imm.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::json::{DeserializedObj, JSON}; use crate::scheduling::frequency::Imm; @@ -84,6 +96,7 @@ impl Imm { _ if item == Imm::Wed1_Post9_HMUZ as usize => Imm::Wed1_Post9_HMUZ, _ if item == Imm::Eom as usize => Imm::Eom, _ if item == Imm::Leap as usize => Imm::Leap, + _ if item == Imm::Som as usize => Imm::Som, _ => panic!("Reportable issue: must map this enum variant for serialization."), } } diff --git a/rust/scheduling/py/mod.rs b/rust/scheduling/py/mod.rs index caabae81f..3a2ce0807 100644 --- a/rust/scheduling/py/mod.rs +++ b/rust/scheduling/py/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + pub(crate) mod adjuster; pub(crate) use adjuster::PyAdjuster; pub(crate) mod calendar; diff --git a/rust/scheduling/py/rollday.rs b/rust/scheduling/py/rollday.rs index e5d1f6db6..ef4acf32d 100644 --- a/rust/scheduling/py/rollday.rs +++ b/rust/scheduling/py/rollday.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::json::{DeserializedObj, JSON}; use crate::scheduling::RollDay; use pyo3::exceptions::PyValueError; diff --git a/rust/scheduling/py/schedule.rs b/rust/scheduling/py/schedule.rs index 3e19e9b66..dd4503445 100644 --- a/rust/scheduling/py/schedule.rs +++ b/rust/scheduling/py/schedule.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::json::{DeserializedObj, JSON}; use crate::scheduling::{Calendar, Frequency, PyAdjuster, Schedule, StubInference}; @@ -15,6 +27,7 @@ impl StubInference { _ if item == StubInference::ShortBack as usize => StubInference::ShortBack, _ if item == StubInference::LongFront as usize => StubInference::LongFront, _ if item == StubInference::LongBack as usize => StubInference::LongBack, + _ if item == StubInference::NeitherSide as usize => StubInference::NeitherSide, _ => panic!("Reportable issue: must map this enum variant for serialization."), } } @@ -44,7 +57,7 @@ impl StubInference { #[pymethods] impl Schedule { #[new] - #[pyo3(signature = (effective, termination, frequency, calendar, accrual_adjuster, payment_adjuster, payment_adjuster2, eom, front_stub=None, back_stub=None, stub_inference=None, payment_adjuster3=None))] + #[pyo3(signature = (effective, termination, frequency, calendar, accrual_adjuster, payment_adjuster, payment_adjuster2, eom, stub_inference, front_stub=None, back_stub=None, payment_adjuster3=None))] fn new_py( effective: NaiveDateTime, termination: NaiveDateTime, @@ -54,9 +67,9 @@ impl Schedule { payment_adjuster: PyAdjuster, payment_adjuster2: PyAdjuster, eom: bool, + stub_inference: StubInference, front_stub: Option, back_stub: Option, - stub_inference: Option, payment_adjuster3: Option, ) -> PyResult { Schedule::try_new_inferred( @@ -182,9 +195,9 @@ impl Schedule { PyAdjuster, PyAdjuster, bool, + StubInference, Option, Option, - Option, Option, )> { Ok(( @@ -196,9 +209,9 @@ impl Schedule { self.payment_adjuster.into(), self.payment_adjuster2.into(), false, + StubInference::NeitherSide, self.ufront_stub, self.uback_stub, - None, self.payment_adjuster3.map(Into::into), )) } diff --git a/rust/scheduling/schedule.rs b/rust/scheduling/schedule.rs index 65af514d2..7c028489f 100644 --- a/rust/scheduling/schedule.rs +++ b/rust/scheduling/schedule.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::scheduling::{ get_unadjusteds, Adjuster, Adjustment, Calendar, Frequency, RollDay, Scheduling, }; @@ -8,7 +20,7 @@ use pyo3::{pyclass, PyErr}; use serde::{Deserialize, Serialize}; /// Specifier used by [`Schedule::try_new_inferred`] to instruct its inference logic. -#[pyclass(module = "rateslib.rs", eq, eq_int)] +#[pyclass(module = "rateslib.rs", eq, eq_int, from_py_object)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum StubInference { /// Short front stub inference. @@ -19,6 +31,8 @@ pub enum StubInference { ShortBack = 2, /// Long back stub inference. LongBack = 3, + /// Explicitly avoid any stub inference. + NeitherSide = 4, } /// A generic financial schedule with regular contiguous periods and, possibly, stubs. @@ -29,7 +43,7 @@ pub enum StubInference { /// - An **irregular** schedule has a ``ufront_stub`` and/or ``uback_stub`` dates defining periods /// at the boundary of the schedule which are not a standard length of time defined by the /// [`Frequency`]. However, a regular schedule must exist between those interior dates. -#[pyclass(module = "rateslib.rs", eq)] +#[pyclass(module = "rateslib.rs", eq, from_py_object)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(from = "ScheduleDataModel")] pub struct Schedule { @@ -362,7 +376,7 @@ impl Schedule { payment_adjuster: Adjuster, payment_adjuster2: Adjuster, payment_adjuster3: Option, - stub_inference: Option, + stub_inference: StubInference, ) -> Result { // evaluate if schedule is valid as defined without stub inference let temp_schedule = Schedule::try_new_defined( @@ -377,81 +391,121 @@ impl Schedule { payment_adjuster2, payment_adjuster3, ); - // validate inference is not blocked by user defined values. let _ = validate_stub_dates_and_inference(&ufront_stub, &uback_stub, &stub_inference)?; let stubs: (Option, Option); - if stub_inference.is_none() { - return temp_schedule; - } else { - let (interior_start, interior_end) = - match_interior_dates(&ueffective, &ufront_stub, &uback_stub, &utermination); - stubs = match stub_inference.unwrap() { - StubInference::ShortFront => { - if temp_schedule.is_ok() { - let test_schedule = temp_schedule.unwrap(); - if frequency.is_short_front_stub( + + let (interior_start, interior_end) = + match_interior_dates(&ueffective, &ufront_stub, &uback_stub, &utermination); + stubs = match stub_inference { + // for no inference simply return the initially generated schedule result. + StubInference::NeitherSide => return temp_schedule, + // when testing stub inference, a single period stub has a uschedule length of 2 and + // the stub can be evaluated in either direction: front or back. + StubInference::ShortFront => { + if temp_schedule.is_ok() { + let test_schedule = temp_schedule.unwrap(); + if frequency.is_short_front_stub( + &test_schedule.uschedule[0], + &test_schedule.uschedule[1], + ) || (test_schedule.uschedule.len() == 2 + && frequency.is_short_back_stub( &test_schedule.uschedule[0], &test_schedule.uschedule[1], - ) { - return Ok(test_schedule); - } // already has a short front stub - } - ( - frequency.try_infer_ufront_stub(&interior_start, &interior_end, true)?, - uback_stub, - ) + )) + { + return Ok(test_schedule); + } // already has a short front stub } - StubInference::LongFront => { - if temp_schedule.is_ok() { - let test_schedule = temp_schedule.unwrap(); - if frequency.is_long_front_stub( - &test_schedule.uschedule[0], - &test_schedule.uschedule[1], - ) { - return Ok(test_schedule); - } // already has a long front stub - } - ( - frequency.try_infer_ufront_stub(&interior_start, &interior_end, false)?, - uback_stub, - ) + let mut ufront_stub = + frequency.try_infer_ufront_stub(&interior_start, &interior_end, true)?; + // validate as dead stub + let valid_stub = validate_individual_dates( + &Some(ueffective), + &ufront_stub, + &accrual_adjuster, + &calendar, + ); + if valid_stub.is_err() { + // an error indicates a dead stub so convert to Long + ufront_stub = + frequency.try_infer_ufront_stub(&interior_start, &interior_end, false)?; } - StubInference::ShortBack => { - if temp_schedule.is_ok() { - let test_schedule = temp_schedule.unwrap(); - let n = test_schedule.uschedule.len(); - if frequency.is_short_back_stub( - &test_schedule.uschedule[n - 1], - &test_schedule.uschedule[n - 2], - ) { - return Ok(test_schedule); - } // already has a short back stub - } - ( - ufront_stub, - frequency.try_infer_uback_stub(&interior_start, &interior_end, true)?, - ) + (ufront_stub, uback_stub) + } + StubInference::LongFront => { + if temp_schedule.is_ok() { + let test_schedule = temp_schedule.unwrap(); + if frequency.is_long_front_stub( + &test_schedule.uschedule[0], + &test_schedule.uschedule[1], + ) || (test_schedule.uschedule.len() == 2 + && frequency + .is_back_stub(&test_schedule.uschedule[0], &test_schedule.uschedule[1])) + { + return Ok(test_schedule); + } // already has a long front stub } - StubInference::LongBack => { - if temp_schedule.is_ok() { - let test_schedule = temp_schedule.unwrap(); - let n = test_schedule.uschedule.len(); - if frequency.is_short_back_stub( + ( + frequency.try_infer_ufront_stub(&interior_start, &interior_end, false)?, + uback_stub, + ) + } + StubInference::ShortBack => { + if temp_schedule.is_ok() { + let test_schedule = temp_schedule.unwrap(); + let n = test_schedule.uschedule.len(); + if frequency.is_short_back_stub( + &test_schedule.uschedule[n - 2], + &test_schedule.uschedule[n - 1], + ) || (n == 2 + && frequency.is_short_front_stub( + &test_schedule.uschedule[n - 2], &test_schedule.uschedule[n - 1], + )) + { + return Ok(test_schedule); + } // already has a short back stub + } + let mut uback_stub = + frequency.try_infer_uback_stub(&interior_start, &interior_end, true)?; + // validate as dead stub + let valid_stub = validate_individual_dates( + &uback_stub, + &Some(utermination), + &accrual_adjuster, + &calendar, + ); + if valid_stub.is_err() { + // error indicates a dead stub so convert to Long + uback_stub = + frequency.try_infer_uback_stub(&interior_start, &interior_end, false)?; + } + (ufront_stub, uback_stub) + } + StubInference::LongBack => { + if temp_schedule.is_ok() { + let test_schedule = temp_schedule.unwrap(); + let n = test_schedule.uschedule.len(); + if frequency.is_short_back_stub( + &test_schedule.uschedule[n - 2], + &test_schedule.uschedule[n - 1], + ) || (n == 2 + && frequency.is_front_stub( &test_schedule.uschedule[n - 2], - ) { - return Ok(test_schedule); - } // already has a long back stub - } - ( - ufront_stub, - frequency.try_infer_uback_stub(&interior_start, &interior_end, false)?, - ) + &test_schedule.uschedule[n - 1], + )) + { + return Ok(test_schedule); + } // already has a long back stub } + ( + ufront_stub, + frequency.try_infer_uback_stub(&interior_start, &interior_end, false)?, + ) } - } + }; Self::try_new_defined( ueffective, utermination, @@ -487,7 +541,7 @@ impl Schedule { payment_adjuster2: Adjuster, payment_adjuster3: Option, eom: bool, - stub_inference: Option, + stub_inference: StubInference, ) -> Result { // evaluate the Options and get the start and end of regular schedule component let (regular_start, regular_end) = @@ -568,7 +622,7 @@ impl Schedule { payment_adjuster2: Adjuster, payment_adjuster3: Option, eom: bool, - stub_inference: Option, + stub_inference: StubInference, ) -> Result { // perform a preliminary check to determine if a given stub date actually falls under some // regular schedule. This is common when a list of bonds have 'first coupon' dates that @@ -739,24 +793,24 @@ fn match_interior_dates( fn validate_stub_dates_and_inference( ufront_stub: &Option, uback_stub: &Option, - stub_inference: &Option, + stub_inference: &StubInference, ) -> Result<(), PyErr> { match (ufront_stub, uback_stub, stub_inference) { - (Some(_v), Some(_w), Some(_f)) => Err(PyValueError::new_err( - "Cannot infer stubs if they are explicitly given.", - )), - (Some(_v), None, Some(val)) - if matches!(val, StubInference::ShortFront | StubInference::LongFront) => + (Some(_v), Some(_w), si) if !matches!(si, StubInference::NeitherSide) => Err( + PyValueError::new_err("Cannot infer any stubs if both are explicitly given."), + ), + (Some(_v), None, si) + if matches!(si, StubInference::ShortFront | StubInference::LongFront) => { Err(PyValueError::new_err( - "Cannot infer stubs if they are explicitly given.", + "Cannot infer front stub if it is explicitly given.", )) } - (None, Some(_w), Some(val)) - if matches!(val, StubInference::ShortBack | StubInference::LongBack) => + (None, Some(_w), si) + if matches!(si, StubInference::ShortBack | StubInference::LongBack) => { Err(PyValueError::new_err( - "Cannot infer stubs if they are explicitly given.", + "Cannot infer back stub if it is explicitly given.", )) } _ => Ok(()), @@ -827,7 +881,7 @@ fn filter_schedules_by_eom(uschedules: Vec, eom: bool) -> Schedule { #[cfg(test)] mod tests { use super::*; - use crate::scheduling::{ndt, Cal, RollDay}; + use crate::scheduling::{ndt, Cal, NamedCal, RollDay}; #[test] fn test_new_uschedule_defined_cases_1_and_2() { @@ -1295,7 +1349,7 @@ mod tests { Adjuster::Following {}, None, true, - None, + StubInference::NeitherSide, ) .unwrap(); assert_eq!( @@ -1321,7 +1375,7 @@ mod tests { Adjuster::Following {}, None, false, - None, + StubInference::NeitherSide, ) .unwrap(); assert_eq!( @@ -1347,7 +1401,7 @@ mod tests { Adjuster::Following {}, None, true, - None, + StubInference::NeitherSide, ) .unwrap(); assert_eq!( @@ -1375,7 +1429,7 @@ mod tests { Adjuster::BusDaysLagSettle(1), Adjuster::Following {}, None, - Some(StubInference::ShortBack) + StubInference::ShortBack, ) .is_err() ); @@ -1394,7 +1448,7 @@ mod tests { Adjuster::BusDaysLagSettle(1), Adjuster::Following {}, None, - Some(StubInference::ShortBack) + StubInference::ShortBack, ) .is_err() ); @@ -1413,7 +1467,7 @@ mod tests { Adjuster::BusDaysLagSettle(1), Adjuster::Following {}, None, - Some(StubInference::LongBack) + StubInference::LongBack, ) .is_err() ); @@ -1432,7 +1486,7 @@ mod tests { Adjuster::BusDaysLagSettle(1), Adjuster::Following {}, None, - Some(StubInference::ShortFront) + StubInference::ShortFront, ) .is_err() ); @@ -1451,7 +1505,7 @@ mod tests { Adjuster::BusDaysLagSettle(1), Adjuster::Following {}, None, - Some(StubInference::LongFront) + StubInference::LongFront, ) .is_err() ); @@ -1475,7 +1529,7 @@ mod tests { Adjuster::Following {}, None, true, - Some(StubInference::ShortFront), + StubInference::ShortFront, ) .expect("short period"); assert_eq!(s.uschedule, vec![ndt(2022, 7, 1), ndt(2022, 10, 1)]); @@ -1499,7 +1553,7 @@ mod tests { Adjuster::Following {}, None, true, - None, + StubInference::NeitherSide, ) .expect("short period"); assert_eq!( @@ -1528,7 +1582,7 @@ mod tests { Adjuster::Following {}, None, true, - None, + StubInference::NeitherSide, ) .expect("regular"); assert!(s.is_regular()); @@ -1548,7 +1602,7 @@ mod tests { Adjuster::Following {}, None, true, - Some(StubInference::ShortBack), + StubInference::ShortBack, ) .expect("regular"); assert!(!s.is_regular()); @@ -1571,7 +1625,7 @@ mod tests { Adjuster::Following {}, None, false, - Some(StubInference::ShortFront), + StubInference::ShortFront, ) .expect("schedule is valid"); assert_eq!( @@ -1597,7 +1651,7 @@ mod tests { Adjuster::Following {}, None, false, - Some(StubInference::ShortFront), + StubInference::ShortFront, ) .expect("schedule is valid"); assert_eq!( @@ -1610,4 +1664,317 @@ mod tests { ] ); } + + #[test] + fn test_cny7d_bug() { + // this bug appeared in the course of building CNY swaps. + let f = Frequency::CalDays { + // frequency + number: 7, + }; + let s = Schedule::try_new_infer_stub( + ndt(2028, 11, 4), // ueffective + ndt(2029, 2, 4), // utermination + f, // frequency + None, // ufront_stub + None, // uback_stub + Calendar::NamedCal(NamedCal::try_new("bjs").unwrap()), // calendar + Adjuster::Following {}, // accrual_adjuster + Adjuster::BusDaysLagSettle(0), // payment_adjuster + Adjuster::Following {}, // payment_adjuster2 + None, // payment_adjuster3 + StubInference::ShortBack, // stub_inference + ); + + assert!(s.is_ok()); + } + + // The follow tests explore dead stubs + #[test] + fn test_7day_defined_errors() { + // this is identified as a single period long stub because it is shorter than 2 periods. + let s = Schedule::try_new_defined( + ndt(2026, 1, 3), // saturday + ndt(2026, 1, 11), // sunday + Frequency::CalDays { number: 7 }, + None, + None, + Calendar::Cal(Cal::new(vec![], vec![5, 6])), + Adjuster::Following {}, + Adjuster::BusDaysLagSettle(0), + Adjuster::Following {}, + None, + ) + .unwrap(); + assert_eq!(s.uschedule, vec![ndt(2026, 1, 3), ndt(2026, 1, 11)]); + assert_eq!(s.aschedule, vec![ndt(2026, 1, 5), ndt(2026, 1, 12)]); + + // this must fail because stubs are not specified and this is not a regular + // schedule and is longer than 2 periods. + let s = Schedule::try_new_defined( + ndt(2026, 1, 3), // saturday + ndt(2026, 1, 18), // sunday + Frequency::CalDays { number: 7 }, + None, + None, + Calendar::Cal(Cal::new(vec![], vec![5, 6])), + Adjuster::Following {}, + Adjuster::BusDaysLagSettle(0), + Adjuster::Following {}, + None, + ); + assert!(s.is_err()); + } + + #[test] + fn test_7day_frequency_can_infer_short_stubs() { + // a 7D frequency can properly infer these unadjusted front stub dates, even though + // they will prove to be dead stub dates when compared with the wider schedules of + // later tests. + let result = Frequency::CalDays { number: 7 }.try_infer_uback_stub( + &ndt(2026, 1, 3), + &ndt(2026, 1, 11), + true, + ); + assert!(result.is_ok()); + assert_eq!(ndt(2026, 1, 10), result.unwrap().unwrap()); + + let result = Frequency::CalDays { number: 7 }.try_infer_ufront_stub( + &ndt(2026, 1, 3), + &ndt(2026, 1, 11), + true, + ); + assert!(result.is_ok()); + assert_eq!(ndt(2026, 1, 4), result.unwrap().unwrap()); + } + + #[test] + fn test_7day_dead_stubs_error() { + // these schedules are defined by dead stubs. They cannot produce valid schedules + // when entered as defined. + let s = Schedule::try_new_defined( + ndt(2026, 1, 3), // saturday + ndt(2026, 1, 11), // sunday + Frequency::CalDays { number: 7 }, + Some(ndt(2026, 1, 4)), + None, + Calendar::Cal(Cal::new(vec![], vec![5, 6])), + Adjuster::Following {}, + Adjuster::BusDaysLagSettle(0), + Adjuster::Following {}, + None, + ); + assert!(s.is_err()); + let s = Schedule::try_new_defined( + ndt(2026, 1, 3), // saturday + ndt(2026, 1, 11), // sunday + Frequency::CalDays { number: 7 }, + None, + Some(ndt(2026, 1, 10)), + Calendar::Cal(Cal::new(vec![], vec![5, 6])), + Adjuster::Following {}, + Adjuster::BusDaysLagSettle(0), + Adjuster::Following {}, + None, + ); + assert!(s.is_err()); + } + + #[test] + fn test_7day_infer_long_inference() { + // all of these schedules should be able to derive valid results with inference. + // because the period is long (longer than holiday blocks) it should not produce a dead stub + // 1st Jan 2028 is a Saturday + let options: Vec<(StubInference, NaiveDateTime, Vec)> = vec![ + ( + StubInference::LongFront, + ndt(2028, 1, 9), + vec![ndt(2028, 1, 1), ndt(2028, 1, 9)], + ), + ( + StubInference::LongFront, + ndt(2028, 1, 16), + vec![ndt(2028, 1, 1), ndt(2028, 1, 9), ndt(2028, 1, 16)], + ), + ( + StubInference::LongFront, + ndt(2028, 1, 23), + vec![ + ndt(2028, 1, 1), + ndt(2028, 1, 9), + ndt(2028, 1, 16), + ndt(2028, 1, 23), + ], + ), + ( + StubInference::LongBack, + ndt(2028, 1, 9), + vec![ndt(2028, 1, 1), ndt(2028, 1, 9)], + ), + ( + StubInference::LongBack, + ndt(2028, 1, 16), + vec![ndt(2028, 1, 1), ndt(2028, 1, 8), ndt(2028, 1, 16)], + ), + ( + StubInference::LongBack, + ndt(2028, 1, 23), + vec![ + ndt(2028, 1, 1), + ndt(2028, 1, 8), + ndt(2028, 1, 15), + ndt(2028, 1, 23), + ], + ), + ]; + + for option in options { + let s = Schedule::try_new_infer_stub( + ndt(2028, 1, 1), // saturday + option.1, // sunday + Frequency::CalDays { number: 7 }, + None, + None, + Calendar::Cal(Cal::new(vec![], vec![5, 6])), + Adjuster::Following {}, + Adjuster::BusDaysLagSettle(0), + Adjuster::Following {}, + None, + option.0, + ) + .unwrap(); + assert_eq!(s.uschedule, option.2); + } + } + + #[test] + fn test_7day_infer_short_inference_converting_dead_stub_to_long() { + // all of these schedules should be able to derive valid results with inference. + // the short stubs initially derived are detected as dead and then converted to long + // 1st Jan 2028 is a Saturday + let options: Vec<(StubInference, NaiveDateTime, Vec)> = vec![ + ( + StubInference::ShortFront, + ndt(2028, 1, 9), + vec![ndt(2028, 1, 1), ndt(2028, 1, 9)], + ), + ( + StubInference::ShortFront, + ndt(2028, 1, 16), + vec![ndt(2028, 1, 1), ndt(2028, 1, 9), ndt(2028, 1, 16)], + ), + ( + StubInference::ShortFront, + ndt(2028, 1, 23), + vec![ + ndt(2028, 1, 1), + ndt(2028, 1, 9), + ndt(2028, 1, 16), + ndt(2028, 1, 23), + ], + ), + ( + StubInference::ShortBack, + ndt(2028, 1, 9), + vec![ndt(2028, 1, 1), ndt(2028, 1, 9)], + ), + ( + StubInference::ShortBack, + ndt(2028, 1, 16), + vec![ndt(2028, 1, 1), ndt(2028, 1, 8), ndt(2028, 1, 16)], + ), + ( + StubInference::ShortBack, + ndt(2028, 1, 23), + vec![ + ndt(2028, 1, 1), + ndt(2028, 1, 8), + ndt(2028, 1, 15), + ndt(2028, 1, 23), + ], + ), + ]; + + for option in options { + let s = Schedule::try_new_infer_stub( + ndt(2028, 1, 1), // saturday + option.1, // sunday + Frequency::CalDays { number: 7 }, + None, + None, + Calendar::Cal(Cal::new(vec![], vec![5, 6])), + Adjuster::Following {}, + Adjuster::BusDaysLagSettle(0), + Adjuster::Following {}, + None, + option.0, + ) + .unwrap(); + assert_eq!(s.uschedule, option.2); + } + } + + #[test] + fn test_bug_developing_neither_side_stub_inference() { + let s = Schedule::try_new_inferred( + ndt(2022, 1, 3), + ndt(2023, 1, 3), + Frequency::Months { + number: 3, + roll: None, + }, + Some(ndt(2022, 2, 10)), + Some(ndt(2022, 8, 10)), + Calendar::Cal(Cal::new(vec![], vec![5, 6])), + Adjuster::ModifiedFollowing {}, + Adjuster::BusDaysLagSettle(2), + Adjuster::Following {}, + None, + false, + StubInference::NeitherSide, + ) + .unwrap(); + assert_eq!( + s.uschedule, + vec![ + ndt(2022, 1, 3), + ndt(2022, 2, 10), + ndt(2022, 5, 10), + ndt(2022, 8, 10), + ndt(2023, 1, 3), + ] + ); + } + + #[test] + fn test_return_single_period_even_with_stub_inference() { + let options = vec![ + StubInference::ShortFront, + StubInference::LongFront, + StubInference::ShortBack, + StubInference::LongBack, + StubInference::NeitherSide, + ]; + for option in options { + let s = Schedule::try_new_inferred( + ndt(2000, 1, 1), + ndt(2000, 2, 15), + Frequency::Months { + number: 3, + roll: Some(RollDay::Day(1)), + }, + None, + None, + Calendar::Cal(Cal::new(vec![], vec![5, 6])), + Adjuster::ModifiedFollowing {}, + Adjuster::BusDaysLagSettle(2), + Adjuster::Following {}, + None, + false, + option, + ) + .unwrap(); + assert_eq!(s.uschedule, vec![ndt(2000, 1, 1), ndt(2000, 2, 15),]); + } + } } diff --git a/rust/scheduling/serde.rs b/rust/scheduling/serde.rs index ee99f78cb..126e84ccf 100644 --- a/rust/scheduling/serde.rs +++ b/rust/scheduling/serde.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::json::JSON; use crate::scheduling::{Cal, Calendar, Convention, NamedCal, StubInference, UnionCal}; diff --git a/rust/splines/mod.rs b/rust/splines/mod.rs index 85675e41a..7eac82333 100644 --- a/rust/splines/mod.rs +++ b/rust/splines/mod.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Toolset to create one dimensional spline curves. mod spline; diff --git a/rust/splines/spline.rs b/rust/splines/spline.rs index 9abdbc32b..8b614728f 100644 --- a/rust/splines/spline.rs +++ b/rust/splines/spline.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::linalg::{dmul11_, fdmul11_, fdsolve, fouter11_}; use crate::dual::{Dual, Dual2, Gradient1, Gradient2, Number, NumberMapping}; use ndarray::{Array1, Array2}; @@ -400,21 +412,21 @@ where } /// Definitive [f64] type variant of a [PPSpline]. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Deserialize, Serialize)] pub struct PPSplineF64 { pub(crate) inner: PPSpline, } /// Definitive [Dual] type variant of a [PPSpline]. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Deserialize, Serialize)] pub struct PPSplineDual { pub(crate) inner: PPSpline, } /// Definitive [Dual2] type variant of a [PPSpline]. -#[pyclass(module = "rateslib.rs")] +#[pyclass(module = "rateslib.rs", from_py_object)] #[derive(Clone, Deserialize, Serialize)] pub struct PPSplineDual2 { pub(crate) inner: PPSpline, diff --git a/rust/splines/spline_py.rs b/rust/splines/spline_py.rs index e4adb4bf1..f67b44689 100644 --- a/rust/splines/spline_py.rs +++ b/rust/splines/spline_py.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + //! Wrapper to export spline functionality to Python use crate::dual::{Dual, Dual2, Number}; diff --git a/rust/tests/dual1.rs b/rust/tests/dual1.rs index 4f7a57d52..74bd5eb44 100644 --- a/rust/tests/dual1.rs +++ b/rust/tests/dual1.rs @@ -1,3 +1,15 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + use crate::dual::Dual; use std::sync::Arc; diff --git a/rust/tests/mod.rs b/rust/tests/mod.rs index 095e5dd44..1ee5cf09f 100644 --- a/rust/tests/mod.rs +++ b/rust/tests/mod.rs @@ -1,2 +1,14 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// + // mod dual1; // mod splines; diff --git a/rust/tests/splines/mod.rs b/rust/tests/splines/mod.rs index 5a91b8496..7c89312e4 100644 --- a/rust/tests/splines/mod.rs +++ b/rust/tests/splines/mod.rs @@ -1,3 +1,14 @@ +// SPDX-License-Identifier: LicenseRef-Rateslib-Dual +// +// Copyright (c) 2026 Siffrorna Technology Limited +// This code cannot be used or copied externally +// +// Dual-licensed: Free Educational Licence or Paid Commercial Licence (commercial/professional use) +// Source-available, not open source. +// +// See LICENSE and https://rateslib.com/py/en/latest/i_licence.html for details, +// and/or contact info (at) rateslib (dot) com +//////////////////////////////////////////////////////////////////////////////////////////////////// use crate::splines::{PPSpline, bspldnev_single_f64, bsplev_single_dual, bsplev_single_f64}; use crate::dual::{Dual, Gradient1};