{ "cells": [ { "cell_type": "markdown", "id": "bb795a90-6814-49e8-ad0b-a3c354f1ec8f", "metadata": {}, "source": [ "# Another Example of an Exogenous Variable (SABR's Beta)\n", "\n", "The development of **exogenous variables** in *rateslib* came with attempting to capture sensitivity to *recovery risk* for a credit name with *CDSs*.\n", "But, their scope is completely general and they are easily used.\n", "\n", "Here we will give a second example of capturing sentivity to the **beta** parameter in a SABR model for *FXOptions*.\n", "The **beta** parameter is usually characterised as representing how normal or log-normal the underlying price process is; zero for fully normal and one for fully log-normal with a ranged value representing a blend.\n", "\n", "We can plot the variation in a *SabrSmile* below for differing values.\n", "\n", "First we create the *FX Forwards* market consistent with some of the other *FX Option* cookbooks." ] }, { "cell_type": "code", "execution_count": null, "id": "846e5f66-2f30-4666-b6eb-e69ae445da06", "metadata": {}, "outputs": [], "source": [ "from rateslib import *\n", "from pandas import DataFrame\n", "\n", "eur = Curve({dt(2009, 5, 3): 1.0, dt(2011, 5, 10): 1.0})\n", "usd = Curve({dt(2009, 5, 3): 1.0, dt(2011, 5, 10): 1.0})\n", "fxf = FXForwards(\n", " fx_rates=FXRates({\"eurusd\": 1.34664}, settlement=dt(2009, 5, 5)),\n", " fx_curves={\"eureur\": eur, \"usdusd\": usd, \"eurusd\": eur},\n", ")\n", "fx_solver = Solver(\n", " curves=[eur, usd],\n", " instruments=[\n", " Value(dt(2009, 5, 4), curves=eur, metric=\"cc_zero_rate\"),\n", " Value(dt(2009, 5, 4), curves=usd, metric=\"cc_zero_rate\")\n", " ],\n", " s=[1.00, 0.4759550366220911],\n", " fx=fxf,\n", ")" ] }, { "cell_type": "markdown", "id": "5450450e-97a3-4f74-90df-823c623c7c63", "metadata": {}, "source": [ "Then build and calibrate an *FXSabrSmile*." ] }, { "cell_type": "code", "execution_count": null, "id": "252f3e84-7143-4326-bc36-557745227625", "metadata": {}, "outputs": [], "source": [ "fxs = FXSabrSmile(\n", " nodes={\"alpha\": 0.04, \"beta\": Variable(0.9, [\"beta\"]), \"rho\": 0.00, \"nu\": 0.01},\n", " eval_date=dt(2009, 5, 3), expiry=dt(2010, 5, 3), pair=\"eurusd\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "b055bd0e-fea0-452d-8725-6989f6001a59", "metadata": {}, "outputs": [], "source": [ "solver = Solver(\n", " pre_solvers=[fx_solver],\n", " curves=[fxs],\n", " instruments=[\n", " FXCall(expiry=dt(2010, 5, 3), pair=\"eurusd\", strike=\"25d\", curves=[None, eur, None, usd], vol=fxs, metric=\"vol\"),\n", " FXCall(expiry=dt(2010, 5, 3), pair=\"eurusd\", strike=\"atm_delta\", curves=[None, eur, None, usd], vol=fxs, metric=\"vol\"),\n", " FXCall(expiry=dt(2010, 5, 3), pair=\"eurusd\", strike=\"75d\", curves=[None, eur, None, usd], vol=fxs, metric=\"vol\"),\n", " ],\n", " s=[10.0, 9.0, 9.9],\n", " fx=fxf,\n", " id=\"options\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "a7a53062-f2b5-4a01-a97a-bd90391953fa", "metadata": {}, "outputs": [], "source": [ "fxs.plot(f=fxf)" ] }, { "cell_type": "markdown", "id": "f5f5a0ae-8282-4667-b45f-591824589fc8", "metadata": {}, "source": [ "## Beta sensitivity\n", "\n", "What is the sensitivity if **beta** changes on this *Smile*? We can evaluate it numerically for a specific *Option*.\n", "This numeric method involves a finite difference approach, shifting it up and down and revaluing the *Option*." ] }, { "cell_type": "markdown", "id": "85b08e49-81fb-49fa-b740-f6743f0381b2", "metadata": {}, "source": [ "### Numerically: Finite Difference" ] }, { "cell_type": "code", "execution_count": null, "id": "deefaa37-f516-4540-b430-628bf8b04d13", "metadata": {}, "outputs": [], "source": [ "fxc = FXCall(expiry=dt(2010, 5, 3), pair=\"eurusd\", strike=1.40, curves=[None, eur, None, usd], vol=fxs, premium=26710)\n", "base_npv = fxc.npv(solver=solver)\n", "base_npv" ] }, { "cell_type": "code", "execution_count": null, "id": "97bd04e6-0080-4d6d-91ff-071bab56e489", "metadata": {}, "outputs": [], "source": [ "fxs.update_node(\"beta\", 0.91)\n", "solver.iterate()\n", "(fxc.npv(solver=solver) - base_npv) * 100.0" ] }, { "cell_type": "code", "execution_count": null, "id": "8ae3ea49-ef24-4e17-bbe3-4c05c7287dda", "metadata": {}, "outputs": [], "source": [ "fxs.update_node(\"beta\", 0.90) # reset\n", "solver.iterate()\n", "fxs.update_node(\"beta\", 0.89)\n", "solver.iterate()\n", "(fxc.npv(solver=solver) - base_npv) * 100.0" ] }, { "cell_type": "markdown", "id": "24d7c40a-9487-4774-a726-48d14993a4ae", "metadata": {}, "source": [ "### Rateslib AD: ``exo_delta``" ] }, { "cell_type": "markdown", "id": "19d77bee-7db9-438a-981c-4e97899eb8e0", "metadata": {}, "source": [ "The result of the finite difference approach is that if **beta** is increased by one unit the *Option* will lose in value by c.77.6USD, whilst if it is decreased by one unit the *Option* will gain in value by c.77.6USD.\n", "\n", "This **sensitivity** can be expressly calculated using ``exo_delta``. We have injected *Variable* sensitivity into the calculation process and all of the internal calculations are configured to recognise this." ] }, { "cell_type": "code", "execution_count": null, "id": "73c45a04-5387-49bd-9bf5-42a45b016650", "metadata": {}, "outputs": [], "source": [ "fxs.update_node(\"beta\", Variable(0.9, [\"beta\"]))\n", "solver.iterate()\n", "fxc.exo_delta(solver=solver, vars=[\"beta\"])" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.0" } }, "nbformat": 4, "nbformat_minor": 5 }