.. _server-slow-fast-doc: ********************** Slow and Fast Approach ********************** This page enhances the :ref:`basic server application `, and therefore assumes familiarity with the code and architecture presented there. This page will: - outline the mathematics we will implement. - make minimal modifications to the code to integrate a fast update. .. container:: twocol .. container:: leftside40 .. image:: _static/thumb_ptirds3.png :alt: Pricing and Trading Interest Rate Derivatives :target: https://www.amazon.com/Pricing-Trading-Interest-Rate-Derivatives/dp/0995455538 :width: 145 :align: center .. container:: rightside60 Chapter 19 of Pricing and Trading Interest Rate Derivatives discusses and outlines the use of *'slow and fast'* methods for *Curve* building in market-making. .. raw:: html
The Fast Update ***************** The basic server application is the **slow** update. It calibrates a *Curve* with market data through multiple iterations, and it does so every 10 seconds. When calculating the rate, $r$, of an :class:`~rateslib.instruments.IRS` from a :class:`~rateslib.curves.Curve` calibrated by a :class:`~rateslib.solver.Solver`, it is measured as :math:`r(\mathbf{v})`. The *Curve* parameters :math:`\mathbf{v}` are determined as of the market data set that was used to calibrate the *Curve*, call it, :math:`\mathbf{s}`. This, however, may be old and potentially out of date (we are talking in terms of seconds). Therefore we seek an adjustment to :math:`r(\mathbf{v})` which accounts for market data movement since that time to the streaming, real-time data, which we call :math:`\mathbf{\hat{s}}`. A **linear approximation** is assumed. I.e. we seek: .. math:: \hat{r}(\mathbf{v}) = r(\mathbf{v}) + \nabla_{\mathbf{s}} r(\mathbf{v}) \cdot \Delta \mathbf{s}, \qquad \text{where} \quad \Delta \mathbf{s} = \mathbf{\hat{s}} - \mathbf{s} Using the chain rule we have that, .. math:: \hat{r}(\mathbf{v}) = r(\mathbf{v}) + \nabla_{\mathbf{s}} \mathbf{v^T} \nabla_{\mathbf{v}} r(\mathbf{v}) \cdot (\mathbf{\hat{s}} - \mathbf{s}) It just so happens that the :class:`~rateslib.solver.Solver` generates all of these quantities directly: - :math:`\nabla_{\mathbf{s}} \mathbf{v^T}` is available as ``solver.grad_s_vT`` - :math:`\nabla_{\mathbf{v}} r(\mathbf{v})` is available as ``gradient(rate, solver.variables)`` So all that the new code needs to capture is the difference between the live market data and that used by the *Solver* in its calibration and perform the linear algebra. Code Changes ************** The code changes to the ``main.py`` are only to the client API USD swap rate request. .. code-block:: python # main.py from rateslib import IRS, FixedRateBond, gradient import numpy as np # ...previous code... @app.route('/api/usd_irs', methods=['GET']) def usd_irs(): bar = request.args.to_dict() bar["effective"] = datetime.strptime(bar["effective"], "%Y%m%d") bar["termination"] = datetime.strptime(bar["termination"], "%Y%m%d") irs = IRS(**bar, spec="usd_irs", curves=["sofr"]) rate = irs.rate(solver=GLOBAL["USD_SOLVER"]) dr_dv = gradient(rate, GLOBAL["USD_SOLVER"].variables) ds = np.array(update_usd_data()) - GLOBAL["USD_SOLVER"].s rate_hat = rate + np.inner(np.matmul(GLOBAL["USD_SOLVER"].grad_s_vT, dr_dv[:, None])[:, 0], ds) return { "solver_rate": float(rate), "rate": float(rate_hat), } Now when the server and the scheduler are both restarted and we visit the API endpoint: ``/api/usd_irs?effective=20000615&termination=20011215&frequency=A`` we now get a JSON return that gives the previous rate, as calculated directly from the :class:`~rateslib.solver.Solver`, and a rate that has the linear adjustment made to account for updated market data. In this example that rate will change every request since the market data has random updates. .. code-block:: # http://127.0.0.1:5000/api/usd_irs?effective=20000615&termination=20011215&frequency=A { "rate": 3.340708058569, "solver_rate": 3.36401626295668 } And that's it. A framework that calculates and returns a mid-market swap rate in micro seconds like a large investment bank.