Basic Implementation#
This page is designed to provide inspiration for a server-side-client-side rateslib integration. It will discuss:
A Basic Web Server#
Personally we like flask, and have used it reliably for commericial projects in the past, so
this page adopts that as the core Python web server. Suppose we have a new Python environment, and
we install both the flask and rateslib dependencies.
(venv) my-server/> pip install flask rateslib
This application will be minimalist for demonstration purposes and it will have the directory structure shown below:
my-server/
main.py
updater.py
data.py
usd_config.py
Go ahead and create these four files in your directory (they can be empty initially), and then
populate main.py with the following code, which configures the web-app and sets up the
main, index, route:
# main.py
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def index():
return (
'Rateslib Server is running! <br/> <br/>'
'Try calling /api/ytm?effective=20000615&termination=20011215&spec=de_gb&fixed_rate=1.0&settlement=20000815&price=100.34 <br/> <br/>'
'Try calling /api/usd_irs?effective=20000615&termination=20011215&frequency=A'
)
Now you can start this web server by executing this script from terminal with:
(venv) my-server/> flask --app main run
* Running on http://127.0.0.1:5000
You can now visit the local URL stated and it will return the string above to the browser. If you happen to try the additional links as suggested it will return with 404 (NOT FOUND) because neither route has yet been constructed. But, at least, we are still up and running here.
Static Routes#
The first suggested route at the homepage is a YTM calculation for
a FixedRateBond defined by static inputs. This does not
require any data configuration or realtime market updates. So this is suitable for our next
addition. We will create a single API endpoint that recovers parameters from the query string
and returns the YTM. Add the following to main.py, which directly adds one route.
# main.py
from datetime import datetime
from flask import Flask, request
from rateslib import IRS, FixedRateBond
# ...previous code...
@app.route('/api/ytm', methods=['GET'])
def ytm():
input = request.args.to_dict()
input["effective"] = datetime.strptime(input["effective"], "%Y%m%d")
input["termination"] = datetime.strptime(input["termination"], "%Y%m%d")
input["settlement"] = datetime.strptime(input["settlement"], "%Y%m%d")
input["price"] = float(input["price"])
input["fixed_rate"] = float(input["fixed_rate"])
kwargs = dict(price=input.pop("price"), settlement=input.pop("settlement"))
frb = FixedRateBond(**bar)
return {"ytm": frb.ytm(**kwargs)}
When the server is restarted and the first hyperlink retried the server now returns the following JSON to the browser:
{"ytm":0.7414146516155802}
This is the first example of providing direct access to the rateslib API via input conversion from a URL hyperlink. Let’s consider how to do this with market updates.
Initial Config#
Our server will build and maintain a USD SOFR curve and provide the ability to trigger updates with new market data on request. The first thing we need to do is start the server in some viable state. This is its configuration.
Add the following code to the usd_config.py file. This code defines a USD SOFR
Curve and creates a Solver object stored on
the server which has the capability of mutating that Curve. None of this should be new if you
are familiar with any of the Curve calibration tutorials. The last line indicates that all this
file is really needed for is to define and export the usd_solver.
# usd_config.py
from rateslib import Curve, IRS, Solver, dt
usd_curve = Curve(
nodes={
dt(2000, 1, 1): 1.0,
dt(2001, 1, 1): 0.99,
dt(2002, 1, 10): 0.98,
},
convention="Act360",
calendar="nyc",
interpolation="spline",
id="sofr"
)
usd_solver = Solver(
curves=[usd_curve],
instruments=[
IRS(dt(2000, 1, 1), "1y", spec="usd_irs", curves=["sofr"]),
IRS(dt(2000, 1, 1), "2y", spec="usd_irs", curves=["sofr"]),
],
s=[3.25, 3.45],
)
__all__ = ["usd_solver"]
Our main.py can now be extended to utilise this configured object and cache it. Make the
following addition to the top of the file.
# main.py
from datetime import datetime
from flask import Flask, request
from rateslib import IRS, FixedRateBond
from usd_config import usd_solver
app = Flask(__name__)
GLOBAL = {
"USD_SOLVER": usd_solver,
}
# ...previous code...
OK, that’s more plumbing in place but we are missing two items;
A route to allow a client to request a swap rate (or any other such IRS data metric)
A route to trigger data updates and mutate the Curve.
Client API Request#
Since the Solver has calibrated lets first design a minimalist
endpoint to get a swap rate. This is now very similar to the ytm endpoint created above.
Add the following route to main.py
# main.py
# ...previous code...
@app.route('/api/usd_irs', methods=['GET'])
def usd_irs():
input = request.args.to_dict()
input["effective"] = datetime.strptime(bar["effective"], "%Y%m%d")
input["termination"] = datetime.strptime(bar["termination"], "%Y%m%d")
irs = IRS(**bar, spec="usd_irs", curves=["sofr"])
return {"rate": float(irs.rate(solver=GLOBAL["USD_SOLVER"]))}
When the server is restarted and the second hyperlink retried the server returns the following JSON to the browser:
{"rate":3.5179617581852303}
Technically this is still a static endpoint currently becuase it depends only on the statically configured Solver at start-up. But that is now about to change..
Data Updates#
Now we will build into the server a mechanism for data updates to be triggered. First we
need an ability to get new market data. Add the following code to the empty data.py
# data.py
import random
def update_usd_data() -> list[float]:
# HERE is where you fetch data in the appropriate format from
# your external data source API
s = [3.25 + random.randint(0, 10) / 100, 3.35 + random.randint(0, 10) / 100]
return s
__all__ = ["update_usd_data"]
And secondly add a route to the server so that when it is visted it will trigger a Solver recalibration.
# main.py
# ...previous code...
from usd_config import usd_solver
from data import update_usd_data
# ...previous code...
@app.route('/update_usd')
def update_usd():
data = update_usd_data()
solver = GLOBAL["USD_SOLVER"]
solver.s = data
solver.iterate()
return GLOBAL["USD_SOLVER"].result
Now if you visit the the ‘/update_usd’ you will get the output from the Solver calibration, and then if you visit the link again for the swap rate you will observe that the rate has indeed changed - reacting to the random data update.
Scheduling Updates#
This server is designed in such a way that at any point it only does two things;
maintain in memory, static objects, i.e.
Solver(which contains cachedCurveand risk jacobians)react to external requests from clients, by providing data from those objects via a calculation, or triggering a data mutation.
It is impractical to require a client-user to first trigger a data update and then make their own request. In practice it is simpler to schedule some other process or worker to trigger data updates at regular intervals. We make no comment on what form your scheduler should take.
The below is just a single Python scipt that continuously loops and calls one URL request.
# updater.py
import time
import urllib.request as ur
if __name__ == "__main__":
usd_update = "http://localhost:5000/update_usd"
while True:
time.sleep(10)
result = ur.urlopen(usd_update)
print(result)
To run this application requires two processes initiated from terminal:
(venv) my-server/> flask --app main run
* Running on http://127.0.0.1:5000
SUCCESS: `func_tol` reached after 3 iterations (levenberg_marquardt) ...
127.0.0.1 - - [01/Feb/2026 14:13:24] "GET /update_usd HTTP/1.1" 200 -
SUCCESS: `func_tol` reached after 3 iterations (levenberg_marquardt) ...
127.0.0.1 - - [01/Feb/2026 14:13:34] "GET /update_usd HTTP/1.1" 200 -
SUCCESS: `func_tol` reached after 3 iterations (levenberg_marquardt) ...
127.0.0.1 - - [01/Feb/2026 14:13:44] "GET /update_usd HTTP/1.1" 200 -
The server is started in the usual way. After every 10 seconds it gets a trigger update.
(venv) my-server/> python updater.py
<http.client.HTTPResponse object at 0x1010101010>
<http.client.HTTPResponse object at 0x1010101230>
<http.client.HTTPResponse object at 0x1010101450>
When we spin up the worker, in another terminal process, it simply acts as the trigger and does not do anything with the response: although of course you can build in error processing, logging and signaling here.
This is now automated, and if you continue to retry the IRS rate API endpoint it will update to new data after every 10 seconds.