.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/pde_methods/stability/plot_03_rannacher_smoothing.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_pde_methods_stability_plot_03_rannacher_smoothing.py: Rannacher smoothing =================== Crank-Nicolson is stable, but its amplification factor tends to :math:`-1` for the stiffest modes, so the high-frequency error excited by a payoff kink is never damped: it just flips sign every step. With large time steps the price looks fine while delta and gamma oscillate around the strike. Rolf Rannacher (1984) proposed starting with a few fully implicit steps, which damp those modes, before switching to Crank-Nicolson. :class:`~financialkit.pde_methods.CrankNicolson` with ``rannacher_steps=2`` replaces the first two steps by four implicit half steps. .. GENERATED FROM PYTHON SOURCE LINES 17-28 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from financialkit.options import black_scholes_greeks from financialkit.pde_methods import CrankNicolson S, K, T, r, sigma = 100.0, 100.0, 0.25, 0.05, 0.2 plain = CrankNicolson(400, 10, s_max=400.0).price(S, K, T, r, sigma) smooth = CrankNicolson(400, 10, rannacher_steps=2, s_max=400.0).price(S, K, T, r, sigma) print(f"prices: plain CN {plain.price:.4f}, Rannacher {smooth.price:.4f}") .. rst-class:: sphx-glr-script-out .. code-block:: none prices: plain CN 4.5980, Rannacher 4.6062 .. GENERATED FROM PYTHON SOURCE LINES 29-31 Gamma on the grid, from second differences ------------------------------------------ .. GENERATED FROM PYTHON SOURCE LINES 31-46 .. code-block:: Python h = plain.S[1] - plain.S[0] s = plain.S[1:-1] near = (s > 75) & (s < 125) exact = black_scholes_greeks(s[near], K, T, r, sigma).gamma fig, axes = plt.subplots(1, 2, figsize=(11, 4), sharey=True) for ax, res, title in ((axes[0], plain, "Crank-Nicolson"), (axes[1], smooth, "Crank-Nicolson + Rannacher")): ax.plot(s[near], np.diff(res.V, 2)[near] / h**2, ".-", ms=3, label="grid gamma") ax.plot(s[near], exact, "k", lw=1, label="Black-Scholes") ax.set_title(title) ax.set_xlabel("spot S") ax.legend() axes[0].set_ylabel("gamma") fig.tight_layout() plt.show() .. image-sg:: /api/gallery/pde_methods/stability/images/sphx_glr_plot_03_rannacher_smoothing_001.png :alt: Crank-Nicolson, Crank-Nicolson + Rannacher :srcset: /api/gallery/pde_methods/stability/images/sphx_glr_plot_03_rannacher_smoothing_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.057 seconds) .. _sphx_glr_download_api_gallery_pde_methods_stability_plot_03_rannacher_smoothing.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/pde_methods/stability/plot_03_rannacher_smoothing.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_03_rannacher_smoothing.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_03_rannacher_smoothing.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_03_rannacher_smoothing.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_