Building Custom Swap Coupons and Amortization Schedules in QuantLib
Summary
The document explains how to represent an interest rate swap with individually specified coupon dates, rates, and notionals in QuantLib. One approach constructs fixed rate coupons one at a time, which lets each period carry its own accrual dates, rate, and principal amount. The example also builds a floating leg and combines both legs into a swap.
A second approach supplies custom dates to a schedule and creates a fixed leg from that schedule, again using period-specific notionals and rates. A response also points to QuantLib’s nonstandard swap class as an alternative for different notionals, rates, spreads, gearings, schedules, and conventions across the legs. The examples illustrate construction and show calculated fixed coupon amounts, but do not demonstrate discounting, valuation setup, or treatment of past fixings for a swap already underway. The discussion notes that standard market conventions may suffice for many trades; custom construction is useful when portfolio dates or cash flows need to be matched explicitly.
Key ideas
- QuantLib allows fixed rate coupons to be constructed individually with custom accrual dates, rates, and notionals.
- A custom date schedule can be used to build a fixed leg with period-specific coupon inputs.
- A floating leg can be combined with a manually constructed fixed leg to form a swap.
- The nonstandard swap class supports different leg schedules and conventions, notionals, rates, gearings, and spreads.
- The examples demonstrate cash flow construction but do not explain the full valuation setup for an already-started swap.
Tags
Full text
# Value a Swap with Custom Coupons with QuantLib
# Value a Swap with Custom Coupons with QuantLib
I'd like to valuate a custom Libor3M - Fix swap with QuantLib in Python. With custom I mean, custom starting/end/payment dates for every coupon, a fixed coupon in the float leg (starting_date < evaluation_date, i.e. a swap that already started) and custom amortization amount for every coupon.
I asked a similar question recently (Valuating Custom Amortization Schedule Libor IRS with QuantLib), but the provided code did not worked for my purpose as I need to build these swaps one coupon at a time to avoid dates mismatches between loaded info to QuantLib and my portfolio schedules.
## Answer by David Duarte (score 1, accepted)
https://quant.stackexchange.com/a/54282
Unless you have some really exotic bespoke dates, I'm pretty sure QuantLib will be able to match what you need. The purpose of market conventions is precisely to allow different entities with different systems to arrive at exacly the same cashflows.
Having said that, QuantLib is very flexible so you can actually define each coupon as you wish.
Here is an example of defining a fixed leg with individual coupons:
```
data = [
# nominal, rate, startDate, endDate
(100, 0.015, '15-06-2020', '15-12-2020'),
(100, 0.015, '15-12-2020', '15-05-2021'),
(50, 0.025, '15-05-2021', '15-11-2021'),
(50, 0.012, '15-11-2021', '15-06-2022'),
]
fixedLeg = ql.Leg()
for nominal, rate, startDate, endDate in data:
startDate = ql.Date(startDate, '%d-%m-%Y')
endDate = ql.Date(endDate, '%d-%m-%Y')
fixedCoupon = ql.FixedRateCoupon(
endDate, nominal, rate, ql.Thirty360(), startDate, endDate)
fixedLeg.append(fixedCoupon)
calendar = ql.TARGET()
start = ql.Date(15,6,2020)
maturity = calendar.advance(start, ql.Period('2y'))
floatSchedule = ql.MakeSchedule(start, maturity, ql.Period('6M'))
floatLeg = ql.IborLeg([100, 100, 50, 50], floatSchedule, ql.Euribor6M(), ql.Actual360())
swap = ql.Swap(fixedLeg, floatLeg)
for cf in map(ql.as_coupon, swap.leg(0)):
print(cf.date().ISO(), cf.rate(), cf.amount())
```
2020-12-15 0.015 0.7500000000000062 2021-05-15 0.015 0.6250000000000089 2021-11-15 0.025 0.6249999999999978 2022-06-15 0.012 0.34999999999999476
Alternatively, you could create a schedule with a list of custom dates:
```
calendar = ql.TARGET()
start = ql.Date(15,6,2020)
maturity = calendar.advance(start, ql.Period('2y'))
fixedSchedule = ql.Schedule([
ql.Date(15,6,2020),
ql.Date(15,12,2020),
ql.Date(15,5,2021),
ql.Date(15,11,2021),
ql.Date(15,6,2022)
])
fixedLeg = ql.FixedRateLeg(fixedSchedule, ql.Thirty360(), [100, 100, 50, 50], [0.015, 0.015, 0.025, 0.012])
floatSchedule = ql.MakeSchedule(start, maturity, ql.Period('6M'))
floatLeg = ql.IborLeg([100, 100, 50, 50], floatSchedule, ql.Euribor6M(), ql.Actual360())
swap = ql.Swap(fixedLeg, floatLeg)
for cf in map(ql.as_coupon, swap.leg(0)):
print(cf.date().ISO(), cf.rate(), cf.amount())
```
## Answer by LePiddu (score 0)
https://quant.stackexchange.com/a/54283
I think the best structure is
> Import QuantLib as ql ql.NonStandardSwap()
It's highly customizable in that you can set different different notionals (and therefore amortizing plans), different fixed rates, different gearings, different spreads at each date for both legs. And of course different schedules and conventions for both legs.
It can be priced by registering a DiscountSwapEngine just like every swap. I'll give you the link to the Github examples for Quantlib Python where it's specifically shown how to use the class.Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.