Your question seems restricted only to the lines:
swap_rate = float(irs.rate(solver=solver))
print(swap_rate)
rolled_swap_rate = float(irs.rate(ESTR.roll("3m")))
with the comment that you are not passing a Solver
.
That's OK, you are passing a Curve
. Python is actually interpreting this (via positional arguments) as equivalent to:
rolled_swap_rate = float(irs.rate(curves=ESTR.roll("3m")))
The roll
method returns a new Curve
so this is all valid.
The part of docs that explains this is here
Btw you should add the "tgt" calendar
to your ESTR curve definintion.