2
$\begingroup$

I’m running a simulation in which I want to calculate the NPV of 100 swaps over 1000 (or even much more) different interest rate curves.

It looks like Quantlib is not really fast in performing these calculations or my code is just not optimal.

Script does the following (for all curves):

  • Create Quantlib curve objects (based on these simulated interest rate curves)
  • Create swap object per swap
  • Set swappriceEngine per swap object
  • Calculate NPV per swap

Code example for every swap over all simulated interest rate curves:

fixed_schedule = ql.Schedule(settle_date, maturity_date,
                         fixed_leg_tenor, calendar,
                         ql.ModifiedFollowing, ql.ModifiedFollowing,
                         ql.DateGeneration.Forward, False
float_schedule = ql.Schedule (settle_date, maturity_date,
                          float_leg_tenor, calendar,
                          ql.ModifiedFollowing, ql.ModifiedFollowing,
                          ql.DateGeneration.Forward, False
swap = ql.VanillaSwap(ql.VanillaSwap.Payer, notional, fixed_schedule,
                     fixed_rate, fixed_leg_daycount, float_schedule,
                     6M_index, float_spread, float_leg_daycount)
swap.setPricingEngine(DiscountingSwapEngine(YieldTermStructureHandle(discount_curve)))
swap.NPV()

I’m wondering if it is possible to create only 100 different swap objects and just update the interest rate curves needed to calculate the NPV instead of creating swap objects in every loop. So only update the 6M_index in swap object and update discountcurve in swap.setPricingEngine.

Is that possible?

$\endgroup$

1 Answer 1

5
$\begingroup$

Yes, it's possible. You can create the 100 swaps and their engines beforehand and only change the curves. If you're using the same discount curve for all swaps, you can even create just one engine and share it between swaps.

You can write something like:

forecast_handle = ql.RelinkableYieldTermStructureHandle()
discount_handle = ql.RelinkableYieldTermStructureHandle()

index_6M = ql.SomeIndex(..., forecast_handle)
engine = ql.DiscountingSwapEngine(discount_handle)

and then for every swap:

fixed_schedule = ...
float_schedule = ...
swap = ...
swap.setPricingEngine(engine)

After this setup phase, for each scenario you can price the swaps with:

forecast_handle.linkTo(forecast_curve)
discount_handle.linkTo(discount_curve)
for s in swaps:
    s.NPV()

You'll still spend time in pricing, and there might be some time spent in notifications between objects, but at least you should save the time spent in building objects. Let me know how this works.

$\endgroup$
1
  • 1
    $\begingroup$ Hi Luigi, looks like it's working! Thanks $\endgroup$
    – Oamriotn
    Sep 19, 2022 at 14:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.