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?