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())