Closed QuantInTheMaking closed 2 years ago
Thanks for posting! It might take a while before we look at your issue, so don't worry if there seems to be no feedback. We'll get to it.
Hi @QuantInTheMaking,
I don't think it is similar to #930. There was a very specific bug in the TreeCallableFixedRateBondEngine
implementation which I guess is not relevant here (see fix #1142).
Can you perhaps share your python code so we can reproduce and understand what causes the jump.
Regards Ralf
Thank you for your response @ralfkonrad
Here is my code:
import QuantLib as ql
import pandas as pd
import matplotlib.pyplot as plt
# Reading term structure data
yield_curve_input = pd.read_excel("Yield Curve Input.xlsx", sheet_name="Yield Curve - Input")
yield_curve_input["Maturity Date"] = pd.to_datetime(yield_curve_input["Maturity Date"])
calculation_date_parameter = pd.to_datetime("28/2/2022", format="%d/%m/%Y")
# Extracting deposits data
deposit_maturities = list(yield_curve_input.loc[yield_curve_input["Type"] == "Deposit"]["Maturity Date"])
deposit_maturities.insert(0, calculation_date_parameter)
deposit_rates = list(yield_curve_input.loc[yield_curve_input["Type"] == "Deposit"]["Adjusted YTM"])
deposit_rates.insert(0, deposit_rates[0])
# Extracting bonds data
bond_maturities = list(yield_curve_input.loc[yield_curve_input["Type"] == "Bond"]["Maturity Date"])
bond_rates = list(yield_curve_input.loc[yield_curve_input["Type"] == "Bond"]["Adjusted YTM"])
# Parameters
calc_date = ql.Date(calculation_date_parameter.day, calculation_date_parameter.month, calculation_date_parameter.year)
ql.Settings.instance().evaluationDate = calc_date
calendar = ql.SaudiArabia()
business_convention = ql.Following
day_count = ql.Actual360()
end_of_month = False
settlement_days = 0
face_amount = 100
coupon_frequency = ql.Period(ql.Semiannual)
# Constructing helpers
depo_helpers = []
for r, m in zip(deposit_rates, deposit_maturities):
maturity = ql.Period(ql.Actual360().dayCount(calc_date, ql.Date(m.day, m.month, m.year)), ql.Days)
depo_helpers.append(ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(r)),
maturity,
settlement_days,
calendar,
business_convention,
end_of_month,
day_count))
bond_helpers = []
for r, m in zip(bond_rates, bond_maturities):
maturity = calc_date + ql.Period(ql.Actual360().dayCount(calc_date, ql.Date(m.day, m.month, m.year)), ql.Days)
schedule = ql.Schedule(calc_date,
maturity,
coupon_frequency,
calendar,
business_convention,
business_convention,
ql.DateGeneration.Backward,
end_of_month)
bond_helper = ql.FixedRateBondHelper(ql.QuoteHandle(ql.SimpleQuote(face_amount)),
settlement_days,
face_amount,
schedule,
[r],
day_count,
business_convention)
bond_helpers.append(bond_helper)
# Combining helpers
rate_helpers = depo_helpers + bond_helpers
def get_spot_rates(yieldcurve, day_count, calendar=ql.SaudiArabia(), months=361):
spots = []
tenors = []
ref_date = yieldcurve.referenceDate()
calc_date = ref_date
for month in range(0, months):
yrs = month/12.0
d = calendar.advance(ref_date, ql.Period(month, ql.Months))
compounding = ql.Compounded
freq = ql.Annual
extrapolate = True
zero_rate = yieldcurve.zeroRate(yrs, compounding, freq, extrapolate)
tenors.append(yrs)
eq_rate = zero_rate.equivalentRate(day_count,compounding,freq,calc_date,d).rate()
spots.append(eq_rate)
return pd.DataFrame(zip(tenors, spots), columns=["Maturities","Curve"], index=['']*len(tenors))
# Interpolation
yc_linearzero = ql.PiecewiseLinearZero(calc_date, rate_helpers, day_count)
splz = get_spot_rates(yc_linearzero, day_count)
# Plotting
plt.plot(splz["Maturities"],splz["Curve"],'--', label="LinearZero")
plt.xlabel("Years", size=12)
plt.ylabel("Zero Rate", size=12)
plt.legend(loc=0)
And here is the data I am reading from the Excel file:
<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
Type | Tenor | Start Date | Maturity Date | Adjusted YTM -- | -- | -- | -- | -- Deposit | 0.25 | 02/28/2022 | 05/30/2022 | 0.80% Deposit | 0.50 | 02/28/2022 | 08/29/2022 | 0.84% Deposit | 0.92 | 02/28/2022 | 02/27/2023 | 0.87% Bond | 1.08 | 02/28/2022 | 4/25/2023 | 1.76% Bond | 1.33 | 02/28/2022 | 7/25/2023 | 2.35% Bond | 1.58 | 02/28/2022 | 10/24/2023 | 2.49% Bond | 1.83 | 02/28/2022 | 1/23/2024 | 2.78% Bond | 2.33 | 02/28/2022 | 7/26/2024 | 2.53% Bond | 2.42 | 02/28/2022 | 8/23/2024 | 2.58% Bond | 2.50 | 02/28/2022 | 9/20/2024 | 2.91% Bond | 2.58 | 02/28/2022 | 10/25/2024 | 2.63% Bond | 2.83 | 02/28/2022 | 1/24/2025 | 2.66% Bond | 3.00 | 02/28/2022 | 3/23/2025 | 3.00% Bond | 3.08 | 02/28/2022 | 4/25/2025 | 2.70% Bond | 3.33 | 02/28/2022 | 7/25/2025 | 3.03% Bond | 3.58 | 02/28/2022 | 10/24/2025 | 3.04% Bond | 4.83 | 02/28/2022 | 1/27/2027 | 3.12% Bond | 5.33 | 02/28/2022 | 7/27/2027 | 3.18% Bond | 5.42 | 02/28/2022 | 8/23/2027 | 3.02% Bond | 5.50 | 02/28/2022 | 9/20/2027 | 3.18% Bond | 5.58 | 02/28/2022 | 10/25/2027 | 3.04% Bond | 5.83 | 02/28/2022 | 1/21/2028 | 3.23% Bond | 6.08 | 02/28/2022 | 4/25/2028 | 3.24% Bond | 6.33 | 02/28/2022 | 7/26/2028 | 3.27% Bond | 6.58 | 02/28/2022 | 10/24/2028 | 3.29% Bond | 6.83 | 02/28/2022 | 1/4/2029 | 3.20% Bond | 7.42 | 02/28/2022 | 8/19/2029 | 3.36% Bond | 7.83 | 02/28/2022 | 1/20/2030 | 3.38% Bond | 8.00 | 02/28/2022 | 3/23/2030 | 3.41% Bond | 8.92 | 02/28/2022 | 2/20/2031 | 3.49% Bond | 9.00 | 02/28/2022 | 3/18/2031 | 3.49% Bond | 9.25 | 02/28/2022 | 6/17/2031 | 3.47% Bond | 9.67 | 02/28/2022 | 11/4/2031 | 3.49% Bond | 10.33 | 02/28/2022 | 7/26/2032 | 3.48% Bond | 10.83 | 02/28/2022 | 1/21/2033 | 3.64% Bond | 11.67 | 02/28/2022 | 11/4/2033 | 3.60% Bond | 11.83 | 02/28/2022 | 1/20/2034 | 3.69% Bond | 12.00 | 02/28/2022 | 3/27/2034 | 3.79% Bond | 12.92 | 02/28/2022 | 2/24/2035 | 3.86% Bond | 13.33 | 02/28/2022 | 7/26/2035 | 3.83% Bond | 14.42 | 02/28/2022 | 8/19/2036 | 3.87% Bond | 14.67 | 02/28/2022 | 11/4/2036 | 3.91% Bond | 27.08 | 02/28/2022 | 4/24/2049 | 4.64% Bond | 28.08 | 02/28/2022 | 3/30/2050 | 4.04%
Hello all,
I followed Goutham Balaraman_ Luigi Ballabio - QuantLib Python Cookbook (2017) textbook to construct deposits + bonds yield curve with actual data. The code is working fine, but I am getting an unexpected output presented in the sudden drop in the zero curve at around year 2 (see the image below). Please ignore the drop at the end it is due to extrapolation.
Although my input yields do not have such a drop as shown below
I have seen a similar issue being reported here: https://github.com/lballabio/QuantLib/issues/930
Your efforts in helping me resolve this issue would be highly appreciated