From 9a3881a6a36a0fa27fb10b45c1811a3d7becbc48 Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Thu, 22 May 2025 10:36:50 +0800
Subject: [PATCH 01/12] Include the computation of interest rate swap duration
Calculation of the Macaulay Duration and Modified_Duration in an Interest Rate Swap Based on Bond Math: The Theory Behind the Formulas, Second Edition by Donald J. Smith
---
financepy/products/rates/ibor_swap.py | 49 +++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/financepy/products/rates/ibor_swap.py b/financepy/products/rates/ibor_swap.py
index 596d1978..df2799f0 100644
--- a/financepy/products/rates/ibor_swap.py
+++ b/financepy/products/rates/ibor_swap.py
@@ -392,6 +392,55 @@ def print_payments(self):
###########################################################################
+ def buyer_side_macaulay_duration(self):
+ """Calculation of the Payer's Macaulay Duration in an Interest Rate Swap
+ Based on Bond Math: The Theory Behind the Formulas, Second Edition by
+ Donald J. Smith
+ """
+ # Number of fixed leg payments
+ payment_period = len(self.fixed_leg.payments)
+
+ # Get coupon frequency
+ coupon_frequency = self.fixed_leg.freq_type.value
+
+ # Get swap rate
+ swap_rate_val = self.swap_rate()
+
+ y = swap_rate_val / coupon_frequency
+ N = payment_period
+ c = swap_rate_val / coupon_frequency
+ md1 = (1 + y) / y
+ md2 = 1 + y + (N * (c - y))
+ md3 = c * ((1 + y) ** N - 1) + y
+ mac_duration = 1 - (md1 - md2 / md3)
+ return mac_duration
+
+ def receiver_side_macaulay_duration(self):
+ """Calculation of the Receiver's Macaulay Duration in an Interest Rate Swap
+ Based on Bond Math: The Theory Behind the Formulas, Second Edition by
+ Donald J. Smith
+ """
+ return self.buyer_side_macaulay_duration()*(-1)
+
+ def buyer_side_modified_duration(self):
+ """Computation of the Modified Duration for the Fixed-Rate
+ Payer's Perspective in Interest Rate Swap
+ """
+ # Get coupon frequency
+ coupon_frequency = self.fixed_leg.freq_type.value
+
+ # Get swap rate
+ swap_rate_val = self.swap_rate()
+
+ return self.buyer_side_macaulay_duration()/(1+swap_rate_val/coupon_frequency)
+
+ def receiver_side_modified_duration(self):
+ """Computation of the Modified Duration for the Fixed-Rate
+ Receiver's Perspective in Interest Rate Swap
+ """
+ return self.buyer_side_modified_duration()*(-1)
+
+
def __repr__(self):
s = label_to_string("OBJECT TYPE", type(self).__name__)
From 1c94087f8c63f95648f3ca8b6286e96beb713f18 Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Thu, 22 May 2025 10:47:20 +0800
Subject: [PATCH 02/12] Update ibor_swap.py
---
financepy/products/rates/ibor_swap.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/financepy/products/rates/ibor_swap.py b/financepy/products/rates/ibor_swap.py
index df2799f0..1916190f 100644
--- a/financepy/products/rates/ibor_swap.py
+++ b/financepy/products/rates/ibor_swap.py
@@ -415,6 +415,8 @@ def buyer_side_macaulay_duration(self):
mac_duration = 1 - (md1 - md2 / md3)
return mac_duration
+ ###########################################################################
+
def receiver_side_macaulay_duration(self):
"""Calculation of the Receiver's Macaulay Duration in an Interest Rate Swap
Based on Bond Math: The Theory Behind the Formulas, Second Edition by
@@ -422,6 +424,8 @@ def receiver_side_macaulay_duration(self):
"""
return self.buyer_side_macaulay_duration()*(-1)
+ ###########################################################################
+
def buyer_side_modified_duration(self):
"""Computation of the Modified Duration for the Fixed-Rate
Payer's Perspective in Interest Rate Swap
@@ -434,12 +438,15 @@ def buyer_side_modified_duration(self):
return self.buyer_side_macaulay_duration()/(1+swap_rate_val/coupon_frequency)
+ ###########################################################################
+
def receiver_side_modified_duration(self):
"""Computation of the Modified Duration for the Fixed-Rate
Receiver's Perspective in Interest Rate Swap
"""
return self.buyer_side_modified_duration()*(-1)
+ ###########################################################################
def __repr__(self):
From 8ece84760a789c4a764e9c2aa9caa2571bc0bb71 Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Fri, 23 May 2025 09:36:54 +0800
Subject: [PATCH 03/12] fix duration method
fix duration method
---
financepy/products/rates/ibor_swap.py | 28 +-
..._ReplicationgBONDMATHDurationExample.ipynb | 587 ++++++++++++++++++
...eplicationgBONDMATHDurationExample3M.ipynb | 477 ++++++++++++++
3 files changed, 1079 insertions(+), 13 deletions(-)
create mode 100644 notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
create mode 100644 notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
diff --git a/financepy/products/rates/ibor_swap.py b/financepy/products/rates/ibor_swap.py
index 1916190f..8a4f26eb 100644
--- a/financepy/products/rates/ibor_swap.py
+++ b/financepy/products/rates/ibor_swap.py
@@ -392,22 +392,24 @@ def print_payments(self):
###########################################################################
- def buyer_side_macaulay_duration(self):
+ def payer_side_macaulay_duration(self, value_dt, discount_curve, payment_periods: float):
"""Calculation of the Payer's Macaulay Duration in an Interest Rate Swap
Based on Bond Math: The Theory Behind the Formulas, Second Edition by
Donald J. Smith
"""
- # Number of fixed leg payments
- payment_period = len(self.fixed_leg.payments)
-
# Get coupon frequency
coupon_frequency = self.fixed_leg.freq_type.value
# Get swap rate
- swap_rate_val = self.swap_rate()
+ swap_rate_val = self.swap_rate(value_dt,discount_curve)
y = swap_rate_val / coupon_frequency
- N = payment_period
+ # payment_periods is the number of periods to maturity as of the beginning of the period;
+ # for instance, If the start date of the interest rate swap is 2024-01-01,
+ # the end date is 2025-12-31, the valuation date is 2024-03-31,
+ # and the frequency type is QUARTERLY,
+ # then the number of payment periods is 8; it is independent of the valuation date.
+ N = payment_periods
c = swap_rate_val / coupon_frequency
md1 = (1 + y) / y
md2 = 1 + y + (N * (c - y))
@@ -417,16 +419,16 @@ def buyer_side_macaulay_duration(self):
###########################################################################
- def receiver_side_macaulay_duration(self):
+ def receiver_side_macaulay_duration(self, value_dt, discount_curve,payment_periods: float):
"""Calculation of the Receiver's Macaulay Duration in an Interest Rate Swap
Based on Bond Math: The Theory Behind the Formulas, Second Edition by
Donald J. Smith
"""
- return self.buyer_side_macaulay_duration()*(-1)
+ return self.payer_side_macaulay_duration(value_dt, discount_curve,payment_periods)*(-1)
###########################################################################
- def buyer_side_modified_duration(self):
+ def payer_side_modified_duration(self, value_dt, discount_curve,payment_periods: float):
"""Computation of the Modified Duration for the Fixed-Rate
Payer's Perspective in Interest Rate Swap
"""
@@ -434,17 +436,17 @@ def buyer_side_modified_duration(self):
coupon_frequency = self.fixed_leg.freq_type.value
# Get swap rate
- swap_rate_val = self.swap_rate()
+ swap_rate_val = self.swap_rate(value_dt,discount_curve)
- return self.buyer_side_macaulay_duration()/(1+swap_rate_val/coupon_frequency)
+ return self.payer_side_macaulay_duration(value_dt, discount_curve,payment_periods)/(1+swap_rate_val/coupon_frequency)
###########################################################################
- def receiver_side_modified_duration(self):
+ def receiver_side_modified_duration(self, value_dt, discount_curve,payment_periods: float):
"""Computation of the Modified Duration for the Fixed-Rate
Receiver's Perspective in Interest Rate Swap
"""
- return self.buyer_side_modified_duration()*(-1)
+ return self.payer_side_modified_duration(value_dt, discount_curve,payment_periods)*(-1)
###########################################################################
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
new file mode 100644
index 00000000..916ef5a9
--- /dev/null
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
@@ -0,0 +1,587 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "id": "initial_id",
+ "metadata": {
+ "collapsed": true,
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:52.331390Z",
+ "start_time": "2025-05-23T01:25:52.328042Z"
+ }
+ },
+ "source": [
+ "from financepy.utils import *\n",
+ "from financepy.products.rates import *\n",
+ "from financepy.market.curves import *\n",
+ "import datetime as dt\n",
+ "\n",
+ "from notebooks.products.rates.FINIBORSWAP_ReplicationgBONDMATHDurationExample3M import payment_period"
+ ],
+ "outputs": [],
+ "execution_count": 22
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:53.315940Z",
+ "start_time": "2025-05-23T01:25:53.311144Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "swap_cal_type = CalendarTypes.TARGET\n",
+ "bd_type = BusDayAdjustTypes.FOLLOWING\n",
+ "dg_type = DateGenRuleTypes.BACKWARD\n",
+ "\n",
+ "\n",
+ "fixed_cpn = 0.034\n",
+ "fixed_freq_type = FrequencyTypes.QUARTERLY\n",
+ "fixed_dc_type = DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "float_spread = 0.0\n",
+ "float_freq_type = FrequencyTypes.QUARTERLY\n",
+ "float_dc_type = DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "swap_type = SwapTypes.PAY\n",
+ "notional = 60000000\n",
+ "\n",
+ "start_dt = Date(1, 1, 2024)\n",
+ "maturity_dt = start_dt.add_tenor('2Y')\n",
+ "\n",
+ "swap = IborSwap(start_dt,\n",
+ " maturity_dt,\n",
+ " swap_type,\n",
+ " fixed_cpn,\n",
+ " fixed_freq_type,\n",
+ " fixed_dc_type,\n",
+ " notional,\n",
+ " float_spread,\n",
+ " float_freq_type,\n",
+ " float_dc_type,\n",
+ " swap_cal_type,\n",
+ " bd_type,\n",
+ " dg_type)\n"
+ ],
+ "id": "1ebf43316efee835",
+ "outputs": [],
+ "execution_count": 23
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:55.512229Z",
+ "start_time": "2025-05-23T01:25:55.509220Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "value_date= dt.datetime(2023,12,31)\n",
+ "value_dt = from_datetime(value_date)\n",
+ "\n",
+ "settle_dt = value_dt.add_weekdays(0)\n",
+ "# settle_dt=value_dt"
+ ],
+ "id": "8e46f142f3cba5d7",
+ "outputs": [],
+ "execution_count": 24
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:57.156649Z",
+ "start_time": "2025-05-23T01:25:57.152272Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "yield_curve=[i/100 for i in [0.5,1.0407,1.5829,2.1271,2.4506,2.7756,3.1025,3.4316]]\n",
+ "zero_dts=value_dt.add_years([0.25,0.5,0.75,1.0,1.25,1.5,1.75,2.0])\n",
+ "\n",
+ "zero_curve = DiscountCurveZeros(value_dt=value_dt,\n",
+ " zero_dts=zero_dts,\n",
+ " zero_rates=yield_curve,\n",
+ " freq_type=FrequencyTypes.QUARTERLY,\n",
+ " dc_type=DayCountTypes.THIRTY_360_BOND,\n",
+ " interp_type=InterpTypes.FINCUBIC_ZERO_RATES\n",
+ " )"
+ ],
+ "id": "290b7a06932da41d",
+ "outputs": [],
+ "execution_count": 25
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:58.324864Z",
+ "start_time": "2025-05-23T01:25:58.320708Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.swap_rate(value_dt, zero_curve)",
+ "id": "7bb1613d5e865838",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0.03404344249149676"
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 26
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:59.653219Z",
+ "start_time": "2025-05-23T01:25:59.647340Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.value(settle_dt, zero_curve)",
+ "id": "e2fabe76f4bbdf2d",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "5070.7014320408925"
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 27
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:33:14.904831Z",
+ "start_time": "2025-05-23T01:33:14.899446Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "payment_periods=8\n",
+ "swap.payer_side_macaulay_duration(value_dt, zero_curve,payment_periods)"
+ ],
+ "id": "3f988f26e6662203",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-6.767653343606554"
+ ]
+ },
+ "execution_count": 40,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 40
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:27:02.073420Z",
+ "start_time": "2025-05-23T01:27:02.060189Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.receiver_side_macaulay_duration(value_dt, zero_curve,payment_periods)",
+ "id": "96d568f7a71861fe",
+ "outputs": [
+ {
+ "ename": "TypeError",
+ "evalue": "IborSwap.receiver_side_macaulay_duration() takes 3 positional arguments but 4 were given",
+ "output_type": "error",
+ "traceback": [
+ "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
+ "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)",
+ "Cell \u001B[1;32mIn[36], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mswap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mreceiver_side_macaulay_duration\u001B[49m\u001B[43m(\u001B[49m\u001B[43mvalue_dt\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mzero_curve\u001B[49m\u001B[43m,\u001B[49m\u001B[43mpayment_periods\u001B[49m\u001B[43m)\u001B[49m\n",
+ "\u001B[1;31mTypeError\u001B[0m: IborSwap.receiver_side_macaulay_duration() takes 3 positional arguments but 4 were given"
+ ]
+ }
+ ],
+ "execution_count": 36
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:27:08.799220Z",
+ "start_time": "2025-05-23T01:27:08.788672Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.payer_side_modified_duration(value_dt, zero_curve,payment_periods)",
+ "id": "ec2187c7336c1bc3",
+ "outputs": [
+ {
+ "ename": "TypeError",
+ "evalue": "IborSwap.payer_side_modified_duration() takes 3 positional arguments but 4 were given",
+ "output_type": "error",
+ "traceback": [
+ "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
+ "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)",
+ "Cell \u001B[1;32mIn[37], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mswap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mpayer_side_modified_duration\u001B[49m\u001B[43m(\u001B[49m\u001B[43mvalue_dt\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mzero_curve\u001B[49m\u001B[43m,\u001B[49m\u001B[43mpayment_periods\u001B[49m\u001B[43m)\u001B[49m\n",
+ "\u001B[1;31mTypeError\u001B[0m: IborSwap.payer_side_modified_duration() takes 3 positional arguments but 4 were given"
+ ]
+ }
+ ],
+ "execution_count": 37
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:27:12.992002Z",
+ "start_time": "2025-05-23T01:27:12.980577Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.receiver_side_modified_duration(value_dt, zero_curve,payment_periods)",
+ "id": "2c1b845afaf5e18f",
+ "outputs": [
+ {
+ "ename": "TypeError",
+ "evalue": "IborSwap.receiver_side_modified_duration() takes 3 positional arguments but 4 were given",
+ "output_type": "error",
+ "traceback": [
+ "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
+ "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)",
+ "Cell \u001B[1;32mIn[38], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mswap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mreceiver_side_modified_duration\u001B[49m\u001B[43m(\u001B[49m\u001B[43mvalue_dt\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mzero_curve\u001B[49m\u001B[43m,\u001B[49m\u001B[43mpayment_periods\u001B[49m\u001B[43m)\u001B[49m\n",
+ "\u001B[1;31mTypeError\u001B[0m: IborSwap.receiver_side_modified_duration() takes 3 positional arguments but 4 were given"
+ ]
+ }
+ ],
+ "execution_count": 38
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:42.381647100Z",
+ "start_time": "2025-05-22T06:57:55.610805Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.print_payments()",
+ "id": "2af7c95b07730dda",
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "START DATE: 01-JAN-2024\n",
+ "MATURITY DATE: 02-JAN-2026\n",
+ "COUPON (%): 3.4000000000000004\n",
+ "FREQUENCY: FrequencyTypes.QUARTERLY\n",
+ "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "PAYMENTS SCHEDULE:\n",
+ "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
+ "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC | RATE | PMNT |\n",
+ "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
+ "| 1 | 02-APR-2024 | 01-JAN-2024 | 02-APR-2024 | 91 | 0.2528 | 3.4 | 515666.67 |\n",
+ "| 2 | 01-JUL-2024 | 02-APR-2024 | 01-JUL-2024 | 89 | 0.2472 | 3.4 | 504333.33 |\n",
+ "| 3 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 | 3.4 | 510000.0 |\n",
+ "| 4 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 | 3.4 | 515666.67 |\n",
+ "| 5 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 | 3.4 | 504333.33 |\n",
+ "| 6 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 | 3.4 | 510000.0 |\n",
+ "| 7 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 | 3.4 | 510000.0 |\n",
+ "| 8 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 | 3.4 | 515666.67 |\n",
+ "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
+ "START DATE: 01-JAN-2024\n",
+ "MATURITY DATE: 02-JAN-2026\n",
+ "SPREAD (bp): 0.0\n",
+ "FREQUENCY: FrequencyTypes.QUARTERLY\n",
+ "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "PAYMENTS SCHEDULE:\n",
+ "+---------+-------------+-------------+-------------+------+----------+\n",
+ "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC |\n",
+ "+---------+-------------+-------------+-------------+------+----------+\n",
+ "| 1 | 02-APR-2024 | 01-JAN-2024 | 02-APR-2024 | 91 | 0.2528 |\n",
+ "| 2 | 01-JUL-2024 | 02-APR-2024 | 01-JUL-2024 | 89 | 0.2472 |\n",
+ "| 3 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 |\n",
+ "| 4 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 |\n",
+ "| 5 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 |\n",
+ "| 6 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 |\n",
+ "| 7 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 |\n",
+ "| 8 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 |\n",
+ "+---------+-------------+-------------+-------------+------+----------+\n"
+ ]
+ }
+ ],
+ "execution_count": 65
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:42.389019500Z",
+ "start_time": "2025-05-22T07:19:36.402004Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "pd.Series(swap.fixed_leg.payment_dts)",
+ "id": "52df44f5a67bc377",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0 02-APR-2024\n",
+ "1 01-JUL-2024\n",
+ "2 01-OCT-2024\n",
+ "3 02-JAN-2025\n",
+ "4 01-APR-2025\n",
+ "5 01-JUL-2025\n",
+ "6 01-OCT-2025\n",
+ "7 02-JAN-2026\n",
+ "dtype: object"
+ ]
+ },
+ "execution_count": 70,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 70
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "# 3months later",
+ "id": "39513cfdc5d7ef1"
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:42.392700200Z",
+ "start_time": "2025-05-22T08:57:46.274653Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "yield_curve_3m=[i/100 for i in [0.75,1.1853,1.6822,2.1474,2.4371,2.7390,3.0198]]\n",
+ "zero_dts_3m=value_dt.add_years([0.25,0.5,0.75,1.0,1.25,1.5,1.75])\n",
+ "\n",
+ "zero_curve_3m = DiscountCurveZeros(value_dt=value_dt.add_months(3),\n",
+ " zero_dts=zero_dts_3m,\n",
+ " zero_rates=yield_curve_3m,\n",
+ " freq_type=FrequencyTypes.QUARTERLY,\n",
+ " dc_type=DayCountTypes.THIRTY_360_BOND,\n",
+ " interp_type=InterpTypes.FINCUBIC_ZERO_RATES\n",
+ " )\n",
+ "\n"
+ ],
+ "id": "8acc84107dae665e",
+ "outputs": [],
+ "execution_count": 93
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:42.392700200Z",
+ "start_time": "2025-05-22T08:58:16.963888Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "fixed_cpn_3m=0.034\n",
+ "swap_3m = IborSwap(start_dt.add_months(3),\n",
+ " maturity_dt,\n",
+ " swap_type,\n",
+ " fixed_cpn_3m,\n",
+ " fixed_freq_type,\n",
+ " fixed_dc_type,\n",
+ " notional,\n",
+ " float_spread,\n",
+ " float_freq_type,\n",
+ " float_dc_type,\n",
+ " swap_cal_type,\n",
+ " bd_type,\n",
+ " dg_type)\n",
+ "\n"
+ ],
+ "id": "5892081fb637c810",
+ "outputs": [],
+ "execution_count": 99
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:42.392700200Z",
+ "start_time": "2025-05-22T08:58:18.380055Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap_3m.value(value_dt.add_months(3), zero_curve_3m)",
+ "id": "3aa3b8731a5cc344",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-1103746.1176017257"
+ ]
+ },
+ "execution_count": 100,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 100
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:42.392700200Z",
+ "start_time": "2025-05-22T08:58:11.381600Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap_3m.swap_rate(value_dt.add_months(3), zero_curve_3m)",
+ "id": "5d8fe704908ed541",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0.023244839642912206"
+ ]
+ },
+ "execution_count": 98,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 98
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:42.394185900Z",
+ "start_time": "2025-05-22T08:15:54.437385Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap_3m.payer_side_macaulay_duration(value_dt.add_months(3), zero_curve_3m)",
+ "id": "f9c796b4218d3df7",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-5.879831278293125"
+ ]
+ },
+ "execution_count": 76,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 76
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:42.394185900Z",
+ "start_time": "2025-05-22T08:15:55.564419Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "start_dt.add_months(3)",
+ "id": "68a6d3e4cc14ee91",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "01-APR-2024"
+ ]
+ },
+ "execution_count": 77,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 77
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:25:42.394185900Z",
+ "start_time": "2025-05-22T08:19:10.564739Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap_3m.print_payments()",
+ "id": "68097534a5e9ba5e",
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "START DATE: 01-APR-2024\n",
+ "MATURITY DATE: 02-JAN-2026\n",
+ "COUPON (%): 3.0\n",
+ "FREQUENCY: FrequencyTypes.QUARTERLY\n",
+ "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "PAYMENTS SCHEDULE:\n",
+ "+---------+-------------+-------------+-------------+------+----------+------+----------+\n",
+ "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC | RATE | PMNT |\n",
+ "+---------+-------------+-------------+-------------+------+----------+------+----------+\n",
+ "| 1 | 01-JUL-2024 | 01-APR-2024 | 01-JUL-2024 | 90 | 0.25 | 3.0 | 450000.0 |\n",
+ "| 2 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 | 3.0 | 450000.0 |\n",
+ "| 3 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 | 3.0 | 455000.0 |\n",
+ "| 4 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 | 3.0 | 445000.0 |\n",
+ "| 5 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 | 3.0 | 450000.0 |\n",
+ "| 6 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 | 3.0 | 450000.0 |\n",
+ "| 7 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 | 3.0 | 455000.0 |\n",
+ "+---------+-------------+-------------+-------------+------+----------+------+----------+\n",
+ "START DATE: 01-APR-2024\n",
+ "MATURITY DATE: 02-JAN-2026\n",
+ "SPREAD (bp): 0.0\n",
+ "FREQUENCY: FrequencyTypes.QUARTERLY\n",
+ "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "PAYMENTS SCHEDULE:\n",
+ "+---------+-------------+-------------+-------------+------+----------+\n",
+ "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC |\n",
+ "+---------+-------------+-------------+-------------+------+----------+\n",
+ "| 1 | 01-JUL-2024 | 01-APR-2024 | 01-JUL-2024 | 90 | 0.25 |\n",
+ "| 2 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 |\n",
+ "| 3 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 |\n",
+ "| 4 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 |\n",
+ "| 5 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 |\n",
+ "| 6 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 |\n",
+ "| 7 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 |\n",
+ "+---------+-------------+-------------+-------------+------+----------+\n"
+ ]
+ }
+ ],
+ "execution_count": 83
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 2
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython2",
+ "version": "2.7.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
new file mode 100644
index 00000000..603c18e5
--- /dev/null
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
@@ -0,0 +1,477 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "id": "initial_id",
+ "metadata": {
+ "collapsed": true,
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:13:12.026880Z",
+ "start_time": "2025-05-23T01:13:12.023386Z"
+ }
+ },
+ "source": [
+ "from financepy.utils import *\n",
+ "from financepy.products.rates import *\n",
+ "from financepy.market.curves import *\n",
+ "import datetime as dt"
+ ],
+ "outputs": [],
+ "execution_count": 92
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:13:13.020649Z",
+ "start_time": "2025-05-23T01:13:13.015544Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "swap_cal_type = CalendarTypes.TARGET\n",
+ "bd_type = BusDayAdjustTypes.FOLLOWING\n",
+ "dg_type = DateGenRuleTypes.BACKWARD\n",
+ "\n",
+ "\n",
+ "fixed_cpn = 0.034\n",
+ "fixed_freq_type = FrequencyTypes.QUARTERLY\n",
+ "fixed_dc_type = DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "float_spread = 0.0\n",
+ "float_freq_type = FrequencyTypes.QUARTERLY\n",
+ "float_dc_type = DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "swap_type = SwapTypes.PAY\n",
+ "notional = 60000000\n",
+ "\n",
+ "start_dt = Date(1, 4, 2024)\n",
+ "maturity_dt = start_dt.add_years(1.75)\n",
+ "\n",
+ "swap = IborSwap(start_dt,\n",
+ " maturity_dt,\n",
+ " swap_type,\n",
+ " fixed_cpn,\n",
+ " fixed_freq_type,\n",
+ " fixed_dc_type,\n",
+ " notional,\n",
+ " float_spread,\n",
+ " float_freq_type,\n",
+ " float_dc_type,\n",
+ " swap_cal_type,\n",
+ " bd_type,\n",
+ " dg_type)\n"
+ ],
+ "id": "1ebf43316efee835",
+ "outputs": [],
+ "execution_count": 93
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:13:15.489337Z",
+ "start_time": "2025-05-23T01:13:15.485019Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "value_date= dt.datetime(2024,3,31)\n",
+ "value_dt = from_datetime(value_date)\n",
+ "\n",
+ "settle_dt = value_dt.add_weekdays(0)\n",
+ "# settle_dt=value_dt\n",
+ "settle_dt"
+ ],
+ "id": "8e46f142f3cba5d7",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "31-MAR-2024"
+ ]
+ },
+ "execution_count": 94,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 94
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:13:18.003794Z",
+ "start_time": "2025-05-23T01:13:17.998703Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "# 书中曲线\n",
+ "# yield_curve=[i/100 for i in [0.75,1.1853,1.6822,2.1474,2.4371,2.7390,3.0198]]\n",
+ "# zero_dts=value_dt.add_years([0.25,0.5,0.75,1.0,1.25,1.5,1.75])\n",
+ "\n",
+ "\n",
+ "yield_curve=[i/100 for i in [0.75,1.1853,1.6822,2.1474,2.4371,2.7390,3.0198]]\n",
+ "zero_dts=value_dt.add_years([0.25,0.5,0.75,1.0,1.25,1.5,1.75])\n",
+ "\n",
+ "zero_curve = DiscountCurveZeros(value_dt=value_dt,\n",
+ " zero_dts=zero_dts,\n",
+ " zero_rates=yield_curve,\n",
+ " freq_type=FrequencyTypes.QUARTERLY,\n",
+ " dc_type=DayCountTypes.THIRTY_360_BOND,\n",
+ " interp_type=InterpTypes.FINCUBIC_ZERO_RATES\n",
+ " )"
+ ],
+ "id": "290b7a06932da41d",
+ "outputs": [],
+ "execution_count": 95
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:13:19.311195Z",
+ "start_time": "2025-05-23T01:13:19.307399Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.swap_rate(value_dt, zero_curve)",
+ "id": "7bb1613d5e865838",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0.030065619962567392"
+ ]
+ },
+ "execution_count": 96,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 96
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:13:29.846190Z",
+ "start_time": "2025-05-23T01:13:29.841877Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "# def payer_side_macaulay_duration(value_dt, discount_curve):\n",
+ "# \"\"\"Calculation of the Payer's Macaulay Duration in an Interest Rate Swap\n",
+ "# Based on Bond Math: The Theory Behind the Formulas, Second Edition by\n",
+ "# Donald J. Smith\n",
+ "# \"\"\"\n",
+ "# # Number of fixed leg payments\n",
+ "# payment_period = len(swap.fixed_leg.payments)\n",
+ "#\n",
+ "# # Get coupon frequency\n",
+ "# coupon_frequency = self.fixed_leg.freq_type.value\n",
+ "#\n",
+ "# # Get swap rate\n",
+ "# swap_rate_val = self.swap_rate(value_dt, discount_curve)\n",
+ "#\n",
+ "# y = swap_rate_val / coupon_frequency\n",
+ "# N = payment_period\n",
+ "# c = swap_rate_val / coupon_frequency\n",
+ "# md1 = (1 + y) / y\n",
+ "# md2 = 1 + y + (N * (c - y))\n",
+ "# md3 = c * ((1 + y) ** N - 1) + y\n",
+ "# mac_duration = 1 - (md1 - md2 / md3)\n",
+ "# return mac_duration\n",
+ "\n",
+ "\n",
+ "payment_period = len(swap.fixed_leg.payments) + 1\n",
+ "coupon_frequency = swap.fixed_leg.freq_type.value\n",
+ "swap_rate_val = swap.swap_rate(value_dt, zero_curve)\n",
+ "y = swap_rate_val / coupon_frequency\n",
+ "N = payment_period\n",
+ "c = swap_rate_val / coupon_frequency\n",
+ "md1 = (1 + y) / y\n",
+ "md2 = 1 + y + (N * (c - y))\n",
+ "md3 = c * ((1 + y) ** N - 1) + y\n",
+ "mac_duration = 1 - (md1 - md2 / md3)\n",
+ "\n",
+ "delta_mv=-(-mac_duration/4*notional*(-0.004))"
+ ],
+ "id": "65a401442f9bf084",
+ "outputs": [],
+ "execution_count": 98
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:13:32.846466Z",
+ "start_time": "2025-05-23T01:13:32.841730Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.value(settle_dt, zero_curve)",
+ "id": "e2fabe76f4bbdf2d",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-404094.769553849"
+ ]
+ },
+ "execution_count": 99,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 99
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T01:23:14.567789Z",
+ "start_time": "2025-05-23T01:23:14.556465Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.payer_side_macaulay_duration(value_dt,zero_curve,8)",
+ "id": "3f988f26e6662203",
+ "outputs": [
+ {
+ "ename": "TypeError",
+ "evalue": "IborSwap.payer_side_macaulay_duration() takes 3 positional arguments but 4 were given",
+ "output_type": "error",
+ "traceback": [
+ "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
+ "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)",
+ "Cell \u001B[1;32mIn[107], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mswap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mpayer_side_macaulay_duration\u001B[49m\u001B[43m(\u001B[49m\u001B[43mvalue_dt\u001B[49m\u001B[43m,\u001B[49m\u001B[43mzero_curve\u001B[49m\u001B[43m,\u001B[49m\u001B[38;5;241;43m8\u001B[39;49m\u001B[43m)\u001B[49m\n",
+ "\u001B[1;31mTypeError\u001B[0m: IborSwap.payer_side_macaulay_duration() takes 3 positional arguments but 4 were given"
+ ]
+ }
+ ],
+ "execution_count": 107
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T00:45:15.232484600Z",
+ "start_time": "2025-05-23T00:39:29.952636Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.receiver_side_macaulay_duration(value_dt, zero_curve)",
+ "id": "96d568f7a71861fe",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "5.84526657803498"
+ ]
+ },
+ "execution_count": 55,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 55
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T00:45:15.232484600Z",
+ "start_time": "2025-05-23T00:39:30.019485Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.payer_side_modified_duration(value_dt, zero_curve)",
+ "id": "ec2187c7336c1bc3",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-5.801658959676467"
+ ]
+ },
+ "execution_count": 56,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 56
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T00:45:15.238495100Z",
+ "start_time": "2025-05-23T00:39:30.068245Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.receiver_side_modified_duration(value_dt, zero_curve)",
+ "id": "2c1b845afaf5e18f",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "5.801658959676467"
+ ]
+ },
+ "execution_count": 57,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 57
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T00:45:15.239505100Z",
+ "start_time": "2025-05-23T00:39:30.125510Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.print_payments()",
+ "id": "2af7c95b07730dda",
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "START DATE: 01-APR-2024\n",
+ "MATURITY DATE: 02-JAN-2026\n",
+ "COUPON (%): 3.4000000000000004\n",
+ "FREQUENCY: FrequencyTypes.QUARTERLY\n",
+ "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "PAYMENTS SCHEDULE:\n",
+ "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
+ "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC | RATE | PMNT |\n",
+ "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
+ "| 1 | 01-JUL-2024 | 01-APR-2024 | 01-JUL-2024 | 90 | 0.25 | 3.4 | 510000.0 |\n",
+ "| 2 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 | 3.4 | 510000.0 |\n",
+ "| 3 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 | 3.4 | 515666.67 |\n",
+ "| 4 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 | 3.4 | 504333.33 |\n",
+ "| 5 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 | 3.4 | 510000.0 |\n",
+ "| 6 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 | 3.4 | 510000.0 |\n",
+ "| 7 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 | 3.4 | 515666.67 |\n",
+ "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
+ "START DATE: 01-APR-2024\n",
+ "MATURITY DATE: 02-JAN-2026\n",
+ "SPREAD (bp): 0.0\n",
+ "FREQUENCY: FrequencyTypes.QUARTERLY\n",
+ "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "PAYMENTS SCHEDULE:\n",
+ "+---------+-------------+-------------+-------------+------+----------+\n",
+ "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC |\n",
+ "+---------+-------------+-------------+-------------+------+----------+\n",
+ "| 1 | 01-JUL-2024 | 01-APR-2024 | 01-JUL-2024 | 90 | 0.25 |\n",
+ "| 2 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 |\n",
+ "| 3 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 |\n",
+ "| 4 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 |\n",
+ "| 5 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 |\n",
+ "| 6 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 |\n",
+ "| 7 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 |\n",
+ "+---------+-------------+-------------+-------------+------+----------+\n"
+ ]
+ }
+ ],
+ "execution_count": 58
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T00:45:15.239505100Z",
+ "start_time": "2025-05-23T00:39:30.159010Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.print_float_leg_pv()",
+ "id": "1c960526153c2223",
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "START DATE: 01-APR-2024\n",
+ "MATURITY DATE: 02-JAN-2026\n",
+ "SPREAD (BPS): 0.0\n",
+ "FREQUENCY: FrequencyTypes.QUARTERLY\n",
+ "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "PAYMENTS VALUATION:\n",
+ "+---------+-------------+----------+--------+-----------+--------+-----------+------------+\n",
+ "| PAY_NUM | PAY_dt | NOTIONAL | IBOR | PMNT | DF | PV | CUM_PV |\n",
+ "+---------+-------------+----------+--------+-----------+--------+-----------+------------+\n",
+ "| 1 | 01-JUL-2024 | 60000000 | 0.7529 | 112935.42 | 0.9981 | 112722.26 | 112722.26 |\n",
+ "| 2 | 01-OCT-2024 | 60000000 | 1.6379 | 245686.53 | 0.994 | 244222.77 | 356945.03 |\n",
+ "| 3 | 02-JAN-2025 | 60000000 | 2.7131 | 411480.71 | 0.9873 | 406243.16 | 763188.19 |\n",
+ "| 4 | 01-APR-2025 | 60000000 | 3.5062 | 520087.02 | 0.9788 | 509054.52 | 1272242.71 |\n",
+ "| 5 | 01-JUL-2025 | 60000000 | 3.588 | 538192.75 | 0.9701 | 522093.07 | 1794335.78 |\n",
+ "| 6 | 01-OCT-2025 | 60000000 | 4.293 | 643955.16 | 0.9598 | 618058.3 | 2412394.08 |\n",
+ "| 7 | 02-JAN-2026 | 60000000 | 4.6963 | 712268.76 | 0.9485 | 675604.45 | 3087998.53 |\n",
+ "+---------+-------------+----------+--------+-----------+--------+-----------+------------+\n"
+ ]
+ }
+ ],
+ "execution_count": 59
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T00:45:15.240494900Z",
+ "start_time": "2025-05-23T00:39:30.197673Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.print_fixed_leg_pv()",
+ "id": "5037651021a91d38",
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "START DATE: 01-APR-2024\n",
+ "MATURITY DATE: 02-JAN-2026\n",
+ "COUPON (%): 3.4000000000000004\n",
+ "FREQUENCY: FrequencyTypes.QUARTERLY\n",
+ "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
+ "\n",
+ "PAYMENTS VALUATION:\n",
+ "+---------+-------------+----------+------+-----------+--------+-----------+------------+\n",
+ "| PAY_NUM | PAY_dt | NOTIONAL | RATE | PMNT | DF | PV | CUM_PV |\n",
+ "+---------+-------------+----------+------+-----------+--------+-----------+------------+\n",
+ "| 1 | 01-JUL-2024 | 60000000 | 3.4 | 510000.0 | 0.9981 | 509037.4 | 509037.4 |\n",
+ "| 2 | 01-OCT-2024 | 60000000 | 3.4 | 510000.0 | 0.994 | 506961.51 | 1015998.91 |\n",
+ "| 3 | 02-JAN-2025 | 60000000 | 3.4 | 515666.67 | 0.9873 | 509102.98 | 1525101.88 |\n",
+ "| 4 | 01-APR-2025 | 60000000 | 3.4 | 504333.33 | 0.9788 | 493635.02 | 2018736.9 |\n",
+ "| 5 | 01-JUL-2025 | 60000000 | 3.4 | 510000.0 | 0.9701 | 494743.69 | 2513480.58 |\n",
+ "| 6 | 01-OCT-2025 | 60000000 | 3.4 | 510000.0 | 0.9598 | 489490.19 | 3002970.77 |\n",
+ "| 7 | 02-JAN-2026 | 60000000 | 3.4 | 515666.67 | 0.9485 | 489122.52 | 3492093.3 |\n",
+ "+---------+-------------+----------+------+-----------+--------+-----------+------------+\n"
+ ]
+ }
+ ],
+ "execution_count": 60
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 2
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython2",
+ "version": "2.7.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
From b6dd01e13422eb1dec037453c8dfd58c45d9ef46 Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Fri, 23 May 2025 10:27:10 +0800
Subject: [PATCH 04/12] Using Modified Duration to Estimate Gains or Losses
---
financepy/products/rates/ibor_swap.py | 12 ++
..._ReplicationgBONDMATHDurationExample.ipynb | 134 ++++++++--------
...eplicationgBONDMATHDurationExample3M.ipynb | 150 ++++++++++--------
3 files changed, 164 insertions(+), 132 deletions(-)
diff --git a/financepy/products/rates/ibor_swap.py b/financepy/products/rates/ibor_swap.py
index 8a4f26eb..ffcf2b01 100644
--- a/financepy/products/rates/ibor_swap.py
+++ b/financepy/products/rates/ibor_swap.py
@@ -450,6 +450,18 @@ def receiver_side_modified_duration(self, value_dt, discount_curve,payment_perio
###########################################################################
+ def payer_side_profits(self,
+ value_dt,
+ discount_curve,payment_periods: float,
+ swap_rate_changes: float ):
+ """Computation of the Profits for the Fixed-Rate Payer's Perspective in Interest Rate Swap
+ """
+ # Get coupon frequency
+ coupon_frequency = self.fixed_leg.freq_type.value
+ annualized_modi_dur = self.payer_side_modified_duration(value_dt, discount_curve,payment_periods)/coupon_frequency
+ return (-1)*(annualized_modi_dur*self.fixed_leg.notional*swap_rate_changes)
+
+
def __repr__(self):
s = label_to_string("OBJECT TYPE", type(self).__name__)
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
index 916ef5a9..724c6aa6 100644
--- a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
@@ -6,8 +6,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:52.331390Z",
- "start_time": "2025-05-23T01:25:52.328042Z"
+ "end_time": "2025-05-23T01:37:56.175867Z",
+ "start_time": "2025-05-23T01:37:56.171771Z"
}
},
"source": [
@@ -15,17 +15,16 @@
"from financepy.products.rates import *\n",
"from financepy.market.curves import *\n",
"import datetime as dt\n",
- "\n",
- "from notebooks.products.rates.FINIBORSWAP_ReplicationgBONDMATHDurationExample3M import payment_period"
+ "\n"
],
"outputs": [],
- "execution_count": 22
+ "execution_count": 2
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:53.315940Z",
- "start_time": "2025-05-23T01:25:53.311144Z"
+ "end_time": "2025-05-23T01:37:57.664887Z",
+ "start_time": "2025-05-23T01:37:57.637136Z"
}
},
"cell_type": "code",
@@ -65,13 +64,13 @@
],
"id": "1ebf43316efee835",
"outputs": [],
- "execution_count": 23
+ "execution_count": 3
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:55.512229Z",
- "start_time": "2025-05-23T01:25:55.509220Z"
+ "end_time": "2025-05-23T01:38:00.243014Z",
+ "start_time": "2025-05-23T01:38:00.238262Z"
}
},
"cell_type": "code",
@@ -84,13 +83,13 @@
],
"id": "8e46f142f3cba5d7",
"outputs": [],
- "execution_count": 24
+ "execution_count": 4
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:57.156649Z",
- "start_time": "2025-05-23T01:25:57.152272Z"
+ "end_time": "2025-05-23T01:38:01.679542Z",
+ "start_time": "2025-05-23T01:38:01.673799Z"
}
},
"cell_type": "code",
@@ -108,13 +107,13 @@
],
"id": "290b7a06932da41d",
"outputs": [],
- "execution_count": 25
+ "execution_count": 5
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:58.324864Z",
- "start_time": "2025-05-23T01:25:58.320708Z"
+ "end_time": "2025-05-23T01:38:03.960837Z",
+ "start_time": "2025-05-23T01:38:03.952526Z"
}
},
"cell_type": "code",
@@ -127,18 +126,18 @@
"0.03404344249149676"
]
},
- "execution_count": 26,
+ "execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 26
+ "execution_count": 6
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:59.653219Z",
- "start_time": "2025-05-23T01:25:59.647340Z"
+ "end_time": "2025-05-23T01:38:05.697242Z",
+ "start_time": "2025-05-23T01:38:05.690197Z"
}
},
"cell_type": "code",
@@ -151,18 +150,18 @@
"5070.7014320408925"
]
},
- "execution_count": 27,
+ "execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 27
+ "execution_count": 7
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:33:14.904831Z",
- "start_time": "2025-05-23T01:33:14.899446Z"
+ "end_time": "2025-05-23T01:38:07.096647Z",
+ "start_time": "2025-05-23T01:38:07.090478Z"
}
},
"cell_type": "code",
@@ -178,18 +177,18 @@
"-6.767653343606554"
]
},
- "execution_count": 40,
+ "execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 40
+ "execution_count": 8
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:27:02.073420Z",
- "start_time": "2025-05-23T01:27:02.060189Z"
+ "end_time": "2025-05-23T01:38:09.247259Z",
+ "start_time": "2025-05-23T01:38:09.242767Z"
}
},
"cell_type": "code",
@@ -197,24 +196,23 @@
"id": "96d568f7a71861fe",
"outputs": [
{
- "ename": "TypeError",
- "evalue": "IborSwap.receiver_side_macaulay_duration() takes 3 positional arguments but 4 were given",
- "output_type": "error",
- "traceback": [
- "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
- "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)",
- "Cell \u001B[1;32mIn[36], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mswap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mreceiver_side_macaulay_duration\u001B[49m\u001B[43m(\u001B[49m\u001B[43mvalue_dt\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mzero_curve\u001B[49m\u001B[43m,\u001B[49m\u001B[43mpayment_periods\u001B[49m\u001B[43m)\u001B[49m\n",
- "\u001B[1;31mTypeError\u001B[0m: IborSwap.receiver_side_macaulay_duration() takes 3 positional arguments but 4 were given"
- ]
+ "data": {
+ "text/plain": [
+ "6.767653343606554"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
}
],
- "execution_count": 36
+ "execution_count": 9
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:27:08.799220Z",
- "start_time": "2025-05-23T01:27:08.788672Z"
+ "end_time": "2025-05-23T01:38:11.105175Z",
+ "start_time": "2025-05-23T01:38:11.098720Z"
}
},
"cell_type": "code",
@@ -222,24 +220,23 @@
"id": "ec2187c7336c1bc3",
"outputs": [
{
- "ename": "TypeError",
- "evalue": "IborSwap.payer_side_modified_duration() takes 3 positional arguments but 4 were given",
- "output_type": "error",
- "traceback": [
- "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
- "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)",
- "Cell \u001B[1;32mIn[37], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mswap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mpayer_side_modified_duration\u001B[49m\u001B[43m(\u001B[49m\u001B[43mvalue_dt\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mzero_curve\u001B[49m\u001B[43m,\u001B[49m\u001B[43mpayment_periods\u001B[49m\u001B[43m)\u001B[49m\n",
- "\u001B[1;31mTypeError\u001B[0m: IborSwap.payer_side_modified_duration() takes 3 positional arguments but 4 were given"
- ]
+ "data": {
+ "text/plain": [
+ "-6.710540865595371"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
}
],
- "execution_count": 37
+ "execution_count": 10
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:27:12.992002Z",
- "start_time": "2025-05-23T01:27:12.980577Z"
+ "end_time": "2025-05-23T01:38:12.408437Z",
+ "start_time": "2025-05-23T01:38:12.401251Z"
}
},
"cell_type": "code",
@@ -247,24 +244,23 @@
"id": "2c1b845afaf5e18f",
"outputs": [
{
- "ename": "TypeError",
- "evalue": "IborSwap.receiver_side_modified_duration() takes 3 positional arguments but 4 were given",
- "output_type": "error",
- "traceback": [
- "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
- "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)",
- "Cell \u001B[1;32mIn[38], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mswap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mreceiver_side_modified_duration\u001B[49m\u001B[43m(\u001B[49m\u001B[43mvalue_dt\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mzero_curve\u001B[49m\u001B[43m,\u001B[49m\u001B[43mpayment_periods\u001B[49m\u001B[43m)\u001B[49m\n",
- "\u001B[1;31mTypeError\u001B[0m: IborSwap.receiver_side_modified_duration() takes 3 positional arguments but 4 were given"
- ]
+ "data": {
+ "text/plain": [
+ "6.710540865595371"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
}
],
- "execution_count": 38
+ "execution_count": 11
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:42.381647100Z",
- "start_time": "2025-05-22T06:57:55.610805Z"
+ "end_time": "2025-05-23T01:38:15.309142Z",
+ "start_time": "2025-05-23T01:38:15.301795Z"
}
},
"cell_type": "code",
@@ -316,13 +312,13 @@
]
}
],
- "execution_count": 65
+ "execution_count": 12
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:42.389019500Z",
- "start_time": "2025-05-22T07:19:36.402004Z"
+ "end_time": "2025-05-23T01:38:16.922391Z",
+ "start_time": "2025-05-23T01:38:16.915012Z"
}
},
"cell_type": "code",
@@ -343,12 +339,12 @@
"dtype: object"
]
},
- "execution_count": 70,
+ "execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 70
+ "execution_count": 13
},
{
"metadata": {},
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
index 603c18e5..d377e7bb 100644
--- a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
@@ -6,8 +6,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-05-23T01:13:12.026880Z",
- "start_time": "2025-05-23T01:13:12.023386Z"
+ "end_time": "2025-05-23T02:25:34.603675Z",
+ "start_time": "2025-05-23T02:25:34.599467Z"
}
},
"source": [
@@ -17,13 +17,13 @@
"import datetime as dt"
],
"outputs": [],
- "execution_count": 92
+ "execution_count": 16
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:13:13.020649Z",
- "start_time": "2025-05-23T01:13:13.015544Z"
+ "end_time": "2025-05-23T02:25:34.630084Z",
+ "start_time": "2025-05-23T02:25:34.621619Z"
}
},
"cell_type": "code",
@@ -63,13 +63,13 @@
],
"id": "1ebf43316efee835",
"outputs": [],
- "execution_count": 93
+ "execution_count": 17
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:13:15.489337Z",
- "start_time": "2025-05-23T01:13:15.485019Z"
+ "end_time": "2025-05-23T02:25:34.640874Z",
+ "start_time": "2025-05-23T02:25:34.636086Z"
}
},
"cell_type": "code",
@@ -89,18 +89,18 @@
"31-MAR-2024"
]
},
- "execution_count": 94,
+ "execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 94
+ "execution_count": 18
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:13:18.003794Z",
- "start_time": "2025-05-23T01:13:17.998703Z"
+ "end_time": "2025-05-23T02:25:34.675868Z",
+ "start_time": "2025-05-23T02:25:34.663679Z"
}
},
"cell_type": "code",
@@ -123,13 +123,13 @@
],
"id": "290b7a06932da41d",
"outputs": [],
- "execution_count": 95
+ "execution_count": 19
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:13:19.311195Z",
- "start_time": "2025-05-23T01:13:19.307399Z"
+ "end_time": "2025-05-23T02:25:34.693421Z",
+ "start_time": "2025-05-23T02:25:34.686347Z"
}
},
"cell_type": "code",
@@ -142,18 +142,18 @@
"0.030065619962567392"
]
},
- "execution_count": 96,
+ "execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 96
+ "execution_count": 20
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:13:29.846190Z",
- "start_time": "2025-05-23T01:13:29.841877Z"
+ "end_time": "2025-05-23T02:25:34.722494Z",
+ "start_time": "2025-05-23T02:25:34.715862Z"
}
},
"cell_type": "code",
@@ -197,13 +197,13 @@
],
"id": "65a401442f9bf084",
"outputs": [],
- "execution_count": 98
+ "execution_count": 21
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:13:32.846466Z",
- "start_time": "2025-05-23T01:13:32.841730Z"
+ "end_time": "2025-05-23T02:25:34.740382Z",
+ "start_time": "2025-05-23T02:25:34.734050Z"
}
},
"cell_type": "code",
@@ -216,18 +216,18 @@
"-404094.769553849"
]
},
- "execution_count": 99,
+ "execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 99
+ "execution_count": 22
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:23:14.567789Z",
- "start_time": "2025-05-23T01:23:14.556465Z"
+ "end_time": "2025-05-23T02:25:34.769581Z",
+ "start_time": "2025-05-23T02:25:34.763504Z"
}
},
"cell_type": "code",
@@ -235,96 +235,95 @@
"id": "3f988f26e6662203",
"outputs": [
{
- "ename": "TypeError",
- "evalue": "IborSwap.payer_side_macaulay_duration() takes 3 positional arguments but 4 were given",
- "output_type": "error",
- "traceback": [
- "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
- "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)",
- "Cell \u001B[1;32mIn[107], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mswap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mpayer_side_macaulay_duration\u001B[49m\u001B[43m(\u001B[49m\u001B[43mvalue_dt\u001B[49m\u001B[43m,\u001B[49m\u001B[43mzero_curve\u001B[49m\u001B[43m,\u001B[49m\u001B[38;5;241;43m8\u001B[39;49m\u001B[43m)\u001B[49m\n",
- "\u001B[1;31mTypeError\u001B[0m: IborSwap.payer_side_macaulay_duration() takes 3 positional arguments but 4 were given"
- ]
+ "data": {
+ "text/plain": [
+ "-6.794198629548404"
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
}
],
- "execution_count": 107
+ "execution_count": 23
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T00:45:15.232484600Z",
- "start_time": "2025-05-23T00:39:29.952636Z"
+ "end_time": "2025-05-23T02:25:34.803424Z",
+ "start_time": "2025-05-23T02:25:34.798626Z"
}
},
"cell_type": "code",
- "source": "swap.receiver_side_macaulay_duration(value_dt, zero_curve)",
+ "source": "swap.receiver_side_macaulay_duration(value_dt, zero_curve,8)",
"id": "96d568f7a71861fe",
"outputs": [
{
"data": {
"text/plain": [
- "5.84526657803498"
+ "6.794198629548404"
]
},
- "execution_count": 55,
+ "execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 55
+ "execution_count": 24
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T00:45:15.232484600Z",
- "start_time": "2025-05-23T00:39:30.019485Z"
+ "end_time": "2025-05-23T02:25:34.836332Z",
+ "start_time": "2025-05-23T02:25:34.831799Z"
}
},
"cell_type": "code",
- "source": "swap.payer_side_modified_duration(value_dt, zero_curve)",
+ "source": "swap.payer_side_modified_duration(value_dt, zero_curve,8)",
"id": "ec2187c7336c1bc3",
"outputs": [
{
"data": {
"text/plain": [
- "-5.801658959676467"
+ "-6.743511664816526"
]
},
- "execution_count": 56,
+ "execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 56
+ "execution_count": 25
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T00:45:15.238495100Z",
- "start_time": "2025-05-23T00:39:30.068245Z"
+ "end_time": "2025-05-23T02:25:34.864470Z",
+ "start_time": "2025-05-23T02:25:34.860289Z"
}
},
"cell_type": "code",
- "source": "swap.receiver_side_modified_duration(value_dt, zero_curve)",
+ "source": "swap.receiver_side_modified_duration(value_dt, zero_curve,8)",
"id": "2c1b845afaf5e18f",
"outputs": [
{
"data": {
"text/plain": [
- "5.801658959676467"
+ "6.743511664816526"
]
},
- "execution_count": 57,
+ "execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 57
+ "execution_count": 26
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T00:45:15.239505100Z",
- "start_time": "2025-05-23T00:39:30.125510Z"
+ "end_time": "2025-05-23T02:25:34.895364Z",
+ "start_time": "2025-05-23T02:25:34.888381Z"
}
},
"cell_type": "code",
@@ -374,13 +373,13 @@
]
}
],
- "execution_count": 58
+ "execution_count": 27
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T00:45:15.239505100Z",
- "start_time": "2025-05-23T00:39:30.159010Z"
+ "end_time": "2025-05-23T02:25:34.923991Z",
+ "start_time": "2025-05-23T02:25:34.918594Z"
}
},
"cell_type": "code",
@@ -412,13 +411,13 @@
]
}
],
- "execution_count": 59
+ "execution_count": 28
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T00:45:15.240494900Z",
- "start_time": "2025-05-23T00:39:30.197673Z"
+ "end_time": "2025-05-23T02:25:35.017712Z",
+ "start_time": "2025-05-23T02:25:35.013394Z"
}
},
"cell_type": "code",
@@ -450,7 +449,32 @@
]
}
],
- "execution_count": 60
+ "execution_count": 29
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T02:25:35.127867Z",
+ "start_time": "2025-05-23T02:25:35.115423Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.payer_side_profits(value_dt, zero_curve,8,-0.004)",
+ "id": "5ef5f29ad5dfad00",
+ "outputs": [
+ {
+ "ename": "AttributeError",
+ "evalue": "'IborSwap' object has no attribute 'payer_side_profits'",
+ "output_type": "error",
+ "traceback": [
+ "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
+ "\u001B[1;31mAttributeError\u001B[0m Traceback (most recent call last)",
+ "Cell \u001B[1;32mIn[30], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mswap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mpayer_side_profits\u001B[49m(value_dt, zero_curve,\u001B[38;5;241m8\u001B[39m,\u001B[38;5;241m-\u001B[39m\u001B[38;5;241m0.004\u001B[39m)\n",
+ "\u001B[1;31mAttributeError\u001B[0m: 'IborSwap' object has no attribute 'payer_side_profits'"
+ ]
+ }
+ ],
+ "execution_count": 30
}
],
"metadata": {
From 9275b9322393931cedb501e03d6ecda5b09eb1c6 Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Fri, 23 May 2025 10:44:16 +0800
Subject: [PATCH 05/12] add BPV for payer and receiver
---
financepy/products/rates/ibor_swap.py | 33 ++++
...eplicationgBONDMATHDurationExample3M.ipynb | 165 ++++++------------
2 files changed, 90 insertions(+), 108 deletions(-)
diff --git a/financepy/products/rates/ibor_swap.py b/financepy/products/rates/ibor_swap.py
index ffcf2b01..c65910e1 100644
--- a/financepy/products/rates/ibor_swap.py
+++ b/financepy/products/rates/ibor_swap.py
@@ -458,9 +458,42 @@ def payer_side_profits(self,
"""
# Get coupon frequency
coupon_frequency = self.fixed_leg.freq_type.value
+
annualized_modi_dur = self.payer_side_modified_duration(value_dt, discount_curve,payment_periods)/coupon_frequency
return (-1)*(annualized_modi_dur*self.fixed_leg.notional*swap_rate_changes)
+ ###########################################################################
+
+ def receiver_side_profits(self,
+ value_dt,
+ discount_curve,payment_periods: float,
+ swap_rate_changes: float):
+ """Computation of the Profits for the Fixed-Rate Receiver's Perspective in Interest Rate Swap
+ """
+ return self.payer_side_profits(value_dt, discount_curve,payment_periods,swap_rate_changes)*(-1)
+
+ ###########################################################################
+
+ def payer_side_BPV(self, value_dt, discount_curve,payment_periods: float,):
+ """
+ calculate the basis‐point‐value (BPV) for the payer_side of the swap,
+ which is swap's modified duration times the notional principal,
+ times one basis point (0.0001)
+ """
+ bp=0.0001
+ return self.payer_side_modified_duration(value_dt, discount_curve,payment_periods)*self.fixed_leg.notional*bp
+
+ ###########################################################################
+
+ def receiver_side_BPV(self, value_dt, discount_curve,payment_periods: float,):
+ """
+ calculate the basis‐point‐value (BPV) for receiver_side of the swap,
+ which is swap's modified duration times the notional principal,
+ times one basis point (0.0001)
+ """
+ return self.payer_side_BPV(value_dt, discount_curve,payment_periods)*(-1)
+
+ ###########################################################################
def __repr__(self):
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
index d377e7bb..0b7a1adf 100644
--- a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
@@ -6,8 +6,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.603675Z",
- "start_time": "2025-05-23T02:25:34.599467Z"
+ "end_time": "2025-05-23T02:31:22.631355Z",
+ "start_time": "2025-05-23T02:31:22.625849Z"
}
},
"source": [
@@ -17,13 +17,13 @@
"import datetime as dt"
],
"outputs": [],
- "execution_count": 16
+ "execution_count": 2
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.630084Z",
- "start_time": "2025-05-23T02:25:34.621619Z"
+ "end_time": "2025-05-23T02:31:22.679560Z",
+ "start_time": "2025-05-23T02:31:22.657680Z"
}
},
"cell_type": "code",
@@ -63,13 +63,13 @@
],
"id": "1ebf43316efee835",
"outputs": [],
- "execution_count": 17
+ "execution_count": 3
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.640874Z",
- "start_time": "2025-05-23T02:25:34.636086Z"
+ "end_time": "2025-05-23T02:31:22.694667Z",
+ "start_time": "2025-05-23T02:31:22.687165Z"
}
},
"cell_type": "code",
@@ -89,18 +89,18 @@
"31-MAR-2024"
]
},
- "execution_count": 18,
+ "execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 18
+ "execution_count": 4
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.675868Z",
- "start_time": "2025-05-23T02:25:34.663679Z"
+ "end_time": "2025-05-23T02:31:22.727011Z",
+ "start_time": "2025-05-23T02:31:22.719602Z"
}
},
"cell_type": "code",
@@ -123,13 +123,13 @@
],
"id": "290b7a06932da41d",
"outputs": [],
- "execution_count": 19
+ "execution_count": 5
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.693421Z",
- "start_time": "2025-05-23T02:25:34.686347Z"
+ "end_time": "2025-05-23T02:31:22.746919Z",
+ "start_time": "2025-05-23T02:31:22.739589Z"
}
},
"cell_type": "code",
@@ -142,68 +142,18 @@
"0.030065619962567392"
]
},
- "execution_count": 20,
+ "execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 20
+ "execution_count": 6
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.722494Z",
- "start_time": "2025-05-23T02:25:34.715862Z"
- }
- },
- "cell_type": "code",
- "source": [
- "# def payer_side_macaulay_duration(value_dt, discount_curve):\n",
- "# \"\"\"Calculation of the Payer's Macaulay Duration in an Interest Rate Swap\n",
- "# Based on Bond Math: The Theory Behind the Formulas, Second Edition by\n",
- "# Donald J. Smith\n",
- "# \"\"\"\n",
- "# # Number of fixed leg payments\n",
- "# payment_period = len(swap.fixed_leg.payments)\n",
- "#\n",
- "# # Get coupon frequency\n",
- "# coupon_frequency = self.fixed_leg.freq_type.value\n",
- "#\n",
- "# # Get swap rate\n",
- "# swap_rate_val = self.swap_rate(value_dt, discount_curve)\n",
- "#\n",
- "# y = swap_rate_val / coupon_frequency\n",
- "# N = payment_period\n",
- "# c = swap_rate_val / coupon_frequency\n",
- "# md1 = (1 + y) / y\n",
- "# md2 = 1 + y + (N * (c - y))\n",
- "# md3 = c * ((1 + y) ** N - 1) + y\n",
- "# mac_duration = 1 - (md1 - md2 / md3)\n",
- "# return mac_duration\n",
- "\n",
- "\n",
- "payment_period = len(swap.fixed_leg.payments) + 1\n",
- "coupon_frequency = swap.fixed_leg.freq_type.value\n",
- "swap_rate_val = swap.swap_rate(value_dt, zero_curve)\n",
- "y = swap_rate_val / coupon_frequency\n",
- "N = payment_period\n",
- "c = swap_rate_val / coupon_frequency\n",
- "md1 = (1 + y) / y\n",
- "md2 = 1 + y + (N * (c - y))\n",
- "md3 = c * ((1 + y) ** N - 1) + y\n",
- "mac_duration = 1 - (md1 - md2 / md3)\n",
- "\n",
- "delta_mv=-(-mac_duration/4*notional*(-0.004))"
- ],
- "id": "65a401442f9bf084",
- "outputs": [],
- "execution_count": 21
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.740382Z",
- "start_time": "2025-05-23T02:25:34.734050Z"
+ "end_time": "2025-05-23T02:31:22.765913Z",
+ "start_time": "2025-05-23T02:31:22.759349Z"
}
},
"cell_type": "code",
@@ -216,18 +166,18 @@
"-404094.769553849"
]
},
- "execution_count": 22,
+ "execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 22
+ "execution_count": 7
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.769581Z",
- "start_time": "2025-05-23T02:25:34.763504Z"
+ "end_time": "2025-05-23T02:31:22.784960Z",
+ "start_time": "2025-05-23T02:31:22.779808Z"
}
},
"cell_type": "code",
@@ -240,18 +190,18 @@
"-6.794198629548404"
]
},
- "execution_count": 23,
+ "execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 23
+ "execution_count": 8
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.803424Z",
- "start_time": "2025-05-23T02:25:34.798626Z"
+ "end_time": "2025-05-23T02:31:22.817161Z",
+ "start_time": "2025-05-23T02:31:22.812093Z"
}
},
"cell_type": "code",
@@ -264,18 +214,18 @@
"6.794198629548404"
]
},
- "execution_count": 24,
+ "execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 24
+ "execution_count": 9
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.836332Z",
- "start_time": "2025-05-23T02:25:34.831799Z"
+ "end_time": "2025-05-23T02:31:22.858301Z",
+ "start_time": "2025-05-23T02:31:22.853154Z"
}
},
"cell_type": "code",
@@ -288,18 +238,18 @@
"-6.743511664816526"
]
},
- "execution_count": 25,
+ "execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 25
+ "execution_count": 10
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.864470Z",
- "start_time": "2025-05-23T02:25:34.860289Z"
+ "end_time": "2025-05-23T02:31:22.894478Z",
+ "start_time": "2025-05-23T02:31:22.889858Z"
}
},
"cell_type": "code",
@@ -312,18 +262,18 @@
"6.743511664816526"
]
},
- "execution_count": 26,
+ "execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 26
+ "execution_count": 11
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.895364Z",
- "start_time": "2025-05-23T02:25:34.888381Z"
+ "end_time": "2025-05-23T02:31:22.942622Z",
+ "start_time": "2025-05-23T02:31:22.937046Z"
}
},
"cell_type": "code",
@@ -373,13 +323,13 @@
]
}
],
- "execution_count": 27
+ "execution_count": 12
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:34.923991Z",
- "start_time": "2025-05-23T02:25:34.918594Z"
+ "end_time": "2025-05-23T02:31:22.977499Z",
+ "start_time": "2025-05-23T02:31:22.971711Z"
}
},
"cell_type": "code",
@@ -411,13 +361,13 @@
]
}
],
- "execution_count": 28
+ "execution_count": 13
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:35.017712Z",
- "start_time": "2025-05-23T02:25:35.013394Z"
+ "end_time": "2025-05-23T02:31:23.015658Z",
+ "start_time": "2025-05-23T02:31:23.010172Z"
}
},
"cell_type": "code",
@@ -449,13 +399,13 @@
]
}
],
- "execution_count": 29
+ "execution_count": 14
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:25:35.127867Z",
- "start_time": "2025-05-23T02:25:35.115423Z"
+ "end_time": "2025-05-23T02:31:23.043840Z",
+ "start_time": "2025-05-23T02:31:23.039172Z"
}
},
"cell_type": "code",
@@ -463,18 +413,17 @@
"id": "5ef5f29ad5dfad00",
"outputs": [
{
- "ename": "AttributeError",
- "evalue": "'IborSwap' object has no attribute 'payer_side_profits'",
- "output_type": "error",
- "traceback": [
- "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
- "\u001B[1;31mAttributeError\u001B[0m Traceback (most recent call last)",
- "Cell \u001B[1;32mIn[30], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mswap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mpayer_side_profits\u001B[49m(value_dt, zero_curve,\u001B[38;5;241m8\u001B[39m,\u001B[38;5;241m-\u001B[39m\u001B[38;5;241m0.004\u001B[39m)\n",
- "\u001B[1;31mAttributeError\u001B[0m: 'IborSwap' object has no attribute 'payer_side_profits'"
- ]
+ "data": {
+ "text/plain": [
+ "-404610.6998889916"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
}
],
- "execution_count": 30
+ "execution_count": 15
}
],
"metadata": {
From 0cfcc73a4fd697069c528d570076b28dd1dc53e5 Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Fri, 23 May 2025 10:55:41 +0800
Subject: [PATCH 06/12] modified BPV calculation
---
financepy/products/rates/ibor_swap.py | 3 +-
...eplicationgBONDMATHDurationExample3M.ipynb | 182 +++++++++++++-----
2 files changed, 132 insertions(+), 53 deletions(-)
diff --git a/financepy/products/rates/ibor_swap.py b/financepy/products/rates/ibor_swap.py
index c65910e1..e3247417 100644
--- a/financepy/products/rates/ibor_swap.py
+++ b/financepy/products/rates/ibor_swap.py
@@ -481,7 +481,8 @@ def payer_side_BPV(self, value_dt, discount_curve,payment_periods: float,):
times one basis point (0.0001)
"""
bp=0.0001
- return self.payer_side_modified_duration(value_dt, discount_curve,payment_periods)*self.fixed_leg.notional*bp
+ modi_dur = self.payer_side_modified_duration(value_dt, discount_curve,payment_periods)
+ return modi_dur*self.fixed_leg.notional*bp
###########################################################################
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
index 0b7a1adf..e2759851 100644
--- a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
@@ -6,24 +6,26 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.631355Z",
- "start_time": "2025-05-23T02:31:22.625849Z"
+ "end_time": "2025-05-23T02:54:25.031837Z",
+ "start_time": "2025-05-23T02:54:25.027815Z"
}
},
"source": [
"from financepy.utils import *\n",
"from financepy.products.rates import *\n",
"from financepy.market.curves import *\n",
- "import datetime as dt"
+ "import datetime as dt\n",
+ "\n",
+ "from notebooks.products.rates.FINIBORSWAP_ReplicationgBONDMATHDurationExample import payment_periods"
],
"outputs": [],
- "execution_count": 2
+ "execution_count": 34
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.679560Z",
- "start_time": "2025-05-23T02:31:22.657680Z"
+ "end_time": "2025-05-23T02:54:25.043454Z",
+ "start_time": "2025-05-23T02:54:25.039940Z"
}
},
"cell_type": "code",
@@ -63,13 +65,13 @@
],
"id": "1ebf43316efee835",
"outputs": [],
- "execution_count": 3
+ "execution_count": 35
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.694667Z",
- "start_time": "2025-05-23T02:31:22.687165Z"
+ "end_time": "2025-05-23T02:54:25.056980Z",
+ "start_time": "2025-05-23T02:54:25.052895Z"
}
},
"cell_type": "code",
@@ -89,18 +91,18 @@
"31-MAR-2024"
]
},
- "execution_count": 4,
+ "execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 4
+ "execution_count": 36
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.727011Z",
- "start_time": "2025-05-23T02:31:22.719602Z"
+ "end_time": "2025-05-23T02:54:25.078736Z",
+ "start_time": "2025-05-23T02:54:25.073700Z"
}
},
"cell_type": "code",
@@ -123,13 +125,13 @@
],
"id": "290b7a06932da41d",
"outputs": [],
- "execution_count": 5
+ "execution_count": 37
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.746919Z",
- "start_time": "2025-05-23T02:31:22.739589Z"
+ "end_time": "2025-05-23T02:54:25.092695Z",
+ "start_time": "2025-05-23T02:54:25.087190Z"
}
},
"cell_type": "code",
@@ -142,18 +144,18 @@
"0.030065619962567392"
]
},
- "execution_count": 6,
+ "execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 6
+ "execution_count": 38
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.765913Z",
- "start_time": "2025-05-23T02:31:22.759349Z"
+ "end_time": "2025-05-23T02:54:25.120452Z",
+ "start_time": "2025-05-23T02:54:25.116135Z"
}
},
"cell_type": "code",
@@ -166,18 +168,18 @@
"-404094.769553849"
]
},
- "execution_count": 7,
+ "execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 7
+ "execution_count": 39
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.784960Z",
- "start_time": "2025-05-23T02:31:22.779808Z"
+ "end_time": "2025-05-23T02:54:25.148481Z",
+ "start_time": "2025-05-23T02:54:25.143313Z"
}
},
"cell_type": "code",
@@ -190,18 +192,18 @@
"-6.794198629548404"
]
},
- "execution_count": 8,
+ "execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 8
+ "execution_count": 40
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.817161Z",
- "start_time": "2025-05-23T02:31:22.812093Z"
+ "end_time": "2025-05-23T02:54:25.169741Z",
+ "start_time": "2025-05-23T02:54:25.164469Z"
}
},
"cell_type": "code",
@@ -214,18 +216,18 @@
"6.794198629548404"
]
},
- "execution_count": 9,
+ "execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 9
+ "execution_count": 41
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.858301Z",
- "start_time": "2025-05-23T02:31:22.853154Z"
+ "end_time": "2025-05-23T02:54:25.199176Z",
+ "start_time": "2025-05-23T02:54:25.193898Z"
}
},
"cell_type": "code",
@@ -238,18 +240,18 @@
"-6.743511664816526"
]
},
- "execution_count": 10,
+ "execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 10
+ "execution_count": 42
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.894478Z",
- "start_time": "2025-05-23T02:31:22.889858Z"
+ "end_time": "2025-05-23T02:54:25.228763Z",
+ "start_time": "2025-05-23T02:54:25.224367Z"
}
},
"cell_type": "code",
@@ -262,18 +264,18 @@
"6.743511664816526"
]
},
- "execution_count": 11,
+ "execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 11
+ "execution_count": 43
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.942622Z",
- "start_time": "2025-05-23T02:31:22.937046Z"
+ "end_time": "2025-05-23T02:54:25.264697Z",
+ "start_time": "2025-05-23T02:54:25.260233Z"
}
},
"cell_type": "code",
@@ -323,13 +325,13 @@
]
}
],
- "execution_count": 12
+ "execution_count": 44
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:22.977499Z",
- "start_time": "2025-05-23T02:31:22.971711Z"
+ "end_time": "2025-05-23T02:54:25.286790Z",
+ "start_time": "2025-05-23T02:54:25.282897Z"
}
},
"cell_type": "code",
@@ -361,13 +363,13 @@
]
}
],
- "execution_count": 13
+ "execution_count": 45
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:23.015658Z",
- "start_time": "2025-05-23T02:31:23.010172Z"
+ "end_time": "2025-05-23T02:54:25.315781Z",
+ "start_time": "2025-05-23T02:54:25.311063Z"
}
},
"cell_type": "code",
@@ -399,17 +401,21 @@
]
}
],
- "execution_count": 14
+ "execution_count": 46
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:31:23.043840Z",
- "start_time": "2025-05-23T02:31:23.039172Z"
+ "end_time": "2025-05-23T02:54:25.345988Z",
+ "start_time": "2025-05-23T02:54:25.341966Z"
}
},
"cell_type": "code",
- "source": "swap.payer_side_profits(value_dt, zero_curve,8,-0.004)",
+ "source": [
+ "payment_periods=8\n",
+ "swap_rate_changes=-0.004\n",
+ "swap.payer_side_profits(value_dt, zero_curve,payment_periods,swap_rate_changes)"
+ ],
"id": "5ef5f29ad5dfad00",
"outputs": [
{
@@ -418,12 +424,84 @@
"-404610.6998889916"
]
},
- "execution_count": 15,
+ "execution_count": 47,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 47
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T02:54:25.433818Z",
+ "start_time": "2025-05-23T02:54:25.427828Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.receiver_side_profits(value_dt, zero_curve,payment_periods,swap_rate_changes)",
+ "id": "11109a6f2da7b7dc",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "404610.6998889916"
+ ]
+ },
+ "execution_count": 48,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 48
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T02:54:25.518531Z",
+ "start_time": "2025-05-23T02:54:25.513863Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.payer_side_BPV(value_dt, zero_curve,payment_periods)",
+ "id": "a4c532a9a90b445c",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-40461.06998889916"
+ ]
+ },
+ "execution_count": 49,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 49
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T02:54:25.578843Z",
+ "start_time": "2025-05-23T02:54:25.574712Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "swap.receiver_side_BPV(value_dt, zero_curve,payment_periods)",
+ "id": "8f8630e90883e3b5",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "40461.06998889916"
+ ]
+ },
+ "execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 15
+ "execution_count": 50
}
],
"metadata": {
From 59558be0ea5fe1b29e168666d67bce4ba0da815f Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Fri, 23 May 2025 11:07:28 +0800
Subject: [PATCH 07/12] modified BPV calculation
---
financepy/products/rates/ibor_swap.py | 5 +-
...eplicationgBONDMATHDurationExample3M.ipynb | 141 ++++++++----------
2 files changed, 69 insertions(+), 77 deletions(-)
diff --git a/financepy/products/rates/ibor_swap.py b/financepy/products/rates/ibor_swap.py
index e3247417..c57566c8 100644
--- a/financepy/products/rates/ibor_swap.py
+++ b/financepy/products/rates/ibor_swap.py
@@ -481,8 +481,11 @@ def payer_side_BPV(self, value_dt, discount_curve,payment_periods: float,):
times one basis point (0.0001)
"""
bp=0.0001
+ # Get coupon frequency
+ coupon_frequency = self.fixed_leg.freq_type.value
modi_dur = self.payer_side_modified_duration(value_dt, discount_curve,payment_periods)
- return modi_dur*self.fixed_leg.notional*bp
+ annualized_modi_dur= modi_dur/coupon_frequency
+ return annualized_modi_dur*self.fixed_leg.notional*bp
###########################################################################
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
index e2759851..ca5a8b00 100644
--- a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
@@ -6,26 +6,24 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.031837Z",
- "start_time": "2025-05-23T02:54:25.027815Z"
+ "end_time": "2025-05-23T03:01:38.516595Z",
+ "start_time": "2025-05-23T03:01:38.512089Z"
}
},
"source": [
"from financepy.utils import *\n",
"from financepy.products.rates import *\n",
"from financepy.market.curves import *\n",
- "import datetime as dt\n",
- "\n",
- "from notebooks.products.rates.FINIBORSWAP_ReplicationgBONDMATHDurationExample import payment_periods"
+ "import datetime as dt\n"
],
"outputs": [],
- "execution_count": 34
+ "execution_count": 22
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.043454Z",
- "start_time": "2025-05-23T02:54:25.039940Z"
+ "end_time": "2025-05-23T03:01:38.528444Z",
+ "start_time": "2025-05-23T03:01:38.524597Z"
}
},
"cell_type": "code",
@@ -65,13 +63,13 @@
],
"id": "1ebf43316efee835",
"outputs": [],
- "execution_count": 35
+ "execution_count": 23
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.056980Z",
- "start_time": "2025-05-23T02:54:25.052895Z"
+ "end_time": "2025-05-23T03:01:38.542275Z",
+ "start_time": "2025-05-23T03:01:38.537531Z"
}
},
"cell_type": "code",
@@ -91,18 +89,18 @@
"31-MAR-2024"
]
},
- "execution_count": 36,
+ "execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 36
+ "execution_count": 24
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.078736Z",
- "start_time": "2025-05-23T02:54:25.073700Z"
+ "end_time": "2025-05-23T03:01:38.569014Z",
+ "start_time": "2025-05-23T03:01:38.564129Z"
}
},
"cell_type": "code",
@@ -125,13 +123,13 @@
],
"id": "290b7a06932da41d",
"outputs": [],
- "execution_count": 37
+ "execution_count": 25
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.092695Z",
- "start_time": "2025-05-23T02:54:25.087190Z"
+ "end_time": "2025-05-23T03:01:38.585724Z",
+ "start_time": "2025-05-23T03:01:38.579955Z"
}
},
"cell_type": "code",
@@ -144,18 +142,18 @@
"0.030065619962567392"
]
},
- "execution_count": 38,
+ "execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 38
+ "execution_count": 26
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.120452Z",
- "start_time": "2025-05-23T02:54:25.116135Z"
+ "end_time": "2025-05-23T03:01:38.610747Z",
+ "start_time": "2025-05-23T03:01:38.606021Z"
}
},
"cell_type": "code",
@@ -168,18 +166,18 @@
"-404094.769553849"
]
},
- "execution_count": 39,
+ "execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 39
+ "execution_count": 27
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.148481Z",
- "start_time": "2025-05-23T02:54:25.143313Z"
+ "end_time": "2025-05-23T03:01:38.645126Z",
+ "start_time": "2025-05-23T03:01:38.640384Z"
}
},
"cell_type": "code",
@@ -192,18 +190,18 @@
"-6.794198629548404"
]
},
- "execution_count": 40,
+ "execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 40
+ "execution_count": 28
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.169741Z",
- "start_time": "2025-05-23T02:54:25.164469Z"
+ "end_time": "2025-05-23T03:01:38.686342Z",
+ "start_time": "2025-05-23T03:01:38.681347Z"
}
},
"cell_type": "code",
@@ -216,18 +214,18 @@
"6.794198629548404"
]
},
- "execution_count": 41,
+ "execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 41
+ "execution_count": 29
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.199176Z",
- "start_time": "2025-05-23T02:54:25.193898Z"
+ "end_time": "2025-05-23T03:01:38.722907Z",
+ "start_time": "2025-05-23T03:01:38.717909Z"
}
},
"cell_type": "code",
@@ -240,18 +238,18 @@
"-6.743511664816526"
]
},
- "execution_count": 42,
+ "execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 42
+ "execution_count": 30
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.228763Z",
- "start_time": "2025-05-23T02:54:25.224367Z"
+ "end_time": "2025-05-23T03:01:38.756278Z",
+ "start_time": "2025-05-23T03:01:38.751727Z"
}
},
"cell_type": "code",
@@ -264,18 +262,18 @@
"6.743511664816526"
]
},
- "execution_count": 43,
+ "execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 43
+ "execution_count": 31
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.264697Z",
- "start_time": "2025-05-23T02:54:25.260233Z"
+ "end_time": "2025-05-23T03:01:38.790007Z",
+ "start_time": "2025-05-23T03:01:38.786002Z"
}
},
"cell_type": "code",
@@ -325,13 +323,13 @@
]
}
],
- "execution_count": 44
+ "execution_count": 32
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.286790Z",
- "start_time": "2025-05-23T02:54:25.282897Z"
+ "end_time": "2025-05-23T03:01:38.821049Z",
+ "start_time": "2025-05-23T03:01:38.816897Z"
}
},
"cell_type": "code",
@@ -363,13 +361,13 @@
]
}
],
- "execution_count": 45
+ "execution_count": 33
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.315781Z",
- "start_time": "2025-05-23T02:54:25.311063Z"
+ "end_time": "2025-05-23T03:01:38.907291Z",
+ "start_time": "2025-05-23T03:01:38.903054Z"
}
},
"cell_type": "code",
@@ -401,13 +399,13 @@
]
}
],
- "execution_count": 46
+ "execution_count": 34
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.345988Z",
- "start_time": "2025-05-23T02:54:25.341966Z"
+ "end_time": "2025-05-23T03:01:39.014637Z",
+ "start_time": "2025-05-23T03:01:39.009932Z"
}
},
"cell_type": "code",
@@ -424,18 +422,18 @@
"-404610.6998889916"
]
},
- "execution_count": 47,
+ "execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 47
+ "execution_count": 35
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.433818Z",
- "start_time": "2025-05-23T02:54:25.427828Z"
+ "end_time": "2025-05-23T03:01:39.056730Z",
+ "start_time": "2025-05-23T03:01:39.050609Z"
}
},
"cell_type": "code",
@@ -448,18 +446,18 @@
"404610.6998889916"
]
},
- "execution_count": 48,
+ "execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 48
+ "execution_count": 36
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.518531Z",
- "start_time": "2025-05-23T02:54:25.513863Z"
+ "end_time": "2025-05-23T03:01:39.100675Z",
+ "start_time": "2025-05-23T03:01:39.095809Z"
}
},
"cell_type": "code",
@@ -472,36 +470,27 @@
"-40461.06998889916"
]
},
- "execution_count": 49,
+ "execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 49
+ "execution_count": 37
},
{
"metadata": {
+ "jupyter": {
+ "is_executing": true
+ },
"ExecuteTime": {
- "end_time": "2025-05-23T02:54:25.578843Z",
- "start_time": "2025-05-23T02:54:25.574712Z"
+ "start_time": "2025-05-23T03:01:55.128551Z"
}
},
"cell_type": "code",
"source": "swap.receiver_side_BPV(value_dt, zero_curve,payment_periods)",
"id": "8f8630e90883e3b5",
- "outputs": [
- {
- "data": {
- "text/plain": [
- "40461.06998889916"
- ]
- },
- "execution_count": 50,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 50
+ "outputs": [],
+ "execution_count": null
}
],
"metadata": {
From 7b3572d287ea6946111e7bf4025e37b58511a531 Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Fri, 23 May 2025 14:53:44 +0800
Subject: [PATCH 08/12] Calculate IRS Duration & Metrics vs. Bond Math Case
---
..._ReplicationgBONDMATHDurationExample.ipynb | 669 +++++++++++-------
...eplicationgBONDMATHDurationExample3M.ipynb | 272 +++----
2 files changed, 505 insertions(+), 436 deletions(-)
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
index 724c6aa6..f42cf92e 100644
--- a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
@@ -6,8 +6,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-05-23T01:37:56.175867Z",
- "start_time": "2025-05-23T01:37:56.171771Z"
+ "end_time": "2025-05-23T06:49:48.974729Z",
+ "start_time": "2025-05-23T06:49:48.971287Z"
}
},
"source": [
@@ -15,16 +15,57 @@
"from financepy.products.rates import *\n",
"from financepy.market.curves import *\n",
"import datetime as dt\n",
- "\n"
+ "import numpy as np"
],
"outputs": [],
- "execution_count": 2
+ "execution_count": 101
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:37:57.664887Z",
- "start_time": "2025-05-23T01:37:57.637136Z"
+ "end_time": "2025-05-23T06:49:49.013677Z",
+ "start_time": "2025-05-23T06:49:49.009267Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ " \"\"\"\n",
+ "Calculating the Duration and Other Interest Rate Sensitivity Metrics in an Interest Rate Swap\n",
+ "Based on Bond Math: The Theory Behind the Formulas, Second Edition by Donald J. Smith\n",
+ " \"\"\""
+ ],
+ "id": "1771696c9beba73c",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'\\nCalculating the Duration and Other Interest Rate Sensitivity Metrics in an Interest Rate Swap\\nBased on Bond Math: The Theory Behind the Formulas, Second Edition by Donald J. Smith\\n'"
+ ]
+ },
+ "execution_count": 102,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 102
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "# 1.Interest rate swaps at the beginning",
+ "id": "c710af2d079e815d"
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "## Define the swap",
+ "id": "e606fc8bae71cc9e"
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-23T06:49:49.022425Z",
+ "start_time": "2025-05-23T06:49:49.018680Z"
}
},
"cell_type": "code",
@@ -33,7 +74,6 @@
"bd_type = BusDayAdjustTypes.FOLLOWING\n",
"dg_type = DateGenRuleTypes.BACKWARD\n",
"\n",
- "\n",
"fixed_cpn = 0.034\n",
"fixed_freq_type = FrequencyTypes.QUARTERLY\n",
"fixed_dc_type = DayCountTypes.THIRTY_360_BOND\n",
@@ -64,38 +104,42 @@
],
"id": "1ebf43316efee835",
"outputs": [],
- "execution_count": 3
+ "execution_count": 103
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:38:00.243014Z",
- "start_time": "2025-05-23T01:38:00.238262Z"
+ "end_time": "2025-05-23T06:49:49.040866Z",
+ "start_time": "2025-05-23T06:49:49.037306Z"
}
},
"cell_type": "code",
"source": [
- "value_date= dt.datetime(2023,12,31)\n",
+ "value_date = dt.datetime(2023, 12, 31)\n",
"value_dt = from_datetime(value_date)\n",
- "\n",
- "settle_dt = value_dt.add_weekdays(0)\n",
- "# settle_dt=value_dt"
+ "settle_dt = value_dt.add_weekdays(0)\n"
],
"id": "8e46f142f3cba5d7",
"outputs": [],
- "execution_count": 4
+ "execution_count": 104
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "## Define the yield curve",
+ "id": "9e298d9eeefb972a"
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:38:01.679542Z",
- "start_time": "2025-05-23T01:38:01.673799Z"
+ "end_time": "2025-05-23T06:49:49.057895Z",
+ "start_time": "2025-05-23T06:49:49.053646Z"
}
},
"cell_type": "code",
"source": [
- "yield_curve=[i/100 for i in [0.5,1.0407,1.5829,2.1271,2.4506,2.7756,3.1025,3.4316]]\n",
- "zero_dts=value_dt.add_years([0.25,0.5,0.75,1.0,1.25,1.5,1.75,2.0])\n",
+ "yield_curve = [i / 100 for i in [0.5, 1.0407, 1.5829, 2.1271, 2.4506, 2.7756, 3.1025, 3.4316]]\n",
+ "zero_dts = value_dt.add_years([0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0])\n",
"\n",
"zero_curve = DiscountCurveZeros(value_dt=value_dt,\n",
" zero_dts=zero_dts,\n",
@@ -107,17 +151,26 @@
],
"id": "290b7a06932da41d",
"outputs": [],
- "execution_count": 5
+ "execution_count": 105
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "## Calculate the swap rate and sensitivity indicators",
+ "id": "de6b6c0c33f6f4a6"
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:38:03.960837Z",
- "start_time": "2025-05-23T01:38:03.952526Z"
+ "end_time": "2025-05-23T06:49:49.073393Z",
+ "start_time": "2025-05-23T06:49:49.068617Z"
}
},
"cell_type": "code",
- "source": "swap.swap_rate(value_dt, zero_curve)",
+ "source": [
+ "swap_rate = swap.swap_rate(value_dt, zero_curve)\n",
+ "swap_rate"
+ ],
"id": "7bb1613d5e865838",
"outputs": [
{
@@ -126,18 +179,24 @@
"0.03404344249149676"
]
},
- "execution_count": 6,
+ "execution_count": 106,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 6
+ "execution_count": 106
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "",
+ "id": "6ead1b5ec3065f1e"
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:38:05.697242Z",
- "start_time": "2025-05-23T01:38:05.690197Z"
+ "end_time": "2025-05-23T06:49:49.111806Z",
+ "start_time": "2025-05-23T06:49:49.108411Z"
}
},
"cell_type": "code",
@@ -150,24 +209,25 @@
"5070.7014320408925"
]
},
- "execution_count": 7,
+ "execution_count": 107,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 7
+ "execution_count": 107
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:38:07.096647Z",
- "start_time": "2025-05-23T01:38:07.090478Z"
+ "end_time": "2025-05-23T06:49:49.152954Z",
+ "start_time": "2025-05-23T06:49:49.148624Z"
}
},
"cell_type": "code",
"source": [
- "payment_periods=8\n",
- "swap.payer_side_macaulay_duration(value_dt, zero_curve,payment_periods)"
+ "payment_periods = 8\n",
+ "payer_side_macaulay_duration = swap.payer_side_macaulay_duration(value_dt, zero_curve, payment_periods)\n",
+ "payer_side_macaulay_duration"
],
"id": "3f988f26e6662203",
"outputs": [
@@ -177,22 +237,25 @@
"-6.767653343606554"
]
},
- "execution_count": 8,
+ "execution_count": 108,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 8
+ "execution_count": 108
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:38:09.247259Z",
- "start_time": "2025-05-23T01:38:09.242767Z"
+ "end_time": "2025-05-23T06:49:49.197909Z",
+ "start_time": "2025-05-23T06:49:49.192534Z"
}
},
"cell_type": "code",
- "source": "swap.receiver_side_macaulay_duration(value_dt, zero_curve,payment_periods)",
+ "source": [
+ "receiver_side_macaulay_duration = swap.receiver_side_macaulay_duration(value_dt, zero_curve, payment_periods)\n",
+ "receiver_side_macaulay_duration"
+ ],
"id": "96d568f7a71861fe",
"outputs": [
{
@@ -201,22 +264,25 @@
"6.767653343606554"
]
},
- "execution_count": 9,
+ "execution_count": 109,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 9
+ "execution_count": 109
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:38:11.105175Z",
- "start_time": "2025-05-23T01:38:11.098720Z"
+ "end_time": "2025-05-23T06:49:49.243489Z",
+ "start_time": "2025-05-23T06:49:49.239303Z"
}
},
"cell_type": "code",
- "source": "swap.payer_side_modified_duration(value_dt, zero_curve,payment_periods)",
+ "source": [
+ "payer_side_modified_duration = swap.payer_side_modified_duration(value_dt, zero_curve, payment_periods)\n",
+ "payer_side_modified_duration"
+ ],
"id": "ec2187c7336c1bc3",
"outputs": [
{
@@ -225,22 +291,25 @@
"-6.710540865595371"
]
},
- "execution_count": 10,
+ "execution_count": 110,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 10
+ "execution_count": 110
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:38:12.408437Z",
- "start_time": "2025-05-23T01:38:12.401251Z"
+ "end_time": "2025-05-23T06:49:49.288001Z",
+ "start_time": "2025-05-23T06:49:49.283397Z"
}
},
"cell_type": "code",
- "source": "swap.receiver_side_modified_duration(value_dt, zero_curve,payment_periods)",
+ "source": [
+ "receiver_side_modified_duration = swap.receiver_side_modified_duration(value_dt, zero_curve, payment_periods)\n",
+ "receiver_side_modified_duration"
+ ],
"id": "2c1b845afaf5e18f",
"outputs": [
{
@@ -249,314 +318,428 @@
"6.710540865595371"
]
},
- "execution_count": 11,
+ "execution_count": 111,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 11
+ "execution_count": 111
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:38:15.309142Z",
- "start_time": "2025-05-23T01:38:15.301795Z"
+ "end_time": "2025-05-23T06:49:49.340211Z",
+ "start_time": "2025-05-23T06:49:49.332412Z"
}
},
"cell_type": "code",
- "source": "swap.print_payments()",
- "id": "2af7c95b07730dda",
+ "source": [
+ "payer_side_BPV = swap.payer_side_BPV(value_dt, zero_curve, payment_periods)\n",
+ "payer_side_BPV"
+ ],
+ "id": "602fd89b88bd58f0",
"outputs": [
{
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "START DATE: 01-JAN-2024\n",
- "MATURITY DATE: 02-JAN-2026\n",
- "COUPON (%): 3.4000000000000004\n",
- "FREQUENCY: FrequencyTypes.QUARTERLY\n",
- "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
- "\n",
- "PAYMENTS SCHEDULE:\n",
- "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
- "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC | RATE | PMNT |\n",
- "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
- "| 1 | 02-APR-2024 | 01-JAN-2024 | 02-APR-2024 | 91 | 0.2528 | 3.4 | 515666.67 |\n",
- "| 2 | 01-JUL-2024 | 02-APR-2024 | 01-JUL-2024 | 89 | 0.2472 | 3.4 | 504333.33 |\n",
- "| 3 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 | 3.4 | 510000.0 |\n",
- "| 4 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 | 3.4 | 515666.67 |\n",
- "| 5 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 | 3.4 | 504333.33 |\n",
- "| 6 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 | 3.4 | 510000.0 |\n",
- "| 7 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 | 3.4 | 510000.0 |\n",
- "| 8 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 | 3.4 | 515666.67 |\n",
- "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
- "START DATE: 01-JAN-2024\n",
- "MATURITY DATE: 02-JAN-2026\n",
- "SPREAD (bp): 0.0\n",
- "FREQUENCY: FrequencyTypes.QUARTERLY\n",
- "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
- "\n",
- "PAYMENTS SCHEDULE:\n",
- "+---------+-------------+-------------+-------------+------+----------+\n",
- "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC |\n",
- "+---------+-------------+-------------+-------------+------+----------+\n",
- "| 1 | 02-APR-2024 | 01-JAN-2024 | 02-APR-2024 | 91 | 0.2528 |\n",
- "| 2 | 01-JUL-2024 | 02-APR-2024 | 01-JUL-2024 | 89 | 0.2472 |\n",
- "| 3 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 |\n",
- "| 4 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 |\n",
- "| 5 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 |\n",
- "| 6 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 |\n",
- "| 7 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 |\n",
- "| 8 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 |\n",
- "+---------+-------------+-------------+-------------+------+----------+\n"
- ]
+ "data": {
+ "text/plain": [
+ "-10065.811298393059"
+ ]
+ },
+ "execution_count": 112,
+ "metadata": {},
+ "output_type": "execute_result"
}
],
- "execution_count": 12
+ "execution_count": 112
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:38:16.922391Z",
- "start_time": "2025-05-23T01:38:16.915012Z"
+ "end_time": "2025-05-23T06:49:49.366870Z",
+ "start_time": "2025-05-23T06:49:49.360337Z"
}
},
"cell_type": "code",
- "source": "pd.Series(swap.fixed_leg.payment_dts)",
- "id": "52df44f5a67bc377",
+ "source": [
+ "receiver_side_BPV = swap.receiver_side_BPV(value_dt, zero_curve, payment_periods)\n",
+ "receiver_side_BPV"
+ ],
+ "id": "b868dc3219fa867",
"outputs": [
{
"data": {
"text/plain": [
- "0 02-APR-2024\n",
- "1 01-JUL-2024\n",
- "2 01-OCT-2024\n",
- "3 02-JAN-2025\n",
- "4 01-APR-2025\n",
- "5 01-JUL-2025\n",
- "6 01-OCT-2025\n",
- "7 02-JAN-2026\n",
- "dtype: object"
+ "10065.811298393059"
]
},
- "execution_count": 13,
+ "execution_count": 113,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 13
- },
- {
- "metadata": {},
- "cell_type": "markdown",
- "source": "# 3months later",
- "id": "39513cfdc5d7ef1"
+ "execution_count": 113
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:42.392700200Z",
- "start_time": "2025-05-22T08:57:46.274653Z"
+ "end_time": "2025-05-23T06:49:49.412316Z",
+ "start_time": "2025-05-23T06:49:49.405136Z"
}
},
"cell_type": "code",
"source": [
- "yield_curve_3m=[i/100 for i in [0.75,1.1853,1.6822,2.1474,2.4371,2.7390,3.0198]]\n",
- "zero_dts_3m=value_dt.add_years([0.25,0.5,0.75,1.0,1.25,1.5,1.75])\n",
+ "index = ['swap_rate',\n",
+ " 'payer_side_macaulay_duration',\n",
+ " 'payer_side_modified_duration',\n",
+ " 'payer_side_BPV',\n",
+ " 'receiver_side_macaulay_duration',\n",
+ " 'receiver_side_modified_duration',\n",
+ " 'receiver_side_BPV']\n",
+ "data_financepy = [swap_rate,\n",
+ " payer_side_macaulay_duration, payer_side_modified_duration, payer_side_BPV,\n",
+ " receiver_side_macaulay_duration, receiver_side_modified_duration, receiver_side_BPV]\n",
+ "data_bondmath = [0.034,\n",
+ " np.nan, np.nan, np.nan,\n",
+ " np.nan, np.nan, np.nan]\n",
+ "data = {\n",
+ " 'financepy': data_financepy,\n",
+ " 'Bond Math by Donald J. Smith': data_bondmath\n",
+ "}\n",
"\n",
- "zero_curve_3m = DiscountCurveZeros(value_dt=value_dt.add_months(3),\n",
- " zero_dts=zero_dts_3m,\n",
- " zero_rates=yield_curve_3m,\n",
- " freq_type=FrequencyTypes.QUARTERLY,\n",
- " dc_type=DayCountTypes.THIRTY_360_BOND,\n",
- " interp_type=InterpTypes.FINCUBIC_ZERO_RATES\n",
- " )\n",
- "\n"
+ "df = pd.DataFrame(data, index=index)\n",
+ "df"
],
- "id": "8acc84107dae665e",
- "outputs": [],
- "execution_count": 93
+ "id": "952ec880bd1140f2",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ " financepy Bond Math by Donald J. Smith\n",
+ "swap_rate 0.034043 0.034\n",
+ "payer_side_macaulay_duration -6.767653 NaN\n",
+ "payer_side_modified_duration -6.710541 NaN\n",
+ "payer_side_BPV -10065.811298 NaN\n",
+ "receiver_side_macaulay_duration 6.767653 NaN\n",
+ "receiver_side_modified_duration 6.710541 NaN\n",
+ "receiver_side_BPV 10065.811298 NaN"
+ ],
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " financepy | \n",
+ " Bond Math by Donald J. Smith | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " swap_rate | \n",
+ " 0.034043 | \n",
+ " 0.034 | \n",
+ "
\n",
+ " \n",
+ " payer_side_macaulay_duration | \n",
+ " -6.767653 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " payer_side_modified_duration | \n",
+ " -6.710541 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " payer_side_BPV | \n",
+ " -10065.811298 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " receiver_side_macaulay_duration | \n",
+ " 6.767653 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " receiver_side_modified_duration | \n",
+ " 6.710541 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " receiver_side_BPV | \n",
+ " 10065.811298 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ]
+ },
+ "execution_count": 114,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 114
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "# 2.Calculation of indicators after 3 months",
+ "id": "39513cfdc5d7ef1"
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "## update the swap",
+ "id": "91abc51ca7618b13"
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:42.392700200Z",
- "start_time": "2025-05-22T08:58:16.963888Z"
+ "end_time": "2025-05-23T06:49:49.459858Z",
+ "start_time": "2025-05-23T06:49:49.455501Z"
}
},
"cell_type": "code",
"source": [
- "fixed_cpn_3m=0.034\n",
- "swap_3m = IborSwap(start_dt.add_months(3),\n",
- " maturity_dt,\n",
- " swap_type,\n",
- " fixed_cpn_3m,\n",
- " fixed_freq_type,\n",
- " fixed_dc_type,\n",
- " notional,\n",
- " float_spread,\n",
- " float_freq_type,\n",
- " float_dc_type,\n",
- " swap_cal_type,\n",
- " bd_type,\n",
- " dg_type)\n",
+ "fixed_cpn_3m = 0.034\n",
+ "start_dt_3m = Date(1, 4, 2024)\n",
+ "maturity_dt_3m = start_dt_3m.add_years(1.75)\n",
+ "\n",
+ "swap_3m = IborSwap(start_dt_3m,\n",
+ " maturity_dt_3m,\n",
+ " swap_type,\n",
+ " fixed_cpn_3m,\n",
+ " fixed_freq_type,\n",
+ " fixed_dc_type,\n",
+ " notional,\n",
+ " float_spread,\n",
+ " float_freq_type,\n",
+ " float_dc_type,\n",
+ " swap_cal_type,\n",
+ " bd_type,\n",
+ " dg_type)\n",
"\n"
],
"id": "5892081fb637c810",
"outputs": [],
- "execution_count": 99
+ "execution_count": 115
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:42.392700200Z",
- "start_time": "2025-05-22T08:58:18.380055Z"
+ "end_time": "2025-05-23T06:49:49.556137Z",
+ "start_time": "2025-05-23T06:49:49.552270Z"
}
},
"cell_type": "code",
- "source": "swap_3m.value(value_dt.add_months(3), zero_curve_3m)",
- "id": "3aa3b8731a5cc344",
+ "source": [
+ "value_date_3m = dt.datetime(2024, 3, 31)\n",
+ "value_dt_3m = from_datetime(value_date_3m)\n",
+ "\n",
+ "settle_dt_3m = value_dt_3m.add_weekdays(0)\n",
+ "settle_dt_3m"
+ ],
+ "id": "9093bbf0197b619b",
"outputs": [
{
"data": {
"text/plain": [
- "-1103746.1176017257"
+ "31-MAR-2024"
]
},
- "execution_count": 100,
+ "execution_count": 116,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 100
+ "execution_count": 116
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "## update the yield curve",
+ "id": "28ea6f9df37837d0"
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:42.392700200Z",
- "start_time": "2025-05-22T08:58:11.381600Z"
+ "end_time": "2025-05-23T06:49:49.640192Z",
+ "start_time": "2025-05-23T06:49:49.634830Z"
}
},
"cell_type": "code",
- "source": "swap_3m.swap_rate(value_dt.add_months(3), zero_curve_3m)",
- "id": "5d8fe704908ed541",
- "outputs": [
- {
- "data": {
- "text/plain": [
- "0.023244839642912206"
- ]
- },
- "execution_count": 98,
- "metadata": {},
- "output_type": "execute_result"
- }
+ "source": [
+ "yield_curve_3m = [i / 100 for i in [0.75, 1.1853, 1.6822, 2.1474, 2.4371, 2.7390, 3.0198]]\n",
+ "zero_dts_3m = value_dt_3m.add_years([0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75])\n",
+ "\n",
+ "zero_curve_3m = DiscountCurveZeros(value_dt_3m,\n",
+ " zero_dts=zero_dts_3m,\n",
+ " zero_rates=yield_curve_3m,\n",
+ " freq_type=FrequencyTypes.QUARTERLY,\n",
+ " dc_type=DayCountTypes.THIRTY_360_BOND,\n",
+ " interp_type=InterpTypes.FINCUBIC_ZERO_RATES\n",
+ " )\n",
+ "\n"
],
- "execution_count": 98
+ "id": "8acc84107dae665e",
+ "outputs": [],
+ "execution_count": 117
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:42.394185900Z",
- "start_time": "2025-05-22T08:15:54.437385Z"
+ "end_time": "2025-05-23T06:49:49.701074Z",
+ "start_time": "2025-05-23T06:49:49.696661Z"
}
},
"cell_type": "code",
- "source": "swap_3m.payer_side_macaulay_duration(value_dt.add_months(3), zero_curve_3m)",
- "id": "f9c796b4218d3df7",
+ "source": "swap_3m.value(value_dt_3m, zero_curve_3m)",
+ "id": "3aa3b8731a5cc344",
"outputs": [
{
"data": {
"text/plain": [
- "-5.879831278293125"
+ "-404094.769553849"
]
},
- "execution_count": 76,
+ "execution_count": 118,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 76
+ "execution_count": 118
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T01:25:42.394185900Z",
- "start_time": "2025-05-22T08:15:55.564419Z"
+ "end_time": "2025-05-23T06:49:49.753341Z",
+ "start_time": "2025-05-23T06:49:49.741421Z"
}
},
"cell_type": "code",
- "source": "start_dt.add_months(3)",
- "id": "68a6d3e4cc14ee91",
+ "source": [
+ "data_financepy_3m = [swap_3m.swap_rate(value_dt_3m, zero_curve_3m),\n",
+ " swap_3m.payer_side_macaulay_duration(value_dt_3m, zero_curve_3m, payment_periods),\n",
+ " swap_3m.payer_side_modified_duration(value_dt_3m, zero_curve_3m, payment_periods),\n",
+ " swap_3m.payer_side_BPV(value_dt_3m, zero_curve_3m, payment_periods),\n",
+ " swap_3m.receiver_side_macaulay_duration(value_dt_3m, zero_curve_3m, payment_periods),\n",
+ " swap_3m.receiver_side_modified_duration(value_dt_3m, zero_curve_3m, payment_periods),\n",
+ " swap_3m.receiver_side_BPV(value_dt_3m, zero_curve_3m, payment_periods)]\n",
+ "\n",
+ "data_bondmath_3m = [0.030,\n",
+ " -6.769,\n",
+ " -6.7186,\n",
+ " -10077.9,\n",
+ " 6.769,\n",
+ " 6.7186,\n",
+ " 10077.9]\n",
+ "\n",
+ "data_3m = {\n",
+ " 'financepy': data_financepy_3m,\n",
+ " 'Bond Math by Donald J. Smith': data_bondmath_3m\n",
+ "}\n",
+ "\n",
+ "df3m = pd.DataFrame(data_3m, index=index)\n",
+ "df3m"
+ ],
+ "id": "9e64b678f01aa539",
"outputs": [
{
"data": {
"text/plain": [
- "01-APR-2024"
+ " financepy Bond Math by Donald J. Smith\n",
+ "swap_rate 0.030066 0.0300\n",
+ "payer_side_macaulay_duration -6.794199 -6.7690\n",
+ "payer_side_modified_duration -6.743512 -6.7186\n",
+ "payer_side_BPV -10115.267497 -10077.9000\n",
+ "receiver_side_macaulay_duration 6.794199 6.7690\n",
+ "receiver_side_modified_duration 6.743512 6.7186\n",
+ "receiver_side_BPV 10115.267497 10077.9000"
+ ],
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " financepy | \n",
+ " Bond Math by Donald J. Smith | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " swap_rate | \n",
+ " 0.030066 | \n",
+ " 0.0300 | \n",
+ "
\n",
+ " \n",
+ " payer_side_macaulay_duration | \n",
+ " -6.794199 | \n",
+ " -6.7690 | \n",
+ "
\n",
+ " \n",
+ " payer_side_modified_duration | \n",
+ " -6.743512 | \n",
+ " -6.7186 | \n",
+ "
\n",
+ " \n",
+ " payer_side_BPV | \n",
+ " -10115.267497 | \n",
+ " -10077.9000 | \n",
+ "
\n",
+ " \n",
+ " receiver_side_macaulay_duration | \n",
+ " 6.794199 | \n",
+ " 6.7690 | \n",
+ "
\n",
+ " \n",
+ " receiver_side_modified_duration | \n",
+ " 6.743512 | \n",
+ " 6.7186 | \n",
+ "
\n",
+ " \n",
+ " receiver_side_BPV | \n",
+ " 10115.267497 | \n",
+ " 10077.9000 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
]
},
- "execution_count": 77,
+ "execution_count": 119,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 77
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-23T01:25:42.394185900Z",
- "start_time": "2025-05-22T08:19:10.564739Z"
- }
- },
- "cell_type": "code",
- "source": "swap_3m.print_payments()",
- "id": "68097534a5e9ba5e",
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "START DATE: 01-APR-2024\n",
- "MATURITY DATE: 02-JAN-2026\n",
- "COUPON (%): 3.0\n",
- "FREQUENCY: FrequencyTypes.QUARTERLY\n",
- "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
- "\n",
- "PAYMENTS SCHEDULE:\n",
- "+---------+-------------+-------------+-------------+------+----------+------+----------+\n",
- "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC | RATE | PMNT |\n",
- "+---------+-------------+-------------+-------------+------+----------+------+----------+\n",
- "| 1 | 01-JUL-2024 | 01-APR-2024 | 01-JUL-2024 | 90 | 0.25 | 3.0 | 450000.0 |\n",
- "| 2 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 | 3.0 | 450000.0 |\n",
- "| 3 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 | 3.0 | 455000.0 |\n",
- "| 4 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 | 3.0 | 445000.0 |\n",
- "| 5 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 | 3.0 | 450000.0 |\n",
- "| 6 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 | 3.0 | 450000.0 |\n",
- "| 7 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 | 3.0 | 455000.0 |\n",
- "+---------+-------------+-------------+-------------+------+----------+------+----------+\n",
- "START DATE: 01-APR-2024\n",
- "MATURITY DATE: 02-JAN-2026\n",
- "SPREAD (bp): 0.0\n",
- "FREQUENCY: FrequencyTypes.QUARTERLY\n",
- "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
- "\n",
- "PAYMENTS SCHEDULE:\n",
- "+---------+-------------+-------------+-------------+------+----------+\n",
- "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC |\n",
- "+---------+-------------+-------------+-------------+------+----------+\n",
- "| 1 | 01-JUL-2024 | 01-APR-2024 | 01-JUL-2024 | 90 | 0.25 |\n",
- "| 2 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 |\n",
- "| 3 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 |\n",
- "| 4 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 |\n",
- "| 5 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 |\n",
- "| 6 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 |\n",
- "| 7 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 |\n",
- "+---------+-------------+-------------+-------------+------+----------+\n"
- ]
- }
- ],
- "execution_count": 83
+ "execution_count": 119
}
],
"metadata": {
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
index ca5a8b00..5c6d719b 100644
--- a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample3M.ipynb
@@ -6,8 +6,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.516595Z",
- "start_time": "2025-05-23T03:01:38.512089Z"
+ "end_time": "2025-05-23T03:11:32.198988Z",
+ "start_time": "2025-05-23T03:11:30.509140Z"
}
},
"source": [
@@ -16,14 +16,27 @@
"from financepy.market.curves import *\n",
"import datetime as dt\n"
],
- "outputs": [],
- "execution_count": 22
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "####################################################################\n",
+ "# FINANCEPY BETA Version 0.370 - This build: 28 Oct 2024 at 20:29 #\n",
+ "# This software is distributed FREE AND WITHOUT ANY WARRANTY #\n",
+ "# Report bugs as issues at https://github.com/domokane/FinancePy #\n",
+ "####################################################################\n",
+ "\n"
+ ]
+ }
+ ],
+ "execution_count": 1
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.528444Z",
- "start_time": "2025-05-23T03:01:38.524597Z"
+ "end_time": "2025-05-23T03:11:32.234873Z",
+ "start_time": "2025-05-23T03:11:32.208415Z"
}
},
"cell_type": "code",
@@ -63,13 +76,13 @@
],
"id": "1ebf43316efee835",
"outputs": [],
- "execution_count": 23
+ "execution_count": 2
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.542275Z",
- "start_time": "2025-05-23T03:01:38.537531Z"
+ "end_time": "2025-05-23T03:11:32.413949Z",
+ "start_time": "2025-05-23T03:11:32.408884Z"
}
},
"cell_type": "code",
@@ -89,26 +102,22 @@
"31-MAR-2024"
]
},
- "execution_count": 24,
+ "execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 24
+ "execution_count": 3
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.569014Z",
- "start_time": "2025-05-23T03:01:38.564129Z"
+ "end_time": "2025-05-23T03:11:32.447267Z",
+ "start_time": "2025-05-23T03:11:32.442210Z"
}
},
"cell_type": "code",
"source": [
- "# 书中曲线\n",
- "# yield_curve=[i/100 for i in [0.75,1.1853,1.6822,2.1474,2.4371,2.7390,3.0198]]\n",
- "# zero_dts=value_dt.add_years([0.25,0.5,0.75,1.0,1.25,1.5,1.75])\n",
- "\n",
"\n",
"yield_curve=[i/100 for i in [0.75,1.1853,1.6822,2.1474,2.4371,2.7390,3.0198]]\n",
"zero_dts=value_dt.add_years([0.25,0.5,0.75,1.0,1.25,1.5,1.75])\n",
@@ -123,13 +132,13 @@
],
"id": "290b7a06932da41d",
"outputs": [],
- "execution_count": 25
+ "execution_count": 4
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.585724Z",
- "start_time": "2025-05-23T03:01:38.579955Z"
+ "end_time": "2025-05-23T03:11:32.461542Z",
+ "start_time": "2025-05-23T03:11:32.456727Z"
}
},
"cell_type": "code",
@@ -142,18 +151,18 @@
"0.030065619962567392"
]
},
- "execution_count": 26,
+ "execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 26
+ "execution_count": 5
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.610747Z",
- "start_time": "2025-05-23T03:01:38.606021Z"
+ "end_time": "2025-05-23T03:11:32.501044Z",
+ "start_time": "2025-05-23T03:11:32.497430Z"
}
},
"cell_type": "code",
@@ -166,18 +175,18 @@
"-404094.769553849"
]
},
- "execution_count": 27,
+ "execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 27
+ "execution_count": 6
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.645126Z",
- "start_time": "2025-05-23T03:01:38.640384Z"
+ "end_time": "2025-05-23T03:11:32.548673Z",
+ "start_time": "2025-05-23T03:11:32.543824Z"
}
},
"cell_type": "code",
@@ -190,18 +199,18 @@
"-6.794198629548404"
]
},
- "execution_count": 28,
+ "execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 28
+ "execution_count": 7
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.686342Z",
- "start_time": "2025-05-23T03:01:38.681347Z"
+ "end_time": "2025-05-23T03:11:32.591829Z",
+ "start_time": "2025-05-23T03:11:32.587918Z"
}
},
"cell_type": "code",
@@ -214,18 +223,18 @@
"6.794198629548404"
]
},
- "execution_count": 29,
+ "execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 29
+ "execution_count": 8
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.722907Z",
- "start_time": "2025-05-23T03:01:38.717909Z"
+ "end_time": "2025-05-23T03:11:32.651777Z",
+ "start_time": "2025-05-23T03:11:32.646875Z"
}
},
"cell_type": "code",
@@ -238,18 +247,18 @@
"-6.743511664816526"
]
},
- "execution_count": 30,
+ "execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 30
+ "execution_count": 9
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.756278Z",
- "start_time": "2025-05-23T03:01:38.751727Z"
+ "end_time": "2025-05-23T03:11:32.715295Z",
+ "start_time": "2025-05-23T03:11:32.711182Z"
}
},
"cell_type": "code",
@@ -262,150 +271,18 @@
"6.743511664816526"
]
},
- "execution_count": 31,
+ "execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 31
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.790007Z",
- "start_time": "2025-05-23T03:01:38.786002Z"
- }
- },
- "cell_type": "code",
- "source": "swap.print_payments()",
- "id": "2af7c95b07730dda",
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "START DATE: 01-APR-2024\n",
- "MATURITY DATE: 02-JAN-2026\n",
- "COUPON (%): 3.4000000000000004\n",
- "FREQUENCY: FrequencyTypes.QUARTERLY\n",
- "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
- "\n",
- "PAYMENTS SCHEDULE:\n",
- "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
- "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC | RATE | PMNT |\n",
- "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
- "| 1 | 01-JUL-2024 | 01-APR-2024 | 01-JUL-2024 | 90 | 0.25 | 3.4 | 510000.0 |\n",
- "| 2 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 | 3.4 | 510000.0 |\n",
- "| 3 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 | 3.4 | 515666.67 |\n",
- "| 4 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 | 3.4 | 504333.33 |\n",
- "| 5 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 | 3.4 | 510000.0 |\n",
- "| 6 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 | 3.4 | 510000.0 |\n",
- "| 7 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 | 3.4 | 515666.67 |\n",
- "+---------+-------------+-------------+-------------+------+----------+------+-----------+\n",
- "START DATE: 01-APR-2024\n",
- "MATURITY DATE: 02-JAN-2026\n",
- "SPREAD (bp): 0.0\n",
- "FREQUENCY: FrequencyTypes.QUARTERLY\n",
- "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
- "\n",
- "PAYMENTS SCHEDULE:\n",
- "+---------+-------------+-------------+-------------+------+----------+\n",
- "| PAY_NUM | PAY_dt | ACCR_START | ACCR_END | DAYS | YEARFRAC |\n",
- "+---------+-------------+-------------+-------------+------+----------+\n",
- "| 1 | 01-JUL-2024 | 01-APR-2024 | 01-JUL-2024 | 90 | 0.25 |\n",
- "| 2 | 01-OCT-2024 | 01-JUL-2024 | 01-OCT-2024 | 90 | 0.25 |\n",
- "| 3 | 02-JAN-2025 | 01-OCT-2024 | 02-JAN-2025 | 91 | 0.2528 |\n",
- "| 4 | 01-APR-2025 | 02-JAN-2025 | 01-APR-2025 | 89 | 0.2472 |\n",
- "| 5 | 01-JUL-2025 | 01-APR-2025 | 01-JUL-2025 | 90 | 0.25 |\n",
- "| 6 | 01-OCT-2025 | 01-JUL-2025 | 01-OCT-2025 | 90 | 0.25 |\n",
- "| 7 | 02-JAN-2026 | 01-OCT-2025 | 02-JAN-2026 | 91 | 0.2528 |\n",
- "+---------+-------------+-------------+-------------+------+----------+\n"
- ]
- }
- ],
- "execution_count": 32
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.821049Z",
- "start_time": "2025-05-23T03:01:38.816897Z"
- }
- },
- "cell_type": "code",
- "source": "swap.print_float_leg_pv()",
- "id": "1c960526153c2223",
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "START DATE: 01-APR-2024\n",
- "MATURITY DATE: 02-JAN-2026\n",
- "SPREAD (BPS): 0.0\n",
- "FREQUENCY: FrequencyTypes.QUARTERLY\n",
- "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
- "\n",
- "PAYMENTS VALUATION:\n",
- "+---------+-------------+----------+--------+-----------+--------+-----------+------------+\n",
- "| PAY_NUM | PAY_dt | NOTIONAL | IBOR | PMNT | DF | PV | CUM_PV |\n",
- "+---------+-------------+----------+--------+-----------+--------+-----------+------------+\n",
- "| 1 | 01-JUL-2024 | 60000000 | 0.7529 | 112935.42 | 0.9981 | 112722.26 | 112722.26 |\n",
- "| 2 | 01-OCT-2024 | 60000000 | 1.6379 | 245686.53 | 0.994 | 244222.77 | 356945.03 |\n",
- "| 3 | 02-JAN-2025 | 60000000 | 2.7131 | 411480.71 | 0.9873 | 406243.16 | 763188.19 |\n",
- "| 4 | 01-APR-2025 | 60000000 | 3.5062 | 520087.02 | 0.9788 | 509054.52 | 1272242.71 |\n",
- "| 5 | 01-JUL-2025 | 60000000 | 3.588 | 538192.75 | 0.9701 | 522093.07 | 1794335.78 |\n",
- "| 6 | 01-OCT-2025 | 60000000 | 4.293 | 643955.16 | 0.9598 | 618058.3 | 2412394.08 |\n",
- "| 7 | 02-JAN-2026 | 60000000 | 4.6963 | 712268.76 | 0.9485 | 675604.45 | 3087998.53 |\n",
- "+---------+-------------+----------+--------+-----------+--------+-----------+------------+\n"
- ]
- }
- ],
- "execution_count": 33
+ "execution_count": 10
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:38.907291Z",
- "start_time": "2025-05-23T03:01:38.903054Z"
- }
- },
- "cell_type": "code",
- "source": "swap.print_fixed_leg_pv()",
- "id": "5037651021a91d38",
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "START DATE: 01-APR-2024\n",
- "MATURITY DATE: 02-JAN-2026\n",
- "COUPON (%): 3.4000000000000004\n",
- "FREQUENCY: FrequencyTypes.QUARTERLY\n",
- "DAY COUNT: DayCountTypes.THIRTY_360_BOND\n",
- "\n",
- "PAYMENTS VALUATION:\n",
- "+---------+-------------+----------+------+-----------+--------+-----------+------------+\n",
- "| PAY_NUM | PAY_dt | NOTIONAL | RATE | PMNT | DF | PV | CUM_PV |\n",
- "+---------+-------------+----------+------+-----------+--------+-----------+------------+\n",
- "| 1 | 01-JUL-2024 | 60000000 | 3.4 | 510000.0 | 0.9981 | 509037.4 | 509037.4 |\n",
- "| 2 | 01-OCT-2024 | 60000000 | 3.4 | 510000.0 | 0.994 | 506961.51 | 1015998.91 |\n",
- "| 3 | 02-JAN-2025 | 60000000 | 3.4 | 515666.67 | 0.9873 | 509102.98 | 1525101.88 |\n",
- "| 4 | 01-APR-2025 | 60000000 | 3.4 | 504333.33 | 0.9788 | 493635.02 | 2018736.9 |\n",
- "| 5 | 01-JUL-2025 | 60000000 | 3.4 | 510000.0 | 0.9701 | 494743.69 | 2513480.58 |\n",
- "| 6 | 01-OCT-2025 | 60000000 | 3.4 | 510000.0 | 0.9598 | 489490.19 | 3002970.77 |\n",
- "| 7 | 02-JAN-2026 | 60000000 | 3.4 | 515666.67 | 0.9485 | 489122.52 | 3492093.3 |\n",
- "+---------+-------------+----------+------+-----------+--------+-----------+------------+\n"
- ]
- }
- ],
- "execution_count": 34
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-23T03:01:39.014637Z",
- "start_time": "2025-05-23T03:01:39.009932Z"
+ "end_time": "2025-05-23T03:11:32.914101Z",
+ "start_time": "2025-05-23T03:11:32.909828Z"
}
},
"cell_type": "code",
@@ -422,18 +299,18 @@
"-404610.6998889916"
]
},
- "execution_count": 35,
+ "execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 35
+ "execution_count": 14
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:39.056730Z",
- "start_time": "2025-05-23T03:01:39.050609Z"
+ "end_time": "2025-05-23T03:11:32.963176Z",
+ "start_time": "2025-05-23T03:11:32.958757Z"
}
},
"cell_type": "code",
@@ -446,18 +323,18 @@
"404610.6998889916"
]
},
- "execution_count": 36,
+ "execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 36
+ "execution_count": 15
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T03:01:39.100675Z",
- "start_time": "2025-05-23T03:01:39.095809Z"
+ "end_time": "2025-05-23T03:11:33.018125Z",
+ "start_time": "2025-05-23T03:11:33.013277Z"
}
},
"cell_type": "code",
@@ -467,30 +344,39 @@
{
"data": {
"text/plain": [
- "-40461.06998889916"
+ "-10115.26749722479"
]
},
- "execution_count": 37,
+ "execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 37
+ "execution_count": 16
},
{
"metadata": {
- "jupyter": {
- "is_executing": true
- },
"ExecuteTime": {
- "start_time": "2025-05-23T03:01:55.128551Z"
+ "end_time": "2025-05-23T03:11:33.062580Z",
+ "start_time": "2025-05-23T03:11:33.058102Z"
}
},
"cell_type": "code",
"source": "swap.receiver_side_BPV(value_dt, zero_curve,payment_periods)",
"id": "8f8630e90883e3b5",
- "outputs": [],
- "execution_count": null
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "10115.26749722479"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 17
}
],
"metadata": {
From 07c7560a9a6264f94b8bfa28571d5cd4b516fa1b Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Fri, 23 May 2025 15:16:51 +0800
Subject: [PATCH 09/12] Update
FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
---
..._ReplicationgBONDMATHDurationExample.ipynb | 155 ++++++++++--------
1 file changed, 84 insertions(+), 71 deletions(-)
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
index f42cf92e..1fee0073 100644
--- a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
@@ -6,8 +6,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:48.974729Z",
- "start_time": "2025-05-23T06:49:48.971287Z"
+ "end_time": "2025-05-23T07:06:02.211270Z",
+ "start_time": "2025-05-23T07:06:00.531998Z"
}
},
"source": [
@@ -17,14 +17,27 @@
"import datetime as dt\n",
"import numpy as np"
],
- "outputs": [],
- "execution_count": 101
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "####################################################################\n",
+ "# FINANCEPY BETA Version 0.370 - This build: 28 Oct 2024 at 20:29 #\n",
+ "# This software is distributed FREE AND WITHOUT ANY WARRANTY #\n",
+ "# Report bugs as issues at https://github.com/domokane/FinancePy #\n",
+ "####################################################################\n",
+ "\n"
+ ]
+ }
+ ],
+ "execution_count": 1
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.013677Z",
- "start_time": "2025-05-23T06:49:49.009267Z"
+ "end_time": "2025-05-23T07:06:02.229480Z",
+ "start_time": "2025-05-23T07:06:02.224272Z"
}
},
"cell_type": "code",
@@ -42,12 +55,12 @@
"'\\nCalculating the Duration and Other Interest Rate Sensitivity Metrics in an Interest Rate Swap\\nBased on Bond Math: The Theory Behind the Formulas, Second Edition by Donald J. Smith\\n'"
]
},
- "execution_count": 102,
+ "execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 102
+ "execution_count": 2
},
{
"metadata": {},
@@ -64,8 +77,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.022425Z",
- "start_time": "2025-05-23T06:49:49.018680Z"
+ "end_time": "2025-05-23T07:06:02.422259Z",
+ "start_time": "2025-05-23T07:06:02.399642Z"
}
},
"cell_type": "code",
@@ -104,13 +117,13 @@
],
"id": "1ebf43316efee835",
"outputs": [],
- "execution_count": 103
+ "execution_count": 3
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.040866Z",
- "start_time": "2025-05-23T06:49:49.037306Z"
+ "end_time": "2025-05-23T07:06:02.435325Z",
+ "start_time": "2025-05-23T07:06:02.431814Z"
}
},
"cell_type": "code",
@@ -121,7 +134,7 @@
],
"id": "8e46f142f3cba5d7",
"outputs": [],
- "execution_count": 104
+ "execution_count": 4
},
{
"metadata": {},
@@ -132,8 +145,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.057895Z",
- "start_time": "2025-05-23T06:49:49.053646Z"
+ "end_time": "2025-05-23T07:06:02.451098Z",
+ "start_time": "2025-05-23T07:06:02.444694Z"
}
},
"cell_type": "code",
@@ -151,7 +164,7 @@
],
"id": "290b7a06932da41d",
"outputs": [],
- "execution_count": 105
+ "execution_count": 5
},
{
"metadata": {},
@@ -162,8 +175,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.073393Z",
- "start_time": "2025-05-23T06:49:49.068617Z"
+ "end_time": "2025-05-23T07:06:02.466457Z",
+ "start_time": "2025-05-23T07:06:02.460826Z"
}
},
"cell_type": "code",
@@ -179,12 +192,12 @@
"0.03404344249149676"
]
},
- "execution_count": 106,
+ "execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 106
+ "execution_count": 6
},
{
"metadata": {},
@@ -195,8 +208,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.111806Z",
- "start_time": "2025-05-23T06:49:49.108411Z"
+ "end_time": "2025-05-23T07:06:02.510127Z",
+ "start_time": "2025-05-23T07:06:02.504897Z"
}
},
"cell_type": "code",
@@ -209,18 +222,18 @@
"5070.7014320408925"
]
},
- "execution_count": 107,
+ "execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 107
+ "execution_count": 7
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.152954Z",
- "start_time": "2025-05-23T06:49:49.148624Z"
+ "end_time": "2025-05-23T07:06:02.538230Z",
+ "start_time": "2025-05-23T07:06:02.532904Z"
}
},
"cell_type": "code",
@@ -237,18 +250,18 @@
"-6.767653343606554"
]
},
- "execution_count": 108,
+ "execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 108
+ "execution_count": 8
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.197909Z",
- "start_time": "2025-05-23T06:49:49.192534Z"
+ "end_time": "2025-05-23T07:06:02.577877Z",
+ "start_time": "2025-05-23T07:06:02.572337Z"
}
},
"cell_type": "code",
@@ -264,18 +277,18 @@
"6.767653343606554"
]
},
- "execution_count": 109,
+ "execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 109
+ "execution_count": 9
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.243489Z",
- "start_time": "2025-05-23T06:49:49.239303Z"
+ "end_time": "2025-05-23T07:06:02.618947Z",
+ "start_time": "2025-05-23T07:06:02.613773Z"
}
},
"cell_type": "code",
@@ -291,18 +304,18 @@
"-6.710540865595371"
]
},
- "execution_count": 110,
+ "execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 110
+ "execution_count": 10
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.288001Z",
- "start_time": "2025-05-23T06:49:49.283397Z"
+ "end_time": "2025-05-23T07:06:02.657887Z",
+ "start_time": "2025-05-23T07:06:02.652511Z"
}
},
"cell_type": "code",
@@ -318,18 +331,18 @@
"6.710540865595371"
]
},
- "execution_count": 111,
+ "execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 111
+ "execution_count": 11
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.340211Z",
- "start_time": "2025-05-23T06:49:49.332412Z"
+ "end_time": "2025-05-23T07:06:02.688544Z",
+ "start_time": "2025-05-23T07:06:02.683201Z"
}
},
"cell_type": "code",
@@ -345,18 +358,18 @@
"-10065.811298393059"
]
},
- "execution_count": 112,
+ "execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 112
+ "execution_count": 12
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.366870Z",
- "start_time": "2025-05-23T06:49:49.360337Z"
+ "end_time": "2025-05-23T07:06:02.730798Z",
+ "start_time": "2025-05-23T07:06:02.725738Z"
}
},
"cell_type": "code",
@@ -372,18 +385,18 @@
"10065.811298393059"
]
},
- "execution_count": 113,
+ "execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 113
+ "execution_count": 13
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.412316Z",
- "start_time": "2025-05-23T06:49:49.405136Z"
+ "end_time": "2025-05-23T07:06:02.778884Z",
+ "start_time": "2025-05-23T07:06:02.769818Z"
}
},
"cell_type": "code",
@@ -487,12 +500,12 @@
""
]
},
- "execution_count": 114,
+ "execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 114
+ "execution_count": 14
},
{
"metadata": {},
@@ -509,8 +522,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.459858Z",
- "start_time": "2025-05-23T06:49:49.455501Z"
+ "end_time": "2025-05-23T07:06:02.844522Z",
+ "start_time": "2025-05-23T07:06:02.840897Z"
}
},
"cell_type": "code",
@@ -536,13 +549,13 @@
],
"id": "5892081fb637c810",
"outputs": [],
- "execution_count": 115
+ "execution_count": 15
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.556137Z",
- "start_time": "2025-05-23T06:49:49.552270Z"
+ "end_time": "2025-05-23T07:06:02.897137Z",
+ "start_time": "2025-05-23T07:06:02.892722Z"
}
},
"cell_type": "code",
@@ -561,12 +574,12 @@
"31-MAR-2024"
]
},
- "execution_count": 116,
+ "execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 116
+ "execution_count": 16
},
{
"metadata": {},
@@ -577,8 +590,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.640192Z",
- "start_time": "2025-05-23T06:49:49.634830Z"
+ "end_time": "2025-05-23T07:06:03.045244Z",
+ "start_time": "2025-05-23T07:06:03.040708Z"
}
},
"cell_type": "code",
@@ -597,13 +610,13 @@
],
"id": "8acc84107dae665e",
"outputs": [],
- "execution_count": 117
+ "execution_count": 17
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.701074Z",
- "start_time": "2025-05-23T06:49:49.696661Z"
+ "end_time": "2025-05-23T07:06:03.139582Z",
+ "start_time": "2025-05-23T07:06:03.133116Z"
}
},
"cell_type": "code",
@@ -616,18 +629,18 @@
"-404094.769553849"
]
},
- "execution_count": 118,
+ "execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 118
+ "execution_count": 18
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T06:49:49.753341Z",
- "start_time": "2025-05-23T06:49:49.741421Z"
+ "end_time": "2025-05-23T07:06:03.193803Z",
+ "start_time": "2025-05-23T07:06:03.181239Z"
}
},
"cell_type": "code",
@@ -734,12 +747,12 @@
""
]
},
- "execution_count": 119,
+ "execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 119
+ "execution_count": 19
}
],
"metadata": {
From bbf5e8d5df9d488b4f5a5644c5ea9e7c38a79435 Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Mon, 26 May 2025 09:11:43 +0800
Subject: [PATCH 10/12] Use swap.Type to determine which indicators to output.
---
financepy/products/rates/ibor_swap.py | 99 +++++++++++++++++++++++++++
1 file changed, 99 insertions(+)
diff --git a/financepy/products/rates/ibor_swap.py b/financepy/products/rates/ibor_swap.py
index c57566c8..56c9c557 100644
--- a/financepy/products/rates/ibor_swap.py
+++ b/financepy/products/rates/ibor_swap.py
@@ -417,6 +417,44 @@ def payer_side_macaulay_duration(self, value_dt, discount_curve, payment_periods
mac_duration = 1 - (md1 - md2 / md3)
return mac_duration
+
+ def macaulay_duration(self, value_dt, discount_curve, swap_type, payment_periods: float):
+ """Calculation of the Payer's Macaulay Duration in an Interest Rate Swap
+ Based on Bond Math: The Theory Behind the Formulas, Second Edition by
+ Donald J. Smith
+ """
+ # Get coupon frequency
+ coupon_frequency = self.fixed_leg.freq_type.value
+
+ # Get swap rate
+ swap_rate_val = self.swap_rate(value_dt,discount_curve)
+
+ y = swap_rate_val / coupon_frequency
+ # payment_periods is the number of periods to maturity as of the beginning of the period;
+ # for instance, If the start date of the interest rate swap is 2024-01-01,
+ # the end date is 2025-12-31, the valuation date is 2024-03-31,
+ # and the frequency type is QUARTERLY,
+ # then the number of payment periods is 8; it is independent of the valuation date.
+ N = payment_periods
+ c = swap_rate_val / coupon_frequency
+ md1 = (1 + y) / y
+ md2 = 1 + y + (N * (c - y))
+ md3 = c * ((1 + y) ** N - 1) + y
+
+ """
+ The party who pays the fixed rate(ie,SwapTypes.PAY) is known as the payer
+ and the party who receives the fixed rate is known as the receiver.
+ The fixed‐rate payer and floating‐rate receiver,
+ sometimes is said to be the “buyer” of the swap, or is “long” the swap.
+ """
+ if swap_type == SwapTypes.PAY:
+ mac_duration = 1 - (md1 - md2 / md3)
+
+ elif swap_type == SwapTypes.RECEIVE:
+ mac_duration = (1 - (md1 - md2 / md3))*(-1)
+
+ return mac_duration
+
###########################################################################
def receiver_side_macaulay_duration(self, value_dt, discount_curve,payment_periods: float):
@@ -440,6 +478,27 @@ def payer_side_modified_duration(self, value_dt, discount_curve,payment_periods:
return self.payer_side_macaulay_duration(value_dt, discount_curve,payment_periods)/(1+swap_rate_val/coupon_frequency)
+ def modified_duration(self, value_dt, discount_curve, swap_type, payment_periods: float):
+ """Computation of the Modified Duration for the Fixed-Rate
+ Payer's Perspective in Interest Rate Swap
+ """
+ # Get coupon frequency
+ coupon_frequency = self.fixed_leg.freq_type.value
+
+ # Get swap rate
+ swap_rate_val = self.swap_rate(value_dt, discount_curve)
+
+ if swap_type == SwapTypes.PAY:
+ modified_duration = (self.macaulay_duration(value_dt, discount_curve, swap_type, payment_periods) /
+ (1 + swap_rate_val / coupon_frequency))
+
+ elif swap_type == SwapTypes.RECEIVE:
+ modified_duration = (self.macaulay_duration(value_dt, discount_curve, swap_type, payment_periods) /
+ (1 + swap_rate_val / coupon_frequency))
+
+ return modified_duration
+
+
###########################################################################
def receiver_side_modified_duration(self, value_dt, discount_curve,payment_periods: float):
@@ -472,6 +531,25 @@ def receiver_side_profits(self,
"""
return self.payer_side_profits(value_dt, discount_curve,payment_periods,swap_rate_changes)*(-1)
+
+ def change_in_market_value(self,
+ value_dt, discount_curve, swap_type, payment_periods: float,
+ swap_rate_changes: float):
+ """Computation of the Profits for the Fixed-Rate Payer's Perspective in Interest Rate Swap
+ """
+ # Get coupon frequency
+ coupon_frequency = self.fixed_leg.freq_type.value
+
+ annualized_modi_dur = self.modified_duration(value_dt, discount_curve,swap_type,payment_periods)/coupon_frequency
+
+ if swap_type == SwapTypes.PAY:
+ delta_mv=(-1)*(annualized_modi_dur*self.fixed_leg.notional*swap_rate_changes)
+
+ elif swap_type == SwapTypes.RECEIVE:
+ delta_mv=(annualized_modi_dur*self.fixed_leg.notional*swap_rate_changes)
+
+ return delta_mv
+
###########################################################################
def payer_side_BPV(self, value_dt, discount_curve,payment_periods: float,):
@@ -499,6 +577,27 @@ def receiver_side_BPV(self, value_dt, discount_curve,payment_periods: float,):
###########################################################################
+ def basis_point_value (self,value_dt, discount_curve,swap_type, payment_periods: float):
+ """
+ calculate the basis‐point‐value (BPV) for the payer_side of the swap,
+ which is swap's modified duration times the notional principal,
+ times one basis point (0.0001)
+ """
+ bp=0.0001
+ # Get coupon frequency
+ coupon_frequency = self.fixed_leg.freq_type.value
+ modi_dur = self.modified_duration(value_dt, discount_curve, swap_type, payment_periods)
+ annualized_modi_dur= modi_dur/coupon_frequency
+
+ if swap_type == SwapTypes.PAY:
+ BPV=annualized_modi_dur*self.fixed_leg.notional*bp
+
+ elif swap_type == SwapTypes.RECEIVE:
+ BPV=annualized_modi_dur*self.fixed_leg.notional*bp*(-1)
+
+ return BPV
+
+
def __repr__(self):
s = label_to_string("OBJECT TYPE", type(self).__name__)
From ff0750a4e1138ac3e7808ca363c091a071dc53bc Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Mon, 26 May 2025 09:40:21 +0800
Subject: [PATCH 11/12] modified BVP
---
financepy/products/rates/ibor_swap.py | 2 +-
..._ReplicationgBONDMATHDurationExample.ipynb | 224 +++++++++++-------
2 files changed, 141 insertions(+), 85 deletions(-)
diff --git a/financepy/products/rates/ibor_swap.py b/financepy/products/rates/ibor_swap.py
index 56c9c557..e01b27ee 100644
--- a/financepy/products/rates/ibor_swap.py
+++ b/financepy/products/rates/ibor_swap.py
@@ -593,7 +593,7 @@ def basis_point_value (self,value_dt, discount_curve,swap_type, payment_periods:
BPV=annualized_modi_dur*self.fixed_leg.notional*bp
elif swap_type == SwapTypes.RECEIVE:
- BPV=annualized_modi_dur*self.fixed_leg.notional*bp*(-1)
+ BPV=annualized_modi_dur*self.fixed_leg.notional*bp
return BPV
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
index 1fee0073..c0f5d1b9 100644
--- a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
@@ -6,8 +6,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.211270Z",
- "start_time": "2025-05-23T07:06:00.531998Z"
+ "end_time": "2025-05-26T01:38:51.362248Z",
+ "start_time": "2025-05-26T01:38:51.358838Z"
}
},
"source": [
@@ -17,27 +17,14 @@
"import datetime as dt\n",
"import numpy as np"
],
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "####################################################################\n",
- "# FINANCEPY BETA Version 0.370 - This build: 28 Oct 2024 at 20:29 #\n",
- "# This software is distributed FREE AND WITHOUT ANY WARRANTY #\n",
- "# Report bugs as issues at https://github.com/domokane/FinancePy #\n",
- "####################################################################\n",
- "\n"
- ]
- }
- ],
- "execution_count": 1
+ "outputs": [],
+ "execution_count": 53
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.229480Z",
- "start_time": "2025-05-23T07:06:02.224272Z"
+ "end_time": "2025-05-26T01:38:51.410238Z",
+ "start_time": "2025-05-26T01:38:51.406404Z"
}
},
"cell_type": "code",
@@ -55,12 +42,12 @@
"'\\nCalculating the Duration and Other Interest Rate Sensitivity Metrics in an Interest Rate Swap\\nBased on Bond Math: The Theory Behind the Formulas, Second Edition by Donald J. Smith\\n'"
]
},
- "execution_count": 2,
+ "execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 2
+ "execution_count": 54
},
{
"metadata": {},
@@ -77,8 +64,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.422259Z",
- "start_time": "2025-05-23T07:06:02.399642Z"
+ "end_time": "2025-05-26T01:38:51.453736Z",
+ "start_time": "2025-05-26T01:38:51.448754Z"
}
},
"cell_type": "code",
@@ -117,13 +104,13 @@
],
"id": "1ebf43316efee835",
"outputs": [],
- "execution_count": 3
+ "execution_count": 55
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.435325Z",
- "start_time": "2025-05-23T07:06:02.431814Z"
+ "end_time": "2025-05-26T01:38:51.479888Z",
+ "start_time": "2025-05-26T01:38:51.476727Z"
}
},
"cell_type": "code",
@@ -134,7 +121,7 @@
],
"id": "8e46f142f3cba5d7",
"outputs": [],
- "execution_count": 4
+ "execution_count": 56
},
{
"metadata": {},
@@ -145,8 +132,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.451098Z",
- "start_time": "2025-05-23T07:06:02.444694Z"
+ "end_time": "2025-05-26T01:38:51.489195Z",
+ "start_time": "2025-05-26T01:38:51.484891Z"
}
},
"cell_type": "code",
@@ -164,7 +151,7 @@
],
"id": "290b7a06932da41d",
"outputs": [],
- "execution_count": 5
+ "execution_count": 57
},
{
"metadata": {},
@@ -175,8 +162,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.466457Z",
- "start_time": "2025-05-23T07:06:02.460826Z"
+ "end_time": "2025-05-26T01:38:51.510004Z",
+ "start_time": "2025-05-26T01:38:51.503319Z"
}
},
"cell_type": "code",
@@ -192,12 +179,12 @@
"0.03404344249149676"
]
},
- "execution_count": 6,
+ "execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 6
+ "execution_count": 58
},
{
"metadata": {},
@@ -208,8 +195,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.510127Z",
- "start_time": "2025-05-23T07:06:02.504897Z"
+ "end_time": "2025-05-26T01:38:51.544573Z",
+ "start_time": "2025-05-26T01:38:51.538275Z"
}
},
"cell_type": "code",
@@ -222,18 +209,18 @@
"5070.7014320408925"
]
},
- "execution_count": 7,
+ "execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 7
+ "execution_count": 59
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.538230Z",
- "start_time": "2025-05-23T07:06:02.532904Z"
+ "end_time": "2025-05-26T01:38:51.589597Z",
+ "start_time": "2025-05-26T01:38:51.584447Z"
}
},
"cell_type": "code",
@@ -250,18 +237,18 @@
"-6.767653343606554"
]
},
- "execution_count": 8,
+ "execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 8
+ "execution_count": 60
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.577877Z",
- "start_time": "2025-05-23T07:06:02.572337Z"
+ "end_time": "2025-05-26T01:38:51.643031Z",
+ "start_time": "2025-05-26T01:38:51.637701Z"
}
},
"cell_type": "code",
@@ -277,18 +264,18 @@
"6.767653343606554"
]
},
- "execution_count": 9,
+ "execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 9
+ "execution_count": 61
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.618947Z",
- "start_time": "2025-05-23T07:06:02.613773Z"
+ "end_time": "2025-05-26T01:38:51.675717Z",
+ "start_time": "2025-05-26T01:38:51.669055Z"
}
},
"cell_type": "code",
@@ -304,18 +291,18 @@
"-6.710540865595371"
]
},
- "execution_count": 10,
+ "execution_count": 62,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 10
+ "execution_count": 62
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.657887Z",
- "start_time": "2025-05-23T07:06:02.652511Z"
+ "end_time": "2025-05-26T01:38:51.714007Z",
+ "start_time": "2025-05-26T01:38:51.709011Z"
}
},
"cell_type": "code",
@@ -331,18 +318,18 @@
"6.710540865595371"
]
},
- "execution_count": 11,
+ "execution_count": 63,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 11
+ "execution_count": 63
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.688544Z",
- "start_time": "2025-05-23T07:06:02.683201Z"
+ "end_time": "2025-05-26T01:38:51.740994Z",
+ "start_time": "2025-05-26T01:38:51.735899Z"
}
},
"cell_type": "code",
@@ -358,18 +345,18 @@
"-10065.811298393059"
]
},
- "execution_count": 12,
+ "execution_count": 64,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 12
+ "execution_count": 64
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.730798Z",
- "start_time": "2025-05-23T07:06:02.725738Z"
+ "end_time": "2025-05-26T01:38:51.782002Z",
+ "start_time": "2025-05-26T01:38:51.775583Z"
}
},
"cell_type": "code",
@@ -385,18 +372,18 @@
"10065.811298393059"
]
},
- "execution_count": 13,
+ "execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 13
+ "execution_count": 65
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.778884Z",
- "start_time": "2025-05-23T07:06:02.769818Z"
+ "end_time": "2025-05-26T01:38:51.811959Z",
+ "start_time": "2025-05-26T01:38:51.805127Z"
}
},
"cell_type": "code",
@@ -500,12 +487,68 @@
""
]
},
- "execution_count": 14,
+ "execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 14
+ "execution_count": 66
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-26T01:38:51.857020Z",
+ "start_time": "2025-05-26T01:38:51.849735Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "print(swap.macaulay_duration(value_dt, zero_curve, SwapTypes.PAY,payment_periods),\n",
+ " swap.modified_duration(value_dt, zero_curve, SwapTypes.PAY,payment_periods),\n",
+ " swap.basis_point_value(value_dt, zero_curve, SwapTypes.PAY,payment_periods))\n"
+ ],
+ "id": "7f15cd3f76dfa4c1",
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "-6.767653343606554 -6.710540865595371 -10065.811298393059\n"
+ ]
+ }
+ ],
+ "execution_count": 67
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "",
+ "id": "61aa4eb194b3d1d0"
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-26T01:38:52.000991Z",
+ "start_time": "2025-05-26T01:38:51.995187Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "print(swap.macaulay_duration(value_dt, zero_curve, SwapTypes.RECEIVE,payment_periods),\n",
+ " swap.modified_duration(value_dt, zero_curve, SwapTypes.RECEIVE,payment_periods),\n",
+ " swap.basis_point_value(value_dt, zero_curve, SwapTypes.RECEIVE,payment_periods))"
+ ],
+ "id": "a5c75d93d6565468",
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "6.767653343606554 6.710540865595371 -10065.811298393059\n"
+ ]
+ }
+ ],
+ "execution_count": 68
},
{
"metadata": {},
@@ -522,8 +565,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.844522Z",
- "start_time": "2025-05-23T07:06:02.840897Z"
+ "end_time": "2025-05-26T01:38:52.113722Z",
+ "start_time": "2025-05-26T01:38:52.109152Z"
}
},
"cell_type": "code",
@@ -549,13 +592,13 @@
],
"id": "5892081fb637c810",
"outputs": [],
- "execution_count": 15
+ "execution_count": 69
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:02.897137Z",
- "start_time": "2025-05-23T07:06:02.892722Z"
+ "end_time": "2025-05-26T01:38:52.183795Z",
+ "start_time": "2025-05-26T01:38:52.179481Z"
}
},
"cell_type": "code",
@@ -574,12 +617,12 @@
"31-MAR-2024"
]
},
- "execution_count": 16,
+ "execution_count": 70,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 16
+ "execution_count": 70
},
{
"metadata": {},
@@ -590,8 +633,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:03.045244Z",
- "start_time": "2025-05-23T07:06:03.040708Z"
+ "end_time": "2025-05-26T01:38:52.215532Z",
+ "start_time": "2025-05-26T01:38:52.211001Z"
}
},
"cell_type": "code",
@@ -610,13 +653,13 @@
],
"id": "8acc84107dae665e",
"outputs": [],
- "execution_count": 17
+ "execution_count": 71
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:03.139582Z",
- "start_time": "2025-05-23T07:06:03.133116Z"
+ "end_time": "2025-05-26T01:38:52.258023Z",
+ "start_time": "2025-05-26T01:38:52.253684Z"
}
},
"cell_type": "code",
@@ -629,18 +672,18 @@
"-404094.769553849"
]
},
- "execution_count": 18,
+ "execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 18
+ "execution_count": 72
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-23T07:06:03.193803Z",
- "start_time": "2025-05-23T07:06:03.181239Z"
+ "end_time": "2025-05-26T01:38:52.303046Z",
+ "start_time": "2025-05-26T01:38:52.290708Z"
}
},
"cell_type": "code",
@@ -747,12 +790,25 @@
""
]
},
- "execution_count": 19,
+ "execution_count": 73,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 19
+ "execution_count": 73
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-05-26T01:38:52.350298Z",
+ "start_time": "2025-05-26T01:38:52.347838Z"
+ }
+ },
+ "cell_type": "code",
+ "source": "",
+ "id": "25eb3b1fb6b97bde",
+ "outputs": [],
+ "execution_count": null
}
],
"metadata": {
From a3efa4995e708dbd6acec4846f23df202165d7ad Mon Sep 17 00:00:00 2001
From: piper0124 <55830785+piper0124@users.noreply.github.com>
Date: Mon, 26 May 2025 13:32:07 +0800
Subject: [PATCH 12/12] Upgraded the computation of multiple metrics
1. Use the class member fixed_leg_type(SwapTypes.PAY or SwapTypes.RECEIVE) to determine whether a counterparty is a buyer or seller, and calculate the Macaulay duration, modified duration, basis point value (BPV), and present value change of the interest rate swap (IRS).
2. Updated the notebook: FINIBORSWAP_ReplicationBONDMATHDurationExample.ipynb.
---
financepy/products/rates/ibor_swap.py | 148 +-----
..._ReplicationgBONDMATHDurationExample.ipynb | 473 ++++++------------
2 files changed, 159 insertions(+), 462 deletions(-)
diff --git a/financepy/products/rates/ibor_swap.py b/financepy/products/rates/ibor_swap.py
index e01b27ee..efc770ba 100644
--- a/financepy/products/rates/ibor_swap.py
+++ b/financepy/products/rates/ibor_swap.py
@@ -392,34 +392,8 @@ def print_payments(self):
###########################################################################
- def payer_side_macaulay_duration(self, value_dt, discount_curve, payment_periods: float):
- """Calculation of the Payer's Macaulay Duration in an Interest Rate Swap
- Based on Bond Math: The Theory Behind the Formulas, Second Edition by
- Donald J. Smith
- """
- # Get coupon frequency
- coupon_frequency = self.fixed_leg.freq_type.value
-
- # Get swap rate
- swap_rate_val = self.swap_rate(value_dt,discount_curve)
-
- y = swap_rate_val / coupon_frequency
- # payment_periods is the number of periods to maturity as of the beginning of the period;
- # for instance, If the start date of the interest rate swap is 2024-01-01,
- # the end date is 2025-12-31, the valuation date is 2024-03-31,
- # and the frequency type is QUARTERLY,
- # then the number of payment periods is 8; it is independent of the valuation date.
- N = payment_periods
- c = swap_rate_val / coupon_frequency
- md1 = (1 + y) / y
- md2 = 1 + y + (N * (c - y))
- md3 = c * ((1 + y) ** N - 1) + y
- mac_duration = 1 - (md1 - md2 / md3)
- return mac_duration
-
-
def macaulay_duration(self, value_dt, discount_curve, swap_type, payment_periods: float):
- """Calculation of the Payer's Macaulay Duration in an Interest Rate Swap
+ """Calculation of the Macaulay Duration in an Interest Rate Swap
Based on Bond Math: The Theory Behind the Formulas, Second Edition by
Donald J. Smith
"""
@@ -427,7 +401,7 @@ def macaulay_duration(self, value_dt, discount_curve, swap_type, payment_periods
coupon_frequency = self.fixed_leg.freq_type.value
# Get swap rate
- swap_rate_val = self.swap_rate(value_dt,discount_curve)
+ swap_rate_val = self.swap_rate(value_dt, discount_curve)
y = swap_rate_val / coupon_frequency
# payment_periods is the number of periods to maturity as of the beginning of the period;
@@ -447,37 +421,16 @@ def macaulay_duration(self, value_dt, discount_curve, swap_type, payment_periods
The fixed‐rate payer and floating‐rate receiver,
sometimes is said to be the “buyer” of the swap, or is “long” the swap.
"""
- if swap_type == SwapTypes.PAY:
+ if swap_type == SwapTypes.PAY:
mac_duration = 1 - (md1 - md2 / md3)
- elif swap_type == SwapTypes.RECEIVE:
- mac_duration = (1 - (md1 - md2 / md3))*(-1)
+ elif swap_type == SwapTypes.RECEIVE:
+ mac_duration = (1 - (md1 - md2 / md3)) * (-1)
return mac_duration
###########################################################################
- def receiver_side_macaulay_duration(self, value_dt, discount_curve,payment_periods: float):
- """Calculation of the Receiver's Macaulay Duration in an Interest Rate Swap
- Based on Bond Math: The Theory Behind the Formulas, Second Edition by
- Donald J. Smith
- """
- return self.payer_side_macaulay_duration(value_dt, discount_curve,payment_periods)*(-1)
-
- ###########################################################################
-
- def payer_side_modified_duration(self, value_dt, discount_curve,payment_periods: float):
- """Computation of the Modified Duration for the Fixed-Rate
- Payer's Perspective in Interest Rate Swap
- """
- # Get coupon frequency
- coupon_frequency = self.fixed_leg.freq_type.value
-
- # Get swap rate
- swap_rate_val = self.swap_rate(value_dt,discount_curve)
-
- return self.payer_side_macaulay_duration(value_dt, discount_curve,payment_periods)/(1+swap_rate_val/coupon_frequency)
-
def modified_duration(self, value_dt, discount_curve, swap_type, payment_periods: float):
"""Computation of the Modified Duration for the Fixed-Rate
Payer's Perspective in Interest Rate Swap
@@ -488,50 +441,13 @@ def modified_duration(self, value_dt, discount_curve, swap_type, payment_periods
# Get swap rate
swap_rate_val = self.swap_rate(value_dt, discount_curve)
- if swap_type == SwapTypes.PAY:
- modified_duration = (self.macaulay_duration(value_dt, discount_curve, swap_type, payment_periods) /
- (1 + swap_rate_val / coupon_frequency))
-
- elif swap_type == SwapTypes.RECEIVE:
- modified_duration = (self.macaulay_duration(value_dt, discount_curve, swap_type, payment_periods) /
- (1 + swap_rate_val / coupon_frequency))
+ modified_duration = (self.macaulay_duration(value_dt, discount_curve, swap_type, payment_periods) /
+ (1 + swap_rate_val / coupon_frequency))
return modified_duration
-
###########################################################################
- def receiver_side_modified_duration(self, value_dt, discount_curve,payment_periods: float):
- """Computation of the Modified Duration for the Fixed-Rate
- Receiver's Perspective in Interest Rate Swap
- """
- return self.payer_side_modified_duration(value_dt, discount_curve,payment_periods)*(-1)
-
- ###########################################################################
-
- def payer_side_profits(self,
- value_dt,
- discount_curve,payment_periods: float,
- swap_rate_changes: float ):
- """Computation of the Profits for the Fixed-Rate Payer's Perspective in Interest Rate Swap
- """
- # Get coupon frequency
- coupon_frequency = self.fixed_leg.freq_type.value
-
- annualized_modi_dur = self.payer_side_modified_duration(value_dt, discount_curve,payment_periods)/coupon_frequency
- return (-1)*(annualized_modi_dur*self.fixed_leg.notional*swap_rate_changes)
-
- ###########################################################################
-
- def receiver_side_profits(self,
- value_dt,
- discount_curve,payment_periods: float,
- swap_rate_changes: float):
- """Computation of the Profits for the Fixed-Rate Receiver's Perspective in Interest Rate Swap
- """
- return self.payer_side_profits(value_dt, discount_curve,payment_periods,swap_rate_changes)*(-1)
-
-
def change_in_market_value(self,
value_dt, discount_curve, swap_type, payment_periods: float,
swap_rate_changes: float):
@@ -540,63 +456,31 @@ def change_in_market_value(self,
# Get coupon frequency
coupon_frequency = self.fixed_leg.freq_type.value
- annualized_modi_dur = self.modified_duration(value_dt, discount_curve,swap_type,payment_periods)/coupon_frequency
+ annualized_modi_dur = self.modified_duration(value_dt, discount_curve, swap_type,
+ payment_periods) / coupon_frequency
- if swap_type == SwapTypes.PAY:
- delta_mv=(-1)*(annualized_modi_dur*self.fixed_leg.notional*swap_rate_changes)
-
- elif swap_type == SwapTypes.RECEIVE:
- delta_mv=(annualized_modi_dur*self.fixed_leg.notional*swap_rate_changes)
+ delta_mv = (-1) * (annualized_modi_dur * self.fixed_leg.notional * swap_rate_changes)
return delta_mv
###########################################################################
- def payer_side_BPV(self, value_dt, discount_curve,payment_periods: float,):
+ def basis_point_value(self, value_dt, discount_curve, swap_type, payment_periods: float):
"""
- calculate the basis‐point‐value (BPV) for the payer_side of the swap,
+ calculate the basis‐point‐value (BPV) of the swap,
which is swap's modified duration times the notional principal,
times one basis point (0.0001)
"""
- bp=0.0001
- # Get coupon frequency
- coupon_frequency = self.fixed_leg.freq_type.value
- modi_dur = self.payer_side_modified_duration(value_dt, discount_curve,payment_periods)
- annualized_modi_dur= modi_dur/coupon_frequency
- return annualized_modi_dur*self.fixed_leg.notional*bp
-
- ###########################################################################
-
- def receiver_side_BPV(self, value_dt, discount_curve,payment_periods: float,):
- """
- calculate the basis‐point‐value (BPV) for receiver_side of the swap,
- which is swap's modified duration times the notional principal,
- times one basis point (0.0001)
- """
- return self.payer_side_BPV(value_dt, discount_curve,payment_periods)*(-1)
-
- ###########################################################################
-
- def basis_point_value (self,value_dt, discount_curve,swap_type, payment_periods: float):
- """
- calculate the basis‐point‐value (BPV) for the payer_side of the swap,
- which is swap's modified duration times the notional principal,
- times one basis point (0.0001)
- """
- bp=0.0001
+ bp = 0.0001
# Get coupon frequency
coupon_frequency = self.fixed_leg.freq_type.value
modi_dur = self.modified_duration(value_dt, discount_curve, swap_type, payment_periods)
- annualized_modi_dur= modi_dur/coupon_frequency
-
- if swap_type == SwapTypes.PAY:
- BPV=annualized_modi_dur*self.fixed_leg.notional*bp
-
- elif swap_type == SwapTypes.RECEIVE:
- BPV=annualized_modi_dur*self.fixed_leg.notional*bp
+ annualized_modi_dur = modi_dur / coupon_frequency
+ BPV = annualized_modi_dur * self.fixed_leg.notional * bp
return BPV
+ ###########################################################################
def __repr__(self):
diff --git a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
index c0f5d1b9..34c69cf8 100644
--- a/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
+++ b/notebooks/products/rates/FINIBORSWAP_ReplicationgBONDMATHDurationExample.ipynb
@@ -6,8 +6,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.362248Z",
- "start_time": "2025-05-26T01:38:51.358838Z"
+ "end_time": "2025-05-26T05:31:31.795273Z",
+ "start_time": "2025-05-26T05:31:31.791904Z"
}
},
"source": [
@@ -18,36 +18,24 @@
"import numpy as np"
],
"outputs": [],
- "execution_count": 53
+ "execution_count": 15
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.410238Z",
- "start_time": "2025-05-26T01:38:51.406404Z"
+ "end_time": "2025-05-26T05:31:31.835720Z",
+ "start_time": "2025-05-26T05:31:31.831900Z"
}
},
"cell_type": "code",
"source": [
- " \"\"\"\n",
- "Calculating the Duration and Other Interest Rate Sensitivity Metrics in an Interest Rate Swap\n",
- "Based on Bond Math: The Theory Behind the Formulas, Second Edition by Donald J. Smith\n",
- " \"\"\""
+ "# Calculating the macaulay_duration, modified_duration, basis‐point‐value and change_in_value_of_IRS\n",
+ "# in an Interest Rate Swap\n",
+ "# Based on Bond Math: The Theory Behind the Formulas, Second Edition by Donald J. Smith\n"
],
"id": "1771696c9beba73c",
- "outputs": [
- {
- "data": {
- "text/plain": [
- "'\\nCalculating the Duration and Other Interest Rate Sensitivity Metrics in an Interest Rate Swap\\nBased on Bond Math: The Theory Behind the Formulas, Second Edition by Donald J. Smith\\n'"
- ]
- },
- "execution_count": 54,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 54
+ "outputs": [],
+ "execution_count": 16
},
{
"metadata": {},
@@ -64,8 +52,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.453736Z",
- "start_time": "2025-05-26T01:38:51.448754Z"
+ "end_time": "2025-05-26T05:31:31.847045Z",
+ "start_time": "2025-05-26T05:31:31.842610Z"
}
},
"cell_type": "code",
@@ -104,13 +92,13 @@
],
"id": "1ebf43316efee835",
"outputs": [],
- "execution_count": 55
+ "execution_count": 17
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.479888Z",
- "start_time": "2025-05-26T01:38:51.476727Z"
+ "end_time": "2025-05-26T05:31:31.862908Z",
+ "start_time": "2025-05-26T05:31:31.858964Z"
}
},
"cell_type": "code",
@@ -121,7 +109,7 @@
],
"id": "8e46f142f3cba5d7",
"outputs": [],
- "execution_count": 56
+ "execution_count": 18
},
{
"metadata": {},
@@ -132,8 +120,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.489195Z",
- "start_time": "2025-05-26T01:38:51.484891Z"
+ "end_time": "2025-05-26T05:31:31.880211Z",
+ "start_time": "2025-05-26T05:31:31.875398Z"
}
},
"cell_type": "code",
@@ -151,7 +139,7 @@
],
"id": "290b7a06932da41d",
"outputs": [],
- "execution_count": 57
+ "execution_count": 19
},
{
"metadata": {},
@@ -162,8 +150,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.510004Z",
- "start_time": "2025-05-26T01:38:51.503319Z"
+ "end_time": "2025-05-26T05:31:31.898089Z",
+ "start_time": "2025-05-26T05:31:31.892320Z"
}
},
"cell_type": "code",
@@ -179,12 +167,12 @@
"0.03404344249149676"
]
},
- "execution_count": 58,
+ "execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 58
+ "execution_count": 20
},
{
"metadata": {},
@@ -195,8 +183,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.544573Z",
- "start_time": "2025-05-26T01:38:51.538275Z"
+ "end_time": "2025-05-26T05:31:31.945567Z",
+ "start_time": "2025-05-26T05:31:31.941273Z"
}
},
"cell_type": "code",
@@ -209,198 +197,52 @@
"5070.7014320408925"
]
},
- "execution_count": 59,
+ "execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 59
+ "execution_count": 21
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.589597Z",
- "start_time": "2025-05-26T01:38:51.584447Z"
+ "end_time": "2025-05-26T05:31:31.990346Z",
+ "start_time": "2025-05-26T05:31:31.986969Z"
}
},
"cell_type": "code",
- "source": [
- "payment_periods = 8\n",
- "payer_side_macaulay_duration = swap.payer_side_macaulay_duration(value_dt, zero_curve, payment_periods)\n",
- "payer_side_macaulay_duration"
- ],
+ "source": "payment_periods = 8\n",
"id": "3f988f26e6662203",
- "outputs": [
- {
- "data": {
- "text/plain": [
- "-6.767653343606554"
- ]
- },
- "execution_count": 60,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 60
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.643031Z",
- "start_time": "2025-05-26T01:38:51.637701Z"
- }
- },
- "cell_type": "code",
- "source": [
- "receiver_side_macaulay_duration = swap.receiver_side_macaulay_duration(value_dt, zero_curve, payment_periods)\n",
- "receiver_side_macaulay_duration"
- ],
- "id": "96d568f7a71861fe",
- "outputs": [
- {
- "data": {
- "text/plain": [
- "6.767653343606554"
- ]
- },
- "execution_count": 61,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 61
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.675717Z",
- "start_time": "2025-05-26T01:38:51.669055Z"
- }
- },
- "cell_type": "code",
- "source": [
- "payer_side_modified_duration = swap.payer_side_modified_duration(value_dt, zero_curve, payment_periods)\n",
- "payer_side_modified_duration"
- ],
- "id": "ec2187c7336c1bc3",
- "outputs": [
- {
- "data": {
- "text/plain": [
- "-6.710540865595371"
- ]
- },
- "execution_count": 62,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 62
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.714007Z",
- "start_time": "2025-05-26T01:38:51.709011Z"
- }
- },
- "cell_type": "code",
- "source": [
- "receiver_side_modified_duration = swap.receiver_side_modified_duration(value_dt, zero_curve, payment_periods)\n",
- "receiver_side_modified_duration"
- ],
- "id": "2c1b845afaf5e18f",
- "outputs": [
- {
- "data": {
- "text/plain": [
- "6.710540865595371"
- ]
- },
- "execution_count": 63,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 63
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.740994Z",
- "start_time": "2025-05-26T01:38:51.735899Z"
- }
- },
- "cell_type": "code",
- "source": [
- "payer_side_BPV = swap.payer_side_BPV(value_dt, zero_curve, payment_periods)\n",
- "payer_side_BPV"
- ],
- "id": "602fd89b88bd58f0",
- "outputs": [
- {
- "data": {
- "text/plain": [
- "-10065.811298393059"
- ]
- },
- "execution_count": 64,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 64
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.782002Z",
- "start_time": "2025-05-26T01:38:51.775583Z"
- }
- },
- "cell_type": "code",
- "source": [
- "receiver_side_BPV = swap.receiver_side_BPV(value_dt, zero_curve, payment_periods)\n",
- "receiver_side_BPV"
- ],
- "id": "b868dc3219fa867",
- "outputs": [
- {
- "data": {
- "text/plain": [
- "10065.811298393059"
- ]
- },
- "execution_count": 65,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 65
+ "outputs": [],
+ "execution_count": 22
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.811959Z",
- "start_time": "2025-05-26T01:38:51.805127Z"
+ "end_time": "2025-05-26T05:31:32.021487Z",
+ "start_time": "2025-05-26T05:31:32.014011Z"
}
},
"cell_type": "code",
"source": [
"index = ['swap_rate',\n",
- " 'payer_side_macaulay_duration',\n",
- " 'payer_side_modified_duration',\n",
- " 'payer_side_BPV',\n",
- " 'receiver_side_macaulay_duration',\n",
- " 'receiver_side_modified_duration',\n",
- " 'receiver_side_BPV']\n",
+ " 'payer_macaulay_duration',\n",
+ " 'payer_modified_duration',\n",
+ " 'payer_BPV',\n",
+ " 'change_in_value_of_payer',\n",
+ " 'receiver_macaulay_duration',\n",
+ " 'receiver_modified_duration',\n",
+ " 'receiver_BPV',\n",
+ " 'change_in_value_of_receiver', ]\n",
+ "\n",
"data_financepy = [swap_rate,\n",
- " payer_side_macaulay_duration, payer_side_modified_duration, payer_side_BPV,\n",
- " receiver_side_macaulay_duration, receiver_side_modified_duration, receiver_side_BPV]\n",
+ " np.nan, np.nan, np.nan, np.nan,\n",
+ " np.nan, np.nan, np.nan, np.nan]\n",
+ "\n",
"data_bondmath = [0.034,\n",
- " np.nan, np.nan, np.nan,\n",
- " np.nan, np.nan, np.nan]\n",
+ " np.nan, np.nan, np.nan, np.nan,\n",
+ " np.nan, np.nan, np.nan, np.nan, ]\n",
"data = {\n",
" 'financepy': data_financepy,\n",
" 'Bond Math by Donald J. Smith': data_bondmath\n",
@@ -414,14 +256,16 @@
{
"data": {
"text/plain": [
- " financepy Bond Math by Donald J. Smith\n",
- "swap_rate 0.034043 0.034\n",
- "payer_side_macaulay_duration -6.767653 NaN\n",
- "payer_side_modified_duration -6.710541 NaN\n",
- "payer_side_BPV -10065.811298 NaN\n",
- "receiver_side_macaulay_duration 6.767653 NaN\n",
- "receiver_side_modified_duration 6.710541 NaN\n",
- "receiver_side_BPV 10065.811298 NaN"
+ " financepy Bond Math by Donald J. Smith\n",
+ "swap_rate 0.034043 0.034\n",
+ "payer_macaulay_duration NaN NaN\n",
+ "payer_modified_duration NaN NaN\n",
+ "payer_BPV NaN NaN\n",
+ "change_in_value_of_payer NaN NaN\n",
+ "receiver_macaulay_duration NaN NaN\n",
+ "receiver_modified_duration NaN NaN\n",
+ "receiver_BPV NaN NaN\n",
+ "change_in_value_of_receiver NaN NaN"
],
"text/html": [
"\n",
@@ -453,33 +297,43 @@
"
0.034 | \n",
" \n",
" \n",
- " payer_side_macaulay_duration | \n",
- " -6.767653 | \n",
+ " payer_macaulay_duration | \n",
+ " NaN | \n",
" NaN | \n",
"
\n",
" \n",
- " payer_side_modified_duration | \n",
- " -6.710541 | \n",
+ " payer_modified_duration | \n",
+ " NaN | \n",
" NaN | \n",
"
\n",
" \n",
- " payer_side_BPV | \n",
- " -10065.811298 | \n",
+ " payer_BPV | \n",
+ " NaN | \n",
" NaN | \n",
"
\n",
" \n",
- " receiver_side_macaulay_duration | \n",
- " 6.767653 | \n",
+ " change_in_value_of_payer | \n",
+ " NaN | \n",
" NaN | \n",
"
\n",
" \n",
- " receiver_side_modified_duration | \n",
- " 6.710541 | \n",
+ " receiver_macaulay_duration | \n",
+ " NaN | \n",
" NaN | \n",
"
\n",
" \n",
- " receiver_side_BPV | \n",
- " 10065.811298 | \n",
+ " receiver_modified_duration | \n",
+ " NaN | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " receiver_BPV | \n",
+ " NaN | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " change_in_value_of_receiver | \n",
+ " NaN | \n",
" NaN | \n",
"
\n",
" \n",
@@ -487,37 +341,12 @@
""
]
},
- "execution_count": 66,
+ "execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 66
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-26T01:38:51.857020Z",
- "start_time": "2025-05-26T01:38:51.849735Z"
- }
- },
- "cell_type": "code",
- "source": [
- "print(swap.macaulay_duration(value_dt, zero_curve, SwapTypes.PAY,payment_periods),\n",
- " swap.modified_duration(value_dt, zero_curve, SwapTypes.PAY,payment_periods),\n",
- " swap.basis_point_value(value_dt, zero_curve, SwapTypes.PAY,payment_periods))\n"
- ],
- "id": "7f15cd3f76dfa4c1",
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "-6.767653343606554 -6.710540865595371 -10065.811298393059\n"
- ]
- }
- ],
- "execution_count": 67
+ "execution_count": 23
},
{
"metadata": {},
@@ -525,31 +354,6 @@
"source": "",
"id": "61aa4eb194b3d1d0"
},
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-26T01:38:52.000991Z",
- "start_time": "2025-05-26T01:38:51.995187Z"
- }
- },
- "cell_type": "code",
- "source": [
- "print(swap.macaulay_duration(value_dt, zero_curve, SwapTypes.RECEIVE,payment_periods),\n",
- " swap.modified_duration(value_dt, zero_curve, SwapTypes.RECEIVE,payment_periods),\n",
- " swap.basis_point_value(value_dt, zero_curve, SwapTypes.RECEIVE,payment_periods))"
- ],
- "id": "a5c75d93d6565468",
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "6.767653343606554 6.710540865595371 -10065.811298393059\n"
- ]
- }
- ],
- "execution_count": 68
- },
{
"metadata": {},
"cell_type": "markdown",
@@ -565,8 +369,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:52.113722Z",
- "start_time": "2025-05-26T01:38:52.109152Z"
+ "end_time": "2025-05-26T05:31:32.072889Z",
+ "start_time": "2025-05-26T05:31:32.068405Z"
}
},
"cell_type": "code",
@@ -592,13 +396,13 @@
],
"id": "5892081fb637c810",
"outputs": [],
- "execution_count": 69
+ "execution_count": 24
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:52.183795Z",
- "start_time": "2025-05-26T01:38:52.179481Z"
+ "end_time": "2025-05-26T05:31:32.129906Z",
+ "start_time": "2025-05-26T05:31:32.125936Z"
}
},
"cell_type": "code",
@@ -617,12 +421,12 @@
"31-MAR-2024"
]
},
- "execution_count": 70,
+ "execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 70
+ "execution_count": 25
},
{
"metadata": {},
@@ -633,8 +437,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:52.215532Z",
- "start_time": "2025-05-26T01:38:52.211001Z"
+ "end_time": "2025-05-26T05:31:32.243507Z",
+ "start_time": "2025-05-26T05:31:32.239142Z"
}
},
"cell_type": "code",
@@ -653,13 +457,13 @@
],
"id": "8acc84107dae665e",
"outputs": [],
- "execution_count": 71
+ "execution_count": 26
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:52.258023Z",
- "start_time": "2025-05-26T01:38:52.253684Z"
+ "end_time": "2025-05-26T05:31:32.335358Z",
+ "start_time": "2025-05-26T05:31:32.329091Z"
}
},
"cell_type": "code",
@@ -672,37 +476,47 @@
"-404094.769553849"
]
},
- "execution_count": 72,
+ "execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 72
+ "execution_count": 27
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-05-26T01:38:52.303046Z",
- "start_time": "2025-05-26T01:38:52.290708Z"
+ "end_time": "2025-05-26T05:31:32.392498Z",
+ "start_time": "2025-05-26T05:31:32.379861Z"
}
},
"cell_type": "code",
"source": [
+ "# a -40 basis point change in the swap fi xed rate\n",
+ "swap_rate_changes = -0.004\n",
+ "\n",
"data_financepy_3m = [swap_3m.swap_rate(value_dt_3m, zero_curve_3m),\n",
- " swap_3m.payer_side_macaulay_duration(value_dt_3m, zero_curve_3m, payment_periods),\n",
- " swap_3m.payer_side_modified_duration(value_dt_3m, zero_curve_3m, payment_periods),\n",
- " swap_3m.payer_side_BPV(value_dt_3m, zero_curve_3m, payment_periods),\n",
- " swap_3m.receiver_side_macaulay_duration(value_dt_3m, zero_curve_3m, payment_periods),\n",
- " swap_3m.receiver_side_modified_duration(value_dt_3m, zero_curve_3m, payment_periods),\n",
- " swap_3m.receiver_side_BPV(value_dt_3m, zero_curve_3m, payment_periods)]\n",
+ " swap_3m.macaulay_duration(value_dt_3m, zero_curve_3m, swap_type, payment_periods),\n",
+ " swap_3m.modified_duration(value_dt_3m, zero_curve_3m, swap_type, payment_periods),\n",
+ " swap_3m.basis_point_value(value_dt_3m, zero_curve_3m, swap_type, payment_periods),\n",
+ " swap_3m.change_in_market_value(value_dt_3m, zero_curve_3m, swap_type, payment_periods,\n",
+ " swap_rate_changes),\n",
+ " swap_3m.macaulay_duration(value_dt_3m, zero_curve_3m, SwapTypes.RECEIVE, payment_periods),\n",
+ " swap_3m.modified_duration(value_dt_3m, zero_curve_3m, SwapTypes.RECEIVE, payment_periods),\n",
+ " swap_3m.basis_point_value(value_dt_3m, zero_curve_3m, SwapTypes.RECEIVE, payment_periods),\n",
+ " swap_3m.change_in_market_value(value_dt_3m, zero_curve_3m, SwapTypes.RECEIVE,\n",
+ " payment_periods, swap_rate_changes)\n",
+ " ]\n",
"\n",
"data_bondmath_3m = [0.030,\n",
" -6.769,\n",
" -6.7186,\n",
" -10077.9,\n",
+ " -403116,\n",
" 6.769,\n",
" 6.7186,\n",
- " 10077.9]\n",
+ " 10077.9,\n",
+ " 403116]\n",
"\n",
"data_3m = {\n",
" 'financepy': data_financepy_3m,\n",
@@ -717,14 +531,16 @@
{
"data": {
"text/plain": [
- " financepy Bond Math by Donald J. Smith\n",
- "swap_rate 0.030066 0.0300\n",
- "payer_side_macaulay_duration -6.794199 -6.7690\n",
- "payer_side_modified_duration -6.743512 -6.7186\n",
- "payer_side_BPV -10115.267497 -10077.9000\n",
- "receiver_side_macaulay_duration 6.794199 6.7690\n",
- "receiver_side_modified_duration 6.743512 6.7186\n",
- "receiver_side_BPV 10115.267497 10077.9000"
+ " financepy Bond Math by Donald J. Smith\n",
+ "swap_rate 0.030066 0.0300\n",
+ "payer_macaulay_duration -6.794199 -6.7690\n",
+ "payer_modified_duration -6.743512 -6.7186\n",
+ "payer_BPV -10115.267497 -10077.9000\n",
+ "change_in_value_of_payer -404610.699889 -403116.0000\n",
+ "receiver_macaulay_duration 6.794199 6.7690\n",
+ "receiver_modified_duration 6.743512 6.7186\n",
+ "receiver_BPV 10115.267497 10077.9000\n",
+ "change_in_value_of_receiver 404610.699889 403116.0000"
],
"text/html": [
"\n",
@@ -756,59 +572,56 @@
"
0.0300 | \n",
" \n",
" \n",
- " payer_side_macaulay_duration | \n",
+ " payer_macaulay_duration | \n",
" -6.794199 | \n",
" -6.7690 | \n",
"
\n",
" \n",
- " payer_side_modified_duration | \n",
+ " payer_modified_duration | \n",
" -6.743512 | \n",
" -6.7186 | \n",
"
\n",
" \n",
- " payer_side_BPV | \n",
+ " payer_BPV | \n",
" -10115.267497 | \n",
" -10077.9000 | \n",
"
\n",
" \n",
- " receiver_side_macaulay_duration | \n",
+ " change_in_value_of_payer | \n",
+ " -404610.699889 | \n",
+ " -403116.0000 | \n",
+ "
\n",
+ " \n",
+ " receiver_macaulay_duration | \n",
" 6.794199 | \n",
" 6.7690 | \n",
"
\n",
" \n",
- " receiver_side_modified_duration | \n",
+ " receiver_modified_duration | \n",
" 6.743512 | \n",
" 6.7186 | \n",
"
\n",
" \n",
- " receiver_side_BPV | \n",
+ " receiver_BPV | \n",
" 10115.267497 | \n",
" 10077.9000 | \n",
"
\n",
+ " \n",
+ " change_in_value_of_receiver | \n",
+ " 404610.699889 | \n",
+ " 403116.0000 | \n",
+ "
\n",
" \n",
"\n",
""
]
},
- "execution_count": 73,
+ "execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 73
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-05-26T01:38:52.350298Z",
- "start_time": "2025-05-26T01:38:52.347838Z"
- }
- },
- "cell_type": "code",
- "source": "",
- "id": "25eb3b1fb6b97bde",
- "outputs": [],
- "execution_count": null
+ "execution_count": 28
}
],
"metadata": {