Skip to content
All library documents

Diagnosing a SOFR Futures Curve Bootstrap Error in QuantLib

Article Quant Q&A · Author: jpkey

Summary

This question examines a QuantLib error encountered while bootstrapping a yield curve from quarterly SOFR futures. The supplied setup builds futures rate helpers and a piecewise linear zero curve; the reported failure refers to a missing SOFR overnight fixing on a date around Juneteenth. The author asks whether the holiday causes the error or whether the curve is misconstructed.

The accepted answer says that, assuming the evaluation date and known historical SOFR fixings are configured, the behavior was a library bug fixed in QuantLib version 1.35. Updating to that release is presented as the remedy. The answer is brief and does not detail the underlying defect or provide a reproducible fix for older versions, so the diagnosis depends on the stated assumptions about curve setup and fixings.

Key ideas

  • A SOFR futures curve bootstrap can fail when the required overnight fixing is missing from the calculation path.
  • The answer attributes this case to a QuantLib bug fixed in version 1.35.
  • Curve setup should include the evaluation date and known historical SOFR fixings.
  • The response does not explain the bug’s internals or an older-version workaround.

Tags

Full text
# Is Juneteenth causing a runtime error when bootstrapping curve off of futures?


# Is Juneteenth causing a runtime error when bootstrapping curve off of futures?












```
import io
import pandas as pd
import QuantLib as ql

data = io.StringIO("""Start Date    Days    Ticker  Last    Rate    6 Mo    1 Yr    2 Yr    3 Yr    5 Yr    7 Yr    10 Yr
08/01/2024  48  SFRM4   94.6524 5.3476  5.062   4.741   4.236   3.988   3.823   3.843   
09/18/2024  91  SFRU4   94.955  5.045   4.872   4.551   4.11    3.902   3.777   3.815   
12/18/2024  91  SFRZ4   95.36   4.64    4.472   4.217   3.904   3.764   3.708   3.775   
03/19/2025  91  SFRH5   95.745  4.255   4.129   3.952   3.748   3.662   3.663   3.751   
06/18/2025  91  SFRM5   96.04   3.96    3.874   3.762   3.64    3.594   3.64    3.741   
09/17/2025  91  SFRU5   96.25   3.75    3.697   3.635   3.571   3.555   3.633   3.742   
12/17/2025  91  SFRZ5   96.39   3.61    3.581   3.554   3.53    3.536   3.639   3.752   
03/18/2026  91  SFRH6   96.48   3.52    3.508   3.506   3.509   3.533   3.654   3.767   
06/17/2026  91  SFRM6   96.535  3.465   3.465   3.479   3.502   3.541   3.674   3.786   
09/16/2026  91  SFRU6   96.565  3.435   3.442   3.467   3.506   3.556   3.698   3.807   
12/16/2026  91  SFRZ6   96.58   3.42    3.432   3.465   3.518   3.579   3.724   3.827   
03/17/2027  91  SFRH7   96.585  3.415   3.432   3.471   3.537   3.608   3.752   3.85    
06/16/2027  91  SFRM7   96.58   3.42    3.437   3.485   3.561   3.64    3.782       
09/15/2027  91  SFRU7   96.575  3.425   3.45    3.504   3.59    3.675   3.811       
12/15/2027  91  SFRZ7   96.555  3.445   3.471   3.531   3.625   3.711   3.84        
03/15/2028  98  SFRH8   96.535  3.465   3.495   3.562   3.665   3.75    3.871       
06/21/2028  91  SFRM8   96.505  3.495   3.528   3.599   3.709   3.79    3.9     
09/20/2028  91  SFRU28  96.47   3.53    3.566   3.638   3.752   3.827   3.928       
12/20/2028  91  SFRZ28  96.43   3.57    3.606   3.683   3.794   3.863   3.952       
03/21/2029  91  SFRH29  96.39   3.61    3.644   3.732   3.836   3.898   3.976       
06/20/2029  91  SFRM29  96.355  3.645   3.692   3.779   3.875   3.93            
09/19/2029  91  SFRU29  96.295  3.705   3.75    3.827   3.912   3.959           
12/19/2029  91  SFRZ29  96.24   3.76    3.796   3.867   3.944   3.985           
03/20/2030  91  SFRH30  96.205  3.795   3.831   3.901   3.971   4.009           
06/19/2030  91  SFRM30  96.17   3.83    3.864   3.932   3.996   4.028           
09/18/2030  91  SFRU30  96.14   3.86    3.897   3.959   4.016   4.045           
12/18/2030  91  SFRZ30  96.105  3.895   3.924   3.984   4.034   4.057           
03/19/2031  91  SFRH31  96.085  3.915   3.944   4.004   4.053   4.07            
06/18/2031  91  SFRM31  96.065  3.935   3.965   4.022   4.067               
09/17/2031  91  SFRU31  96.045  3.955   3.985   4.037   4.078               
12/17/2031  91  SFRZ31  96.025  3.975   4   4.048   4.084               
03/17/2032  91  SFRH32  96.015  3.985   4.008   4.066   4.093               
06/16/2032  91  SFRM32  96.01   3.99    4.015   4.075                   
09/15/2032  91  SFRU32  96  4   4.043   4.084                   
12/15/2032  91  SFRZ32  95.955  4.045   4.053   4.085                   
03/16/2033  91  SFRH33  95.98   4.02    4.041   4.085                   
06/15/2033  98  SFRM33  95.98   4.02    4.034                       
09/21/2033  91  SFRU33  95.995  4.005   4.046                       
12/21/2033  84  SFRZ33  95.95   4.05                            
""")
df = pd.read_csv(data, sep='\t')
df['Start Date'] = pd.to_datetime(df['Start Date'])
df['contract_month'] = df['Ticker'].apply(lambda x: 3 if x[3] == 'H' else 6 if x[3] == 'M' else 9 if x[3] == 'U' else 12)
```

Creating the curve

```
dates = []
rates = []
futures = []
for i, row in df.iterrows():
    price = row['Last']    
    year = row['Start Date'].year
    future = ql.SofrFutureRateHelper(price, row['contract_month'], year, ql.Quarterly)
    futures.append(future)

curve = ql.PiecewiseLinearZero(2, ql.TARGET(), futures, ql.Actual360())
yts = ql.YieldTermStructureHandle(curve)
engine = ql.DiscountingBondEngine(yts)
```

Viewing the nodes

```
curve.nodes()
```

Error

```
RuntimeError: 1st iteration: failed at 1st alive instrument, pillar September 18th, 2024, maturity September 18th, 2024, reference date August 1st, 2024: missing rate on June 19th, 2024 for index SOFRON Actual/360
```

Do I get the above error because the contract start date begins on Juneteenth? Is this a bug in the library or am I failing to construct the curve properly?

## Answer by Luigi Ballabio (score 3, accepted)

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

It's not shown in your code, but I assume you're also setting the evaluation date and adding to the SOFR instance the known past fixings, right?

If that's the case, what you're hitting was in fact a bug in the library; it was fixed in version 1.35, released last week. Upgrading should fix the problem.

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.