I would like to value an IRS. My first problem is with "RuntimeError: more than one instrument with pillar". Theres is clearly no overlapping instruments. I can't get the valuation of the floating leg. Also, is there a way to value a swap at e.g. june 2023, when it started in may 2022, if I gave past Sofr ON values and spot rates from june 2023. Normally, there shouldn't be the problem, but I am not sure how QuantLib works. THanks!
Here's the code:
import pandas as pd
import datetime as dt
import QuantLib as ql
settlement_days = 2
calendar = ql.UnitedStates(ql.UnitedStates.FederalReserve)
day_count = ql.Actual360()
sofr = ql.Sofr()
curve_dates = ["30.06.2023", "03.07.2023", "05.07.2023", "12.07.2023", "19.07.2023", "07.08.2023", "05.09.2023", "05.10.2023", "06.11.2023",
"05.12.2023", "05.01.2024", "05.02.2024", "05.03.2024", "05.04.2024", "06.05.2024", "05.06.2024", "05.07.2024",
"07.07.2025", "06.07.2026", "05.07.2028", "05.07.2029", "05.07.2030", "07.07.2031",
"05.07.2033", "05.07.2034", "05.07.2035", "07.07.2036", "06.07.2037", "05.07.2039", "05.07.2040",
"05.07.2041", "07.07.2042", "06.07.2043"]
row1 = [0.999576013, 0.999293276, 0.998284236, 0.997276216, 0.994545288, 0.990391441, 0.986043654, 0.981353845]
row2 = [0.977122975, 0.972637548, 0.968188632, 0.964045167, 0.959738687, 0.95554771, 0.951509352, 0.947635722]
row3 = [0.908583534, 0.877579008, 0.823760707, 0.798388971, 0.773888557, 0.749927777]
row4 = [0.703540185, 0.680868756, 0.658502936, 0.636587109, 0.615672676, 0.57654805, 0.558385784]
row5 = [0.541184978, 0.524737797, 0.509183223]
discount_factors = row1 + row2 + row3 + row4 + row5
qlDates = [ql.Date(int(day), int(month), int(year)) for date in curve_dates for day, month, year in [date.split('.')]]
valuationDate = ql.Date(30,6,2023)
ql.Settings.instance().evaluationdate = valuationDate
sofr = ql.Sofr()
SofrCurve = ql.DiscountCurve(qlDates, [1] + discount_factors, day_count, calendar)
SofrCurve.enableExtrapolation()
ValuationCurve = ql.RelinkableYieldTermStructureHandle(SofrCurve)
#ValuationCurve.linkTo(SofrCurve)
sofrIndex = ql.Sofr(ValuationCurve)
swapEngine = ql.DiscountingSwapEngine(ValuationCurve)
fixedRate = 0.0443
Nominal = 3_000_000
forwardStart = ql.Period("2D")
start_date = ql.Date(30,6,2023)
maturity_date = calendar.advance(start_date, 4, ql.Years)
fixed_leg_daycount = ql.Actual360()
fixed_leg_tenor = ql.Period(12, ql.Months)
fixed_schedule = ql.Schedule(start_date, maturity_date,
fixed_leg_tenor, calendar,
ql.ModifiedFollowing, ql.ModifiedFollowing,
ql.DateGeneration.Forward, False)
fixed_leg_daycount = ql.Actual360()
fixed_leg_tenor = ql.Period(12, ql.Months)
fixed_schedule = ql.Schedule(start_date, maturity_date,
fixed_leg_tenor, calendar,
ql.ModifiedFollowing, ql.ModifiedFollowing,
ql.DateGeneration.Forward, False)
float_spread = 0.0
ir_swap = ql.VanillaSwap(ql.VanillaSwap.Payer, Nominal,
fixed_schedule, fixedRate, fixed_leg_daycount, float_schedule, sofrIndex, float_spread, float_leg_daycount)
ir_swap.setPricingEngine(swapEngine)
#Floating Leg
pd.DataFrame(
[(cf.date(), cf.amount()) for cf in ir_swap.leg(1)],
columns=["Date", "Amount"],
index=range(1, len(ir_swap.leg(1))+1)
)
OIS swap
sofr_curve_log_cubic.nodes()[:10]
((Date(30,6,2023), 1.0),
(Date(4,7,2023), 0.9994349085205639),
(Date(20,9,2023), 0.9882497109370333),
(Date(20,12,2023), 0.9749417559680691),
(Date(20,3,2024), 0.9619089583699006),
(Date(20,6,2024), 0.9494974442774458),
(Date(18,9,2024), 0.9383313017859709),
(Date(18,12,2024), 0.9280793760780555),
(Date(19,3,2025), 0.9187319168325597),
(Date(7,7,2025), 0.9085558942301587))
today = ql.Date(30, ql.June, 2023)
ql.Settings.instance().evaluationDate = today
sofr_curve_log_cubic = ql.PiecewiseLogCubicDiscount(0, ql.TARGET(),
helpers, ql.Actual360())
sofr_curve_log_cubic.enableExtrapolation()
swapType = ql.OvernightIndexedSwap.Receiver
nominal = 500_000
schedule = ql.MakeSchedule(ql.Date(13,5,2022),
ql.Date(13, 5,2027),
ql.Period('1Y'),
calendar=ql.TARGET())
fixedRate = 0.03
fixedDC = ql.Actual360()
ValuationCurve = ql.RelinkableYieldTermStructureHandle()
ValuationCurve.linkTo(sofr_curve_log_cubic)
overnightIndex = ql.Sofr(ValuationCurve)
# Here are dates and fixings from the start of the swap up until valuation date
for date, fixing in zip(SofrON_qlDates, SofrON_rates):
overnightIndex.addFixing(date, fixing)
ois_swap = ql.OvernightIndexedSwap(swapType,
nominal,
schedule,
fixedRate,
fixedDC,
overnightIndex)
swapEngine = ql.DiscountingSwapEngine(ValuationCurve)
ois_swap.setPricingEngine(swapEngine)
# Unfortunately, the swap is not pricing with the schedule on the valuation date
```
float_schedule
is not defined. If I also fix that, I don't have a pillar error, but rather a convergence error. May you edit your code so that it reproduces your problem? Thanks! $\endgroup$import QuantLib as ql
,import pandas as pd
andimport datetime as dt
—is that correct? $\endgroup$DiscountCurve
and interpolate them directly. $\endgroup$