Interest Rate Risk Measurement using Duration, Convexity -Excel / Python
Outline for this article :
Interest Rate Risk Management:
Introduction:
Companies often face two key financial risk exposures, interest rate risk and Foreign exchange risk. Int. rate risk is concerned with variability of profit, cash flows or the valuation of a company due to movements of interest rates. Int. rate risk is the most important of all financial risks, in which changes in int rates affect a business due to the quantum of debts in their balance sheets and their linkage to base rates or any floating rates like LIBOR or SOFR etc. A highly leveraged company with a large amount of debt capital relative to equity capital may suffer financial distress if int rates increase dramatically. Alternatively, if cash surplus companies with huge investments on deposits linked t floating rate investments may suffer if interest rates fall dramatically.
Also, individuals who took floating rate mortgages may be impacted due to int rate changes.
Financial Institutions and Int rate risks:
Financial institutions and other market participants manage many types of
risks, including interest rate risk, credit risk, foreign exchange risk, liquidity risk, market risk, and operational risk. For a bank, int rate risk is the threat to the capital position and earnings of a bank driven by changes in the interest rates in the market. Changes to interest rates threaten a bank’s earnings by impacting its Net Interest Income (NII) which is the main source of earnings for a bank. The composition of total income and net Interest Incomes contribute more than 60% on average. Changes to interest rates also threaten the underlying value of the bank’s assets, liabilities, and off-balance sheet instruments, given the adverse impact which may arise on the present value of items, in particular their future cash flows.
Maturity of assets vs Maturity of Liabilities:
For most large banks, the average maturity of the assets is longer than the average maturity of the liabilities, as banks typically lend in the intermediate to long maturity sector and borrow in the short maturity sector. Average maturity, more popularly known as the duration of security, is the most used risk measure for measuring the interest rate risk exposure of the security. The key question is -How do the managers of financial institutions, such as banks, insurance companies, and index bond funds hedge against the effects of int. rate changes? One of the main activities of treasury department in any organization is the management of int rate risk.
What is Interest Rate Risk?
Interest rate risk refers to the potential impact of changes in interest rates on the value of financial instruments, such as bonds, loans, and other fixed-income securities. Price Sensitivity: When interest rates change, the prices of fixed-income securities (like bonds) fluctuate. The relationship is inverse: as interest rates rise, bond prices fall, and vice versa
Types of Interest Rate Risk:
1/ Price Risk (Market Risk)?
This risk arises from changes in bond prices due to interest rate movements. Longer-term bonds are more sensitive to rate changes. Price Risk (Market Risk), also known as interest rate risk, refers to the impact of changes in interest rates on the value of fixed-income securities (such as bonds).
Inverse Relationship (Convex )between Bond Prices and Interest Rates
Price Movement: Bond prices and interest rates have an inverse relationship. When interest rates rise, bond prices fall, and vice versa. This occurs because the fixed coupon payments of existing bonds become less attractive compared to new bonds issued at higher rates, leading to a decrease in their market value.
Why?
This is because existing bonds with fixed coupon rates become less attractive compared to newly issued bonds with higher coupon rates. How?
Bonds typically pay fixed coupon rates. If a bond pays a 5% coupon rate, it will continue to do so regardless of changes in market interest rates. When market interest rates rise and when new bonds are issued at a higher coupon rate, say 6%, they offer more attractive returns compared to the existing 5% bonds.
Investors prefer the new bonds because they yield higher returns. Consequently, the demand for existing bonds decreases. The existing bond prices adjust; to make the existing bonds appealing again, their prices must decrease to match the higher yield offered by new bonds. This is why bond prices fall when interest rates rise.
Python Code for Bond Price vs YTM Inverse Relationship
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
def calculate_bond_price(face_value, coupon_rate, frequency, maturity, ytm):
periods = maturity * frequency
coupon = face_value * (coupon_rate / frequency)
ytm_period = ytm / frequency
cash_flows = [coupon] * int(periods)
cash_flows[-1] += face_value
discount_factors = [(1 / (1 + ytm_period) ** t) for t in range(1, int(periods) + 1)]
present_values = [cf * df for cf, df in zip(cash_flows, discount_factors)]
bond_price = sum(present_values)
return bond_price
def main():
face_value = float(input("Enter the face value of the bond: "))
coupon_rate = float(input("Enter the coupon rate (in decimal, e.g., 0.08 for 8%): "))
frequency = int(input("Enter the coupon frequency (e.g., 2 for semi-annual): "))
maturity = float(input("Enter the maturity of the bond (in years): "))
ytm_start = float(input("Enter the starting yield to maturity (in decimal, e.g., 0.01 for 1%): "))
ytm_end = float(input("Enter the ending yield to maturity (in decimal, e.g., 0.15 for 15%): "))
num_ytms = int(input("Enter the number of YTMs to calculate: "))
ytms = np.linspace(ytm_start, ytm_end, num_ytms)
bond_prices = [calculate_bond_price(face_value, coupon_rate, frequency, maturity, ytm) for ytm in ytms]
# Display results
print("\nBond Price vs. Yield to Maturity (YTM):\n")
for ytm, price in zip(ytms, bond_prices):
print(f"YTM: {ytm:.4f} | Bond Price: {price:.2f}")
# Plotting Bond Price vs. YTM
plt.figure(figsize=(10, 6))
plt.plot(ytms, bond_prices, marker='o', linestyle='-', color='b', markersize=8)
plt.title('Bond Price vs. Yield to Maturity')
plt.xlabel('Yield to Maturity (YTM)')
plt.ylabel('Bond Price')
plt.grid(True)
plt.show()
if __name__ == "__main__":
main()
2/ Reinvestment Risk?
Reinvestment risk refers to the possibility that an investor will be unable to reinvest cash flows received from an investment, such as coupon payments, at a rate comparable to their current rate of return. Suppose when the market int rates go down, a bond investor who is at present is reinvesting his coupon payments, say at 6% , will not able to re-invest at 6% instead only at rates below 6%.
How do you manage re-investment risk?
Consider investing non-callable bonds, zero- coupon bonds, invest in long term securities to reduce the frequency of re-investment decisions.
3/ Cash Flow Risk: For institutions (like banks), changes in interest rates affect cash flows from loans and deposits. Companies with loans or bonds face interest payments. Fluctuating interest rates impact the cash outflows required for these payments.
Large capital investments (e.g., equipment, real estate) can reduce liquidity, affecting immediate and near-future cash flow. Interest rate changes make it harder for businesses to predict cash flows and control margins. Rising rates may render some projects unviable if revenues no longer cover funding costs
Measuring Interest Rate Risk:
Recall, Interest rate risk refers to the potential for financial losses due to changes in interest rates. It can impact a firm’s profitability and the value of its assets and liabilities. When interest rates fluctuate, the value of interest-sensitive assets and liabilities can change, affecting net interest income and overall financial stability
Measurement and Assessment: Two common methods for measuring interest rate risk are:
Gap Analysis: It compares the repricing of assets and liabilities to identify potential mismatches.
Duration Analysis: This method focuses on the sensitivity of assets and liabilities to interest rate changes. Duration measures the weighted average time to receive cash flows from an investment.
Macaulay Duration Overview
Macaulay Duration, named after economist Frederick Macaulay, is a measure of a bond's sensitivity to interest rate changes. It calculates the weighted average time it takes to receive the bond's cash flows, factoring in present value.
The purpose of Macaulay Duration is to provide investors with a precise measure of risk and return trade-off, which is essential for effective portfolio management. Understanding this concept impacts investors as it helps gauge the potential volatility of a bond or bond portfolio.
Excel calculation of Macaulay Duration
Let us take the below example:
Interpretation of Macaulay Duration :
The Macaulay Duration of the bond is approximately 2.72 years. This means that, on average, it will take about 2.72 years to receive the bond's cash flows, weighted by their present value
Python Code for Macaulay Duration for a bond – features of the bond such as face value, coupon rate, frequency of coupon, Yield to Maturity, and Maturity chosen by the user.
import numpy as np
import pandas as pd
def calculate_macaulay_duration(face_value, coupon_rate, frequency, maturity, ytm):
periods = maturity * frequency
coupon = face_value * (coupon_rate / frequency)
ytm_period = ytm / frequency
cash_flows = [coupon] * periods
cash_flows[-1] += face_value
discount_factors = [(1 / (1 + ytm_period) ** t) for t in range(1, periods + 1)]
present_values = [cf * df for cf, df in zip(cash_flows, discount_factors)]
time_weighted_pvs = [(t * pv) for t, pv in zip(range(1, periods + 1), present_values)]
total_present_value = sum(present_values)
macaulay_duration = sum(time_weighted_pvs) / total_present_value
df = pd.DataFrame({
"Term": range(1, periods + 1),
"CFs": cash_flows,
"PV of CFs": present_values,
"Time * PV CFs": time_weighted_pvs
})
return macaulay_duration, total_present_value, sum(time_weighted_pvs), df
def main():
face_value = float(input("Enter the face value of the bond: "))
coupon_rate = float(input("Enter the coupon rate (in decimal, e.g., 0.08 for 8%): "))
frequency = int(input("Enter the coupon frequency (e.g., 2 for semi-annual): "))
maturity = int(input("Enter the maturity of the bond (in years): "))
ytm = float(input("Enter the yield to maturity (in decimal, e.g., 0.09 for 9%): "))
macaulay_duration, total_pv, total_time_weighted_pv, df = calculate_macaulay_duration(face_value, coupon_rate, frequency, maturity, ytm)
macaulay_duration /= frequency
df.loc['Total'] = df[['PV of CFs', 'Time * PV CFs']].sum()
df.loc['Macaulay Duration'] = [None, None, None, macaulay_duration]
print(df)
print(f"\nMacaulay Duration: {macaulay_duration:.6f} years")
if __name__ == "__main__":
main()
Link Between Macaulay Duration and Interest Rates
Interest Rate Sensitivity:
The Macaulay Duration serves as an indicator of a bond's sensitivity to changes in interest rates. It provides a linear approximation of how much the price of a bond will change for a given change in interest rates.
The higher the YTM, the Macaulay Duration will lower
Macaulay Duration as a Measure of Bond's Interest Rate Risk-
Risk Indicator:
The longer the Macaulay Duration, the greater the bond's exposure to interest rate risk. A bond with a high Macaulay Duration will experience larger price fluctuations in response to changes in interest rates compared to a bond with a shorter duration.
Long maturity, low coupon, low yield = high duration
Python Code for Mac Duration analysis
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
def calculate_macaulay_duration(face_value, coupon_rate, frequency, maturity, ytm):
periods = maturity * frequency
coupon = face_value * (coupon_rate / frequency)
ytm_period = ytm / frequency
cash_flows = [coupon] * int(periods)
cash_flows[-1] += face_value
discount_factors = [(1 / (1 + ytm_period) ** t) for t in range(1, int(periods) + 1)]
present_values = [cf * df for cf, df in zip(cash_flows, discount_factors)]
time_weighted_pvs = [(t * pv) for t, pv in zip(range(1, int(periods) + 1), present_values)]
total_present_value = sum(present_values)
macaulay_duration = sum(time_weighted_pvs) / total_present_value / frequency
df = pd.DataFrame({
"Term": range(1, int(periods) + 1),
"CFs": cash_flows,
"PV of CFs": present_values,
"Time * PV CFs": time_weighted_pvs
})
return macaulay_duration, df
def main():
face_value = float(input("Enter the face value of the bond: "))
coupon_rate = float(input("Enter the coupon rate (in decimal, e.g., 0.08 for 8%): "))
frequency = int(input("Enter the coupon frequency (e.g., 2 for semi-annual): "))
maturity = float(input("Enter the maturity of the bond (in years): "))
ytm_start = float(input("Enter the starting yield to maturity (in decimal, e.g., 0.08 for 8%): "))
ytm_end = float(input("Enter the ending yield to maturity (in decimal, e.g., 0.1 for 10%): "))
num_ytms = int(input("Enter the number of YTMs to calculate: "))
ytms = np.linspace(ytm_start, ytm_end, num_ytms)
results = []
for ytm in ytms:
macaulay_duration, df = calculate_macaulay_duration(face_value, coupon_rate, frequency, maturity, ytm)
results.append((ytm, macaulay_duration))
# Display results
print("\nMacaulay Duration vs. Yield to Maturity (YTM):\n")
for ytm, macaulay_duration in results:
print(f"YTM: {ytm:.4f} | Macaulay Duration: {macaulay_duration:.6f} years")
# Plotting Macaulay Duration vs. YTM
ytm_values, duration_values = zip(*results)
plt.figure(figsize=(10, 6))
plt.plot(ytm_values, duration_values, marker='o', linestyle='-', color='b', markersize=8)
plt.title('Macaulay Duration vs. Yield to Maturity')
plt.xlabel('Yield to Maturity (YTM)')
plt.ylabel('Macaulay Duration (years)')
plt.grid(True)
plt.show()
if __name__ == "__main__":
main()
Note : Macaulay Duration of Zero-coupon bond will be equal to the maturity of the bond
Drawbacks of Macaulay Duration
Modified Duration
Modified duration is a modified version of the Macaulay model that accounts for changing interest rates. (Yield to Maturity). Modified formula shows how much the duration changes for each percentage change in yield. There is an inverse relationship between modified duration and an approximate 1% change in yield.
Modified Duration = Duration / [1+(Yield / No of coupons per annum)]
Where ‘f’ is the frequency of payment of coupon.
Recommended by LinkedIn
Python Code for Macaulay Duration and Modified Duration based on user-defined inputs for Bond values: Face value, Coupon Rate, Coupon Frequency, Maturity, YTM
import numpy as np
import pandas as pd
def calculate_macaulay_and_modified_duration(face_value, coupon_rate, frequency, maturity, ytm):
periods = maturity * frequency
coupon = face_value * (coupon_rate / frequency)
ytm_period = ytm / frequency
cash_flows = [coupon] * periods
cash_flows[-1] += face_value
discount_factors = [(1 / (1 + ytm_period) ** t) for t in range(1, periods + 1)]
present_values = [cf / (1 + ytm_period) ** t for t, cf in enumerate(cash_flows, 1)]
total_present_value = sum(present_values)
macaulay_duration = sum(t * pv for t, pv in enumerate(present_values, 1)) / total_present_value / frequency
modified_duration = sum(t * pv for t, pv in zip(range(1, periods + 1), present_values)) / total_present_value / (1 + ytm_period)
df = pd.DataFrame({
"Term": range(1, periods + 1),
"CFs": cash_flows,
"PV of CFs": present_values,
"Time * PV CFs": [t * pv for t, pv in zip(range(1, periods + 1), present_values)]
})
# Add total row and Macaulay Duration row
df.loc['Total'] = df[['PV of CFs', 'Time * PV CFs']].sum()
df.loc['Macaulay Duration'] = [None, None, None, macaulay_duration]
# Calculate Modified Duration
modified_duration = macaulay_duration / (1 + ytm / frequency)
df.loc['Modified Duration'] = [None, None, None, modified_duration]
return macaulay_duration, modified_duration, total_present_value, df
def main():
# Get bond parameters from user
face_value = float(input("Enter the face value of the bond: "))
coupon_rate = float(input("Enter the coupon rate (in decimal, e.g., 0.08 for 8%): "))
frequency = int(input("Enter the coupon frequency (e.g., 2 for semi-annual): "))
maturity = int(input("Enter the maturity of the bond (in years): "))
ytm = float(input("Enter the yield to maturity (in decimal, e.g., 0.09 for 9%): "))
macaulay_duration, modified_duration, total_pv, df = calculate_macaulay_and_modified_duration(face_value, coupon_rate, frequency, maturity, ytm)
# Display the DataFrame
print(df)
print(f"\nMacaulay Duration: {macaulay_duration:.6f} years")
print(f"Modified Duration: {modified_duration:.6f} years")
if __name__ == "__main__":
main()
Recall , Modified Duration is a measure of a bond's sensitivity to interest rate changes. It indicates how much the price of a bond is expected to change in response to a change in its yield to maturity (YTM). The relationship between Modified Duration and YTM can be summarized as follows:
Percentage change in bond price≈−Modified Duration×Change in YTM
This formula shows that the greater the Modified Duration, the greater the change in the bond's price for a given change in YTM.
Example Interpretation:
(I) For example, if a bond has a Modified Duration of 5 years and the YTM increases by 1%, the bond's price would be expected to decrease by approximately 5%.
(ii) Consider a bond with a YTM of 12% and duration is 5 years. If the interest rate increases by 50 basis points , change in the price of the bond will be. Assume annual coupon paying bond.
Modified duration of the bond is 5/1.12 = 4.46 years
Change is price can be calculated as follows:
%ΔPrice = -Dmod ×%Δyield
= -4.46 ×0.5 = -2.23%
Hence price will decline by 2.23% for a given change in yield.
Both Macaulay and Modified Duration measure the linear changes in the price of a bond about changes in Yield to maturity. Modified Duration is a better approximation to measure the interest rate sensitivity.
Modified Duration of a coupon paying bond will be less than the Macaulay duration of the same bond.
Key Considerations:
Application:
Effective Duration
Effective Duration is another measure used to estimate the sensitivity of a bond's price to changes in interest rates. While Modified Duration assumes a parallel shift in the yield curve, Effective Duration accounts for potential changes in the shape of the yield curve and is particularly useful for bonds with embedded options, such as callable bonds or mortgage-backed securities.
Excel Calculation of Effective Duration
Features of Effective Duration
Comparison with Modified Duration:
Application:
Key Rate Duration
Key Rate Duration (KRD) is a useful measure for assessing the sensitivity of a bond’s price to changes in specific key interest rates. Key rate duration is a measure of a bond or bond portfolio’s sensitivity to a 100-basis point – 1% – change in yield at a specific maturity point.
Excel Version of Key Rate Duration
CONVEXITY
Macaulay Duration and Modified Duration do not fully explain the linkage between prices and yield and convexity provides a solution to predicting prices. The actual change depends on the amount of curvature and this is known as convexity.
Convexity measures the curvature of the price-yield relationship and provides a more accurate estimate of how much a bond's price will change in response to interest rate movements.
Understanding convexity is crucial for bond investors and analysts because it helps them better manage interest rate risk and make informed decisions about bond investments based on potential price changes.
Consider the below bond details :
Convexity = (Sum of PV *(t^2+t)) /(1+YTM/freq.)^2) /Price of the bond
In the above example:
Sum of PV * (t^2+t) =53144.38106
The price of the bond =692.771645
(YTM / 2) ^2 = 1.21
Convexity = 63.39892
Convexity using approximation formula:
Convexity = (Phigh + Plow - 2*P0)/(P0*∆r*∆r)
Total % Change in Price of a bond due to Yield change (Yield shock)
% Change due to Modified Duration = -1 MD * Yield change
% Change due to Convexity= 0.5*Convexity * Yield Change ^2
∆P/P = - MD ∆r + 0.5 C * (∆r)^2
Consider a bond portfolio of two bonds equally weighted.
Step 1: Price of the bonds at current yield
Step 2: Calculate Modified Duration, Convexity using approx formula
Step 4: Calculate Portfolio MD, Portfolio Convexity
Step 5: For assumed Yield shock on either side: Say + 40 Basis Points, - 40 Basis points, calculate % Change due to Portfolio MD + %Change due to Portfolio convexity = Total % Change due to Yield in Bond Portfolio Value
Step 6: Finally calculate the price of the bond portfolio value on either side due to yield shock
Python code to calculate Portfolio MD, Portfolio Convexity,
Total % Change in Bond Portfolio value due to Portfolio MD and Portfolio Convexity
Exactly replicating the Excel workout above.
# Function to calculate Present Value of cash flows
def present_value(face_value, coupon_rate, coupon_freq, maturity, ytm):
coupon_payment = face_value * coupon_rate / coupon_freq
pv = 0
for t in range(1, maturity * coupon_freq + 1):
pv += coupon_payment / (1 + ytm / coupon_freq) ** t
pv += face_value / (1 + ytm / coupon_freq) ** (maturity * coupon_freq)
return pv
# Function to calculate Modified Duration
def calc_modified_duration(face_value, coupon_rate, coupon_freq, maturity, ytm, delta_ytm=0.0001):
pv = present_value(face_value, coupon_rate, coupon_freq, maturity, ytm)
pv_down = present_value(face_value, coupon_rate, coupon_freq, maturity, ytm - delta_ytm)
pv_up = present_value(face_value, coupon_rate, coupon_freq, maturity, ytm + delta_ytm)
modified_duration = (pv_down - pv_up) / (2 * pv * delta_ytm)
return modified_duration, pv
# Function to calculate Convexity
def calc_convexity(face_value, coupon_rate, coupon_freq, maturity, ytm, delta_ytm=0.0001):
pv_current = present_value(face_value, coupon_rate, coupon_freq, maturity, ytm)
pv_down = present_value(face_value, coupon_rate, coupon_freq, maturity, ytm - delta_ytm)
pv_up = present_value(face_value, coupon_rate, coupon_freq, maturity, ytm + delta_ytm)
convexity = (pv_down + pv_up - 2 * pv_current) / (pv_current * (delta_ytm ** 2))
return convexity, pv_current
# Main code execution starts here
# Bond A details
face_value_a = 1000
coupon_rate_a = 0.08 # 8% coupon rate
coupon_freq_a = 2 # semi-annual payments
maturity_a = 3
ytm_a = 0.09 # 9%
# Bond B details
face_value_b = 1000
coupon_rate_b = 0.06 # 6% coupon rate
coupon_freq_b = 1 # annual payments
maturity_b = 3
ytm_b = 0.08 # 8%
# Calculate present value, modified duration, and convexity for Bond A
pv_a = present_value(face_value_a, coupon_rate_a, coupon_freq_a, maturity_a, ytm_a)
modified_duration_a, _ = calc_modified_duration(face_value_a, coupon_rate_a, coupon_freq_a, maturity_a, ytm_a)
convexity_a, _ = calc_convexity(face_value_a, coupon_rate_a, coupon_freq_a, maturity_a, ytm_a)
# Calculate present value, modified duration, and convexity for Bond B
pv_b = present_value(face_value_b, coupon_rate_b, coupon_freq_b, maturity_b, ytm_b)
modified_duration_b, _ = calc_modified_duration(face_value_b, coupon_rate_b, coupon_freq_b, maturity_b, ytm_b)
convexity_b, _ = calc_convexity(face_value_b, coupon_rate_b, coupon_freq_b, maturity_b, ytm_b)
# Calculate portfolio values assuming equal weights
weight_a = 0.5
weight_b = 1 - weight_a
portfolio_value = weight_a * pv_a + weight_b * pv_b
# Calculate portfolio modified duration and convexity
portfolio_modified_duration = weight_a * modified_duration_a + weight_b * modified_duration_b
portfolio_convexity = weight_a * convexity_a + weight_b * convexity_b
# Display bond details and portfolio values
print("\nBond A details:")
print(f"Face Value: ₹{face_value_a}")
print(f"Coupon Rate: {coupon_rate_a * 100}%")
print(f"Coupon Frequency: {coupon_freq_a} times per year")
print(f"Maturity: {maturity_a} years")
print(f"Yield to Maturity (YTM): {ytm_a * 100}%")
print(f"Price (Present Value): ₹{pv_a:.2f}")
print(f"Modified Duration: {modified_duration_a:.4f}")
print(f"Convexity: {convexity_a:.4f}")
print("\nBond B details:")
print(f"Face Value: ₹{face_value_b}")
print(f"Coupon Rate: {coupon_rate_b * 100}%")
print(f"Coupon Frequency: {coupon_freq_b} times per year")
print(f"Maturity: {maturity_b} years")
print(f"Yield to Maturity (YTM): {ytm_b * 100}%")
print(f"Price (Present Value): ₹{pv_b:.2f}")
print(f"Modified Duration: {modified_duration_b:.4f}")
print(f"Convexity: {convexity_b:.4f}")
print("\nPortfolio Details:")
print(f"Weight of Bond A: {weight_a * 100}%")
print(f"Weight of Bond B: {weight_b * 100}%")
print(f"Total Portfolio Value: ₹{portfolio_value:.2f}")
print(f"Portfolio Modified Duration: {portfolio_modified_duration:.4f}")
print(f"Portfolio Convexity: {portfolio_convexity:.4f}")
# Input yield change in decimal
yield_change = float(input("\nEnter Yield Change (e.g., 0.004 for 0.4%): "))
# Calculate % change in bond portfolio value due to yield change
percent_change_due_to_md = -1 * portfolio_modified_duration * yield_change * 100 # Convert to percentage
percent_change_due_to_convexity = 0.5 * portfolio_convexity * (yield_change ** 2) * 100 # Convert to percentage
# Total percentage change
total_percent_change = percent_change_due_to_md + percent_change_due_to_convexity
# Calculate new bond portfolio value
new_portfolio_value = portfolio_value * (1 + total_percent_change / 100)
# Display the calculated percentage changes and new portfolio value
print("\nPercentage Change in Bond Portfolio Value due to Yield Change:")
print(f"Due to Modified Duration: {percent_change_due_to_md:.4f}%")
print(f"Due to Convexity: {percent_change_due_to_convexity:.4f}%")
print(f"Total % Change in Bond Portfolio Value: {total_percent_change:.4f}%")
print("\nNew Bond Portfolio Value:")
print(f"Current Portfolio Value: ₹{portfolio_value:.2f}")
print(f"New Portfolio Value: ₹{new_portfolio_value:.2f}")
Output
Conclusion
There are several classes of risk associated with investing in bonds apart from changes in interest rates. These include risks from reinvestment risk, changes in the yield curve, prepayment and call risk, credit, liquidity, exchange rates, inflation and exterior factors.
Modified Duration is the key measure for estimating changes in a bond’s value due to interest rate changes; however, measures based solely on duration become increasingly inaccurate.
Since the calculation needs to include the convexity of the price yield relationship, further measures of convexity are needed to predict the changed price more accurately.
Narsee Monjee Institute of Management Studies (NMIMS)- Bengaluru
5moSir, beautifully covered the topic and nicely explained the concepts of bond valuation.