{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "![](../../images/rivacon_frontmark_combined_header.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Day Counter, Roll Conventions and Schedules" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Grandparent directory containing Rivapy module added to sys.path: c:\\Users\\DrHansNguyen\\Documents\n" ] } ], "source": [ "import os, sys, holidays\n", "from datetime import date, timedelta, datetime\n", "from dateutil.relativedelta import relativedelta\n", "\n", "# Get the current working directory\n", "current_dir = os.getcwd()\n", "\n", "# Get the grandparent directory\n", "grandparent_dir = os.path.abspath(os.path.join(current_dir, \"..\", \"..\"))\n", "\n", "# Add the grandparent directory to sys.path\n", "if grandparent_dir not in sys.path:\n", " sys.path.insert(0, grandparent_dir)\n", "\n", "print(\"Grandparent directory containing Rivapy module added to sys.path:\", grandparent_dir)\n", "from rivapy.tools.enums import RollConvention\n", "from rivapy.tools.datetools import Period, Schedule, roll_day" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Basics\n", "For financial instrument valuation some basic ingredients are needed that are easily neglected when looking at the overall valuation concepts, instrument types, and models. When being precise one has to properly deal with dates at which e.g. payments are due, periods such as accrual periods start and end, etc. Here we briefly introduce \n", "- calenders\n", "- business day conventions\n", "- roll conventions\n", "- schedules, and \n", "- day count conventions.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Holiday calendar\n", "Holiday calenders are at the heart of any financial library. They are used to determine whether a specific date corresponds to a bank holiday. Which calendar to use depends on the context in which the date is used. For financial instruments it is usually the instrument's settlement systen, the papying agent's system, or the clearing house that governs the applicable calender. Across the EUR-zone the relevant calendar is often the TARGET2 calender. \n", "\n", "RIVAPY uses the Python library [holidays](https://holidays.readthedocs.io/en/latest/) as a Holiday calendar for determining business days.\n", "The following example uses the holiday calendar of the Euopean Central Bank below (i.e. TARGET2)." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2024-01-01 New Year's Day\n", "2024-03-29 Good Friday\n", "2024-04-01 Easter Monday\n", "2024-05-01 Labour Day\n", "2024-12-25 Christmas Day\n", "2024-12-26 Christmas Holiday\n", "False\n", "2024-01-01 New Year's Day\n", "2024-03-29 Good Friday\n", "2024-04-01 Easter Monday\n", "2024-05-01 Labour Day\n", "2024-12-25 Christmas Day\n", "2024-12-26 Christmas Holiday\n", "2023-01-01 New Year's Day\n", "2023-04-07 Good Friday\n", "2023-04-10 Easter Monday\n", "2023-05-01 Labour Day\n", "2023-12-25 Christmas Day\n", "2023-12-26 Christmas Holiday\n" ] } ], "source": [ "ecb_holidays = holidays.ECB(2024) # Optionally a year or a list of years can be provided. \n", " # By default the years are automatically extended when needed, see below.\n", "\n", "for d,n in ecb_holidays.items():\n", " print(d,n)\n", " \n", "print(ecb_holidays.is_working_day(\"2023-1-1\")) # This can be used to check for working day (holidays and weekends considered) \n", " # and adds 2023 to ecb_holidays\n", "\n", "for d,n in ecb_holidays.items():\n", " print(d,n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Date Rolling: Business day conventions and Roll Conventions\n", "\n", "Dealing with financial instruments and payment unambiguous information is required on how to 'roll' dates that fall on a bank holiday or that need to be moved to the start date of a subsequent or previous period when building schedules for a given start or end date. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "#### Business Day Conventions\n", "Business day conventions (bdc) determine how dates are adjusted if they fall on non-business days (e.g., weekends or holidays). These conventions are essential in determining the exact timing of payments or other financial events. Common business day conventions include:\n", "\n", "1. **Unadjusted** \n", " The date is not adjusted, even if it falls on a non-business day.\n", " \n", "2. **Following** \n", " If the date falls on a non-business day, it is rolled forward to the next business day.\n", "\n", "3. **Modified Following** \n", " Similar to Following, but if rolling forward moves the date to the next month, it is rolled backward to the preceding business day.\n", "\n", "4. **Preceding** \n", " If the date falls on a non-business day, it is rolled backward to the previous business day.\n", "\n", "5. **Modified Preceding** \n", " Similar to Preceding, but if rolling backward moves the date to the previous month, it is rolled forward to the next business day." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "# Example of selecting a business day convention in rivapy\n", "business_day_convention = [\n", " RollConvention.UNADJUSTED,\n", " RollConvention.FOLLOWING,\n", " RollConvention.MODIFIED_FOLLOWING,\n", " RollConvention.PRECEDING,\n", " RollConvention.MODIFIED_PRECEDING,\n", " ]" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2021-01-01 \t UNADJUSTED\n", "2021-01-04 \t FOLLOWING\n", "2021-01-04 \t MODIFIED_FOLLOWING\n", "2020-12-31 \t PRECEDING\n", "2021-01-04 \t MODIFIED_PRECEDING\n" ] } ], "source": [ "# 01.01.2021 is a friday, notice how MODIFIED_PRECEDING is the following business day\n", "for bdc in business_day_convention:\n", " rolled_day = roll_day(day = date(2021,1,1),\n", " calendar = holidays.ECB(),\n", " business_day_convention = bdc,\n", " start_day = None,\n", " settle_days = 0)\n", " print(rolled_day.date(), \"\\t \", bdc.name)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Roll Conventions\n", "Roll Conventions (aka 'roll rules') govern the rolling forward (or backward) of dates when building schedules for financial instruments. Common roll rules include\n", "1. **End-of-Month (EOF)**\n", " Rolls to the last calender day of a month, adjusting for shorter month. E.g. if the start date is March 15 and frequency is set to monthly then future dates are April 15, May 15, etc.\n", "\n", "2. **Day-of-Month (DOF)**\n", " Rolls to the same calender day each period. E. g. if the start date is Jan 31 and frequency is set to monthly then next dates are Feb 28 (or Feb 29 in leap years), March 31, etc.\n", "\n", "3. **IMM Dates**\n", " Rolls to the 3rd Wednesday of March, June, Sept, dec (used in futures/swaps). \n", "\n", "Other roll rules may be defined by individual contracts, e.g. rules that link dates to a specific day of the week (\"the first Monday of each month in year 2020\")." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Schedules\n", "For different financial instruments such as bonds or swaps a vector for certain dates is needed. These vectors are usually called schedules. They may describe the dates where certain payments or other events (such as fixings) occur. Such schedules are normally based on some construction logic. The generation of schedules is therefore often governed by algorithms, which are called schedule generators. To create such a schedule with a generator, we have three main ingredients:\n", "- A holiday calendar since most often schedules contain only business days,\n", "- Periods describing the frequency of the dates such as monthly, yearly, quarterly etc.,\n", "- a role convention that may adjust period end or start dates,\n", "- a business day convention which defines what happens if the algorithm ends at a holiday." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Periods\n", "A period is described by the number of years/months/days and is the basis in the schedule generation." ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "ExecuteTime": { "end_time": "2020-05-01T08:57:52.770352Z", "start_time": "2020-05-01T08:57:52.746427Z" } }, "outputs": [], "source": [ "period_1yr = Period(1,0,0) # create a period of 1 year (first argument of this method describes years, second month and last days)\n", "period_3m = Period(0,3,0)\n", "period_30days = Period(0,0,30)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Schedule generation\n", "To create a schedule we first have to create a specification containing the information described above (holidays, periods, roll rules, business day conventions). We may then call the generate method to create a list of dates defining the schedule.\n", "\n", "**Additional Options:**\n", "\n", "- **`backwards`** *(bool, optional)*: \n", " Defines the direction for rolling out the schedule. \n", " - **True**: The schedule will be rolled out *backwards* (from the end day to the start day).\n", " - **False**: The schedule will be rolled out *forwards* (from the start day to the end day). \n", " - Defaults to **True**.\n", "\n", "- **`stub`** *(bool, optional)*: \n", " Defines the behavior for the first/last period when it is shorter than the others. \n", " - **True**: The first/last period is accepted even if it is shorter. \n", " - **False**: The remaining days of the shorter period are added to the neighboring period. \n", " - Defaults to **True**." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Unadjusted:\n", "2024-01-01\n", "2024-04-01\n", "2024-07-01\n", "2024-10-01\n", "2025-01-01\n", "\n", "Adjusted for Working Day:\n", "2024-01-02\n", "2024-04-02\n", "2024-07-01\n", "2024-10-01\n", "2025-01-02\n" ] } ], "source": [ "#no business day adjustments\n", "unadjusted_schedule = Schedule._roll_out(from_=date(2024,1,1), to_=date(2025,1,1), term=period_3m, backwards=False,\n", " long_stub=False)\n", "# Show undajusted schedule\n", "print(\"Unadjusted:\")\n", "for s in unadjusted_schedule: \n", " print(s.date())\n", "print()\n", "\n", "# adjust for business days (holidays and weekends)\n", "schedule_2024_3m_period = Schedule(start_day = date(2024,1,1),\n", " end_day = date(2025,1,1),\n", " time_period = period_3m,\n", " backwards = False,\n", " business_day_convention = RollConvention.MODIFIED_FOLLOWING,\n", " calendar = holidays.ECB())\n", "adjusted_schedule = schedule_2024_3m_period.generate_dates(ends_only=False)\n", "print(\"Adjusted for Working Day:\")\n", "for s in adjusted_schedule: \n", " print(s.date())\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Day Count Conventions\n", "Let's imagine we have a financial product (e.g. Bond) which pays us interest of 5% p.a. each month over a year. Additionally let's ignore business days and assume we receive a coupon every month with the schedule being 01.01.2025, 01.02.2025, ..., 01.01.2026. Without further information, it is not clear how the coupon (as a year fraction of 5% times Nominal) is calculated for each monthly period:\n", "- Should the the coupon for the first period in January (01.01.2025 - 01.02.2025, 31 days) be the same as for the second period in February (01.02.2025 - 01.03.2025, 28 days)?\n", "- Are the period start days e.g. 01.01.2025 or the period end days e.g. 01.01.2026 included or excluded in the calculation?\n", " \n", "**Day Count Conventions** (or Date Conventions, Day Count Fractions) give answers to these questions by defining how the time between two dates is measured for financial calculations. They determine how interest accrues between dates. An official source on day count conventions as well as other market conventions can be found [here](../../images/2006-isda-definitions.pdf). For an overview you can check out [this](../../images/Interest-Rate-Instruments-and-Market-Conventions.pdf).\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Actual/Actual (ISDA)\n", "\n", "This Day Count Convention counts the actual days between period start and period end date divided by the actual number of days in the year (365 or 366 in a leap year). If the period spans over a leap year and a normal year, the days are splitted and the year fraction is computed as: \n", "\n", "$$ \\frac{Days\\; in\\; non leap\\; year}{365} + \\frac{Days\\; in\\; leap\\; year}{366}$$\n", "\n", "The **first day** in the period is **included**, the **last day is excluded**.\n", "\n", "Actual/Actual (ISDA) is primarily used in derivatives markets and swaps." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.16963096040122763\n", "0.16963096040122763\n" ] } ], "source": [ "from rivapy.tools.datetools import DayCounter as dc\n", "# Here you see an example using rivapy\n", "# The period contains 31 days in the leap year 2024 and 31 days in the nonleap year 2025\n", "print(dc(\"ActAct\").yf(date(2024,12,1), date(2025,2,1))) #last day is excluded\n", "print(31/366+31/365) # Should be the same result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Actual/365 (Fixed)\n", "\n", "This can be seen as a simplification of the Actual/Actual (ISDA) Convention, where the denominator is always 365.\n", "\n", "#### Actual/360\n", "\n", "Same as the Convention above, but the denominator is always 360.\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Days in period: 366\n", "Act365Fixed:\t 1.0027397260273974\n", "Act360:\t\t 1.0166666666666666\n" ] } ], "source": [ "d1 = date(2024,1,1)\n", "d2 = date(2025,1,1)\n", "print(\"Days in period:\",(d2 - d1).days)\n", "\n", "print(\"Act365Fixed:\\t\",dc(\"Act365Fixed\").yf(d1, d2)) # equal to 366/365\n", "print(\"Act360:\\t\\t\",dc(\"Act360\").yf(d1, d2)) # equal to 366/360" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### ACT/ACT (ICMA)\n", "\n", "This Day Count Convention is commonly used in bond markets to calculate the day count fraction, particularly for determining accrued interest and bond yields. It provides a standardized way to calculate the fraction of a year represented by a given period, based on actual calendar days and the bond's coupon schedule.\n", "\n", "$$\n", "\\text{Day Count Fraction} = \\sum_{c\\in \\text{C}}\\frac{\\mathbb{I}\\left(d_1 \\leq c_{\\text{end}} \\land d_2 \\geq c_{\\text{start}}\\right)\\cdot\\text{days}\\left(\\min(d_2, c_{\\text{end}})-\\max(d_1, c_{\\text{start}})\\right)}{\\text{days}\\left(d_2 - d_1\\right)\\cdot f_\\text{Coupon}}\n", "$$\n", "\n", "Where:\n", "- **$C$**: is the sorted set of coupon payment dates.\n", "- **$c_{\\text{start}}$**: is the start date of the coupon period.\n", "- **$c_{\\text{end}}$**: is the end date of the coupon period.\n", "- **$\\mathbb{I}\\left(\\dots\\right)$**: is an indicator function is returns 1 if the expression inside renders true, otherwise it returns 0.\n", "- **$\\text{days}(\\dots)$**: returns the actual days between to dates.\n", "- **$f_\\text{Coupon}$**: annual coupon frequency (1 for annualy coupon payment, 2 for semi annual etc.)\n", "\n", "The **first day** in the period is **included**, the **last day is excluded**.\n", "\n", "**Example**:\n", "Semi-annual bond with last coupon on\n", "1st May, next coupon on 1 November (number of days: 184). On 31st May, the year franction is calculated as:\n", "$$\\frac{30}{184 \\times 2} = \\frac{30}{368}$$" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.08152173913043478\n", "0.08152173913043478\n" ] } ], "source": [ "# ACT/ACT ICMA is used for bonds and requires additional arguments for coupon payment dates and frequency \n", "coupon_schedule = [date(2024, 5, 1), date(2024, 11, 1)]\n", "print(dc.yf_ActActICMA(date(2024,5,1), date(2024,5,31), coupon_schedule=coupon_schedule, coupon_frequency=2))\n", "print(30/368) # Should be the same result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 30/360 (ISDA) or \"Bond Basis\"\n", "\n", "This convention assumes that each month has 30 days and that the year has 360 days. \n", "The formula is therefore given by:\n", "\n", "$$\n", "\\frac{360 (Y_{2} - Y_{1}) + 30(M_{2}-M_{1}) + D_{2}-D_{1}}{360}\n", "$$ \n", "\n", "where \n", "- $Y_{1}$ is the year of the period start date.\n", "- $Y_{2}$ is the year of the period end date (day immeadiately following last day included).\n", "- $M_{1}$ is the month (expressed as a number) of the period start date.\n", "- $M_{2}$ is the month (expressed as a number) of the period end date (day immeadiately following last day included).\n", "- $D_{1}$ is the calendar day (expressed as a number) of the period start date, unless this number is 31, in which case $D_{1}$ is set to 30.\n", "- $D_{2}$ is the calendar day (expressed as a number) of the period end date (day immeadiately following last day included), unless this number is 31 and $D_{1}>29$, in which case $D_{2}$ is set to 30.\n", " \n" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.08333333333333333\n", "0.08333333333333337\n", "0.08611111111111111\n", "0.08333333333333333\n" ] } ], "source": [ "# in this example we have 31 included days, because the period end date is excluded\n", "print(dc.yf_30360ISDA(date(2025,1,1), date(2025,2,1)))\n", "# Y1=Y2=2025, M1=1, M2=2, D1=D2=1 \n", "# the result should be 30/360=1/12=0,083333...\n", "\n", "# now we move the period one day back (still 31 included days)\n", "print(dc.yf_30360ISDA(date(2024,12,31), date(2025,1,31)))\n", "# Y1=2024, Y2=2025, M1=12, M2=1, D1=D2=30 \n", "# the result should be (360+30*(-11))/360=1/12=0,083333...\n", "# and same as picking one or both of the calendar days to 30th e.g. date(2024,12,30) and date(2025,1,31)\n", "\n", "# we pick a period where D1 and D2 is not adjusted (still 31 included days)\n", "print(dc.yf_30360ISDA(date(2025,4,29), date(2025,5,30)))\n", "# Y1=Y2=2025, M1=4, M2=5, D1=29, D2=30 \n", "# the result should be (30+1)/360=0,08611111...\n", "\n", "# moving the period one day forward changes D1 but not D2 (still 31 included days)\n", "print(dc.yf_30360ISDA(date(2025,4,30), date(2025,5,31)))\n", "# Y1=Y2=2025, M1=4, M2=5, D1=30, D2=30 (because D1>29)\n", "# the result should be 30/360=1/12=0,083333..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 30E/360 or \"Eurobond Basis\"\n", "\n", "This convention follows the same formula as the previous 30/360 (ISDA) convention, but has a simpler adjustment to $D_{2}$:\n", "\n", "$$\n", "\\frac{360 (Y_{2} - Y_{1}) + 30(M_{2}-M_{1}) + D_{2}-D_{1}}{360}\n", "$$ \n", "\n", "where \n", "- $Y_{1}$ is the year of the period start date.\n", "- $Y_{2}$ is the year of the period end date (day immeadiately following last day included).\n", "- $M_{1}$ is the month (expressed as a number) of the period start date.\n", "- $M_{2}$ is the month (expressed as a number) of the period end date (day immeadiately following last day included).\n", "- $D_{1}$ is the calendar day (expressed as a number) of the period start date, unless this number is 31, in which case $D_{1}$ is set to 30.\n", "- $D_{2}$ is the calendar day (expressed as a number) of the period end date (day immeadiately following last day included), **unless this number is 31, in which case $D_{2}$ is set to 30**.\n", " \n" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.08333333333333337\n", "0.08333333333333337\n", "0.08333333333333337\n", "0.08333333333333337\n" ] } ], "source": [ "# all of the examples below have the same result\n", "print(dc.yf_30E360(date(2024,12,31), date(2025,1,31)))\n", "print(dc.yf_30E360(date(2024,12,31), date(2025,1,30)))\n", "print(dc.yf_30E360(date(2024,12,30), date(2025,1,31)))\n", "print(dc.yf_30E360(date(2024,12,30), date(2025,1,30)))\n", "# Y1=2024, Y2=2025, M1=12, M2=1, D1=D2=30 \n", "# the result should be (360+30*(-11))/360=1/12=0,083333..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 30U/360 or 30/360 US\n", "\n", "This convention is also known as the 30/360 U.S. Treasury method and is an extension the 30/360 (ISDA) convention. The only difference is the handling of the last day in february:\n", "\n", "$$\n", "\\frac{360 (Y_{2} - Y_{1}) + 30(M_{2}-M_{1}) + D_{2}-D_{1}}{360}\n", "$$ \n", "\n", "where \n", "- $Y_{1}$ is the year of the period start date.\n", "- $Y_{2}$ is the year of the period end date (day immeadiately following last day included).\n", "- $M_{1}$ is the month (expressed as a number) of the period start date.\n", "- $M_{2}$ is the month (expressed as a number) of the period end date (day immeadiately following last day included).\n", "- $D_{1}$ is the calendar day (expressed as a number) of the period start date, unless:\n", " - if $D_{1}=31$, set $D_{1}=30$.\n", " - **if $D_{1}$ is the last day of february** ($M_{1}=2$, $D_{1}=29$ in leap years or $D_{1}=28$ in nonleap years), **set $D_{1}=30$**\n", "- $D_{2}$ is the calendar day (expressed as a number) of the period end date (day immeadiately following last day included), unless:\n", " - if $D_{2}=31$ and $D_{1}>29$, set $D_{2}=30$.\n", " - **if $D_{1}$ and $D_{2}$ are the last days of february, set $D_{2}=30$**.\n", " " ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.0\n", "1.0\n", "0.9944444444444445\n" ] } ], "source": [ "print(dc.yf_30U360(date(2024,2,29), date(2025,2,28)))\n", "#Y1=2024, Y2=2025, M1=M2=2, D1=D2=30\n", "\n", "print(dc.yf_30U360(date(2024,2,28), date(2025,2,28)))\n", "#Y1=2024, Y2=2025, M1=M2=2, D1=D2=28\n", "\n", "print(dc.yf_30U360(date(2023,2,28), date(2024,2,28))) # (360+28-30)/360\n", "#Y1=2023, Y2=2024, M1=M2=2, D1=30, D2=28" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Below you can find a function printing all the introduced Day Count Conventions at once for a specified period:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.08241758241758242\n", "d1: 2024-01-01\n", "d2: 2024-07-01\n", "ActActICMA: 0.5\n", "30360ISDA: 0.5\n", "30E360: 0.5\n", "30U360: 0.5\n", "ActAct: 0.4972677595628415\n", "Act360: 0.5055555555555555\n", "Act365Fixed: 0.4986301369863014\n" ] } ], "source": [ "from rivapy.tools.datetools import DayCounter as dc\n", "\n", "# this is how you can get the year fraction based on a date count convention in rivapy:\n", "# Options:\n", "#\n", "# - \"ActActICMA\"\n", "# - \"Act365Fixed\"\n", "# - \"ActAct\"\n", "# - \"Act360\"\n", "# - \"30U360\"\n", "# - \"30E360\"\n", "# - \"30360ISDA\"\n", "d1 = date(2023,12,31)\n", "d2 = date(2024,7,1)\n", "coupon_schedule = [date(2024, 1, 1), date(2024, 7, 1)]\n", "dc(\"ActAct\").yf(d1, d2)\n", "\n", "\n", "print(dc.yf_ActActICMA(date(2024,5,1), date(2024,5,31), coupon_schedule=coupon_schedule, coupon_frequency=2))\n", "\n", "#printing all implemented types in rivapy\n", "\n", "def show_day_counter(d1,d2,dc_names):\n", " if isinstance(dc_names, str):\n", " dc_names = [dc_names]\n", " print(\"d1\"+\":\", d1)\n", " print(\"d2\"+\":\", d2)\n", " for dc_name in dc_names:\n", " if dc_name != \"ActActICMA\": \n", " print(dc_name + \":\",dc(dc_name).yf(d1,d2))\n", " else:\n", " print(dc_name + \":\",dc.yf_ActActICMA(d1, d2, coupon_schedule=coupon_schedule, coupon_frequency=2)) \n", " \n", "show_day_counter(date(2024,1,1),date(2024,7,1),[\"ActActICMA\",\"30360ISDA\",\"30E360\", \"30U360\",\"ActAct\", \"Act360\",\"Act365Fixed\"])" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "d1: 2024-02-29\n", "d2: 2024-03-29\n" ] } ], "source": [ "d1 = date(2024,2,29)\n", "delta = relativedelta(years=0, months = 1, days=0)\n", "d2 = d1 + delta\n", "print(\"d1:\", d1)\n", "print(\"d2:\", d2)\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.11" }, "toc": { "base_numbering": 1, "nav_menu": { "height": "191px", "width": "252px" }, "number_sections": true, "sideBar": true, "skip_h1_title": true, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": "block", "toc_window_display": true }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }