.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/fixed_income/immunization/plot_02_fong_vasicek_m_squared.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code or to run this example in your browser via JupyterLite. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_fixed_income_immunization_plot_02_fong_vasicek_m_squared.py: Fong-Vasicek M-squared ====================== Redington's conditions protect against parallel shifts only. Fong and Vasicek (1984) showed that when the forward curve twists with slope at most :math:`K`, a duration-matched portfolio loses at most .. math:: \frac{\Delta V_H}{V_H} \ge -\tfrac12 K M^2, \qquad M^2 = \sum_i w_i (t_i - H)^2, where :math:`M^2` measures how far the cash flows are spread around the horizon :math:`H`. Among immunized portfolios the bullet, with the smallest :math:`M^2`, is the least exposed to twists. .. GENERATED FROM PYTHON SOURCE LINES 17-39 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from financialkit.fixed_income import ( CashFlows, FlatCurve, bond_cash_flows, fong_vasicek_bound, horizon_value, linear_forward_shock, m_squared, redington_immunize, ) curve, H = FlatCurve(0.04), 8.0 target = CashFlows([H], [1000.0]) portfolios = { "bullet 7y/9y": redington_immunize(target, [bond_cash_flows(1.0, 0.0, 7.0), bond_cash_flows(1.0, 0.0, 9.0)], curve).portfolio, "ladder 4y/14y": redington_immunize(target, [bond_cash_flows(1.0, 0.0, 4.0), bond_cash_flows(1.0, 0.0, 14.0)], curve).portfolio, "barbell 1y/30y": redington_immunize(target, [bond_cash_flows(1.0, 0.0, 1.0), bond_cash_flows(1.0, 0.0, 30.0)], curve).portfolio, } .. GENERATED FROM PYTHON SOURCE LINES 40-42 Horizon value under twists of the forward curve ----------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 42-57 .. code-block:: Python slopes = np.linspace(-0.004, 0.004, 41) fig, ax = plt.subplots() for name, port in portfolios.items(): m2 = m_squared(port, H, curve) base = horizon_value(port, curve, H) change = np.array([horizon_value(port, curve.shifted(linear_forward_shock(0.0, b, H)), H) / base - 1 for b in slopes]) (line,) = ax.plot(1e4 * slopes, 100 * change, label=f"{name}, $M^2$ = {m2:.1f}") ax.plot(1e4 * slopes[slopes > 0], 100 * fong_vasicek_bound(m2, slopes[slopes > 0]), ls=":", color=line.get_color()) ax.axhline(0.0, color="0.6", lw=0.8) ax.set_xlabel("forward-curve slope change $b$ (bp per year)") ax.set_ylabel("change in horizon value (%)") ax.set_title("Dotted: Fong-Vasicek bound $-K M^2/2$") ax.legend() plt.show() .. image-sg:: /api/gallery/fixed_income/immunization/images/sphx_glr_plot_02_fong_vasicek_m_squared_001.png :alt: Dotted: Fong-Vasicek bound $-K M^2/2$ :srcset: /api/gallery/fixed_income/immunization/images/sphx_glr_plot_02_fong_vasicek_m_squared_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.038 seconds) .. _sphx_glr_download_api_gallery_fixed_income_immunization_plot_02_fong_vasicek_m_squared.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../../../../lite/lab/index.html?path=api/gallery/fixed_income/immunization/plot_02_fong_vasicek_m_squared.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_02_fong_vasicek_m_squared.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_02_fong_vasicek_m_squared.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_02_fong_vasicek_m_squared.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_