Skip to content
All library documents

Diagnosing Negative-Time Errors in QuantLib Swap Valuation

Article Quant Q&A · Author: Rahul

Summary

This QuantLib example explains a negative-time error encountered while valuing an interest rate swap. The accepted answer points to a likely mismatch between the curve reference date and cash-flow dates: requesting a discount factor for a date before the curve begins can cause the error. The example builds a South African rand zero curve, creates a JIBAR-based swap, adds a historical index fixing, and inspects future floating-leg coupons and discount factors. It also corrects an inconsistency in the question, where the number of supplied rates did not match the number of curve tenors.

The proposed repair uses a consistent set of curve dates and rates, then filters cash flows to dates after the evaluation date. The answer is a practical troubleshooting example rather than a general treatment of swap valuation. It does not discuss curve construction choices, conventions beyond those shown, or alternative causes of negative times, so users should verify their own curve reference date, schedule dates, and fixing history.

Key ideas

  • A request to discount a date earlier than the yield curve reference date can trigger a negative-time error.
  • The number of zero rates must match the number of curve dates supplied to the curve constructor.
  • Historical floating-rate coupons may require the corresponding index fixing to be added.
  • Filtering cash flows to dates after the evaluation date helps focus inspection on future swap payments.

Tags

Full text
# Quantlib: Why Interest Rate Swap valuation throwing the 'Runtime error negative time'?


# Quantlib: Why Interest Rate Swap valuation throwing the 'Runtime error negative time'?












```
# Set evaluation date

spotRates = [0.02514, 0.026285, 0.027326299999999998,
         0.0279, 0.029616299999999998, 0.026526,
         0.026028, 0.0258695, 0.025958000000000002,
         0.0261375, 0.026355, 0.0266255,
         0.026898, 0.0271745, 0.02741,
         0.027666, 0.028107000000000004, 0.028412000000000003,
         0.028447, 0.0284165]

spotPeriod = [Period(1, Weeks), Period(1, Months),
          Period(3, Months), Period(6, Months),
          Period(9, Months), Period(1, Years),
          Period(3, Years),Period(5, Years)
          Period(10, Years),Period(15, Years), Period(20, Years),
          Period(30, Years), Period(50, Years)]
```

## Answer by David Duarte (score 1, accepted)

https://quant.stackexchange.com/a/51597

Had to change a few things because you had 20 spot rates but only 13 spot period, and added a bogus fixing, but here is a working example.

```
import QuantLib as ql
import pandas as pd

todaysDate = ql.Date(13, 9, 2019)
calendar = ql.SouthAfrica()
day_count = ql.Actual365Fixed()
currency = ql.ZARCurrency()

todaysDate = calendar.adjust(todaysDate)
ql.Settings.instance().evaluationDate = todaysDate

spotRates = [0.02514, 0.026285, 0.027326299999999998,
         0.0279, 0.029616299999999998, 0.026526,
         0.026028, 0.0258695, 0.025958000000000002,
         0.0261375, 0.026355, 0.0266255,
         0.026898, 0.0271745, 0.02741,
         0.027666, 0.028107000000000004, 0.028412000000000003,
         0.028447, 0.0284165]

spotPeriod = [ql.Period(1, ql.Weeks), ql.Period(1, ql.Months),
          ql.Period(3, ql.Months), ql.Period(6, ql.Months),
          ql.Period(9, ql.Months), ql.Period(1, ql.Years),
          ql.Period(3, ql.Years),  ql.Period(5, ql.Years),
          ql.Period(10, ql.Years), ql.Period(15, ql.Years), ql.Period(20, ql.Years),
          ql.Period(30, ql.Years), ql.Period(50, ql.Years)]

dates = [calendar.advance(todaysDate, period) for period in spotPeriod]
curve = ql.ZeroCurve(dates, spotRates[:13], day_count, calendar)
yts = ql.YieldTermStructureHandle(curve)
engine = ql.DiscountingSwapEngine(yts)

issue_date = ql.Date(18, 4, 2018)
maturity_date = ql.Date(18, 4, 2028)
fixedRate = .09
index = ql.Jibar(ql.Period('3M'), yts)
fix_payment_frequency = ql.Annual
float_payment_frequency = ql.Quarterly

fixedSchedule = ql.MakeSchedule(issue_date, maturity_date, ql.Period('1Y'), calendar=calendar)
floatSchedule = ql.MakeSchedule(issue_date, maturity_date, ql.Period('3M'), calendar=calendar)
swap = ql.VanillaSwap(
    ql.VanillaSwap.Payer, 100,
    fixedSchedule, fixedRate, day_count,
    floatSchedule, index, 0, index.dayCounter()
    )

index.addFixing(ql.Date(18,7,2019), 0.02)

swap.setPricingEngine(engine)
data = []
for cf in map(ql.as_coupon, swap.leg(1)):
    if cf.date() > todaysDate:
        data.append({
            'accuralStart': cf.accrualStartDate(),
            'accrualEnd': cf.accrualEndDate(),
            'amount': cf.amount(),
            'rate': cf.rate(),
            'discount': yts.discount(cf.date())

        })
pd.DataFrame(data).head()
```

which would output:

I suspect you were trying to get a discount factor from a date before the curve date.

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.