[7]:
from hestonpy.models.heston import Heston
import matplotlib.pyplot as plt
import numpy as np

Hedging with Heston#

We delta and vega hedge with an other call with 110% of strike and 120% of time to maturity

[8]:
# Parameters for the Heston model
S0 = 100.0  # Initial spot price
V0 = 0.06  # Initial volatility
r = 0.03  # Risk-free interest rate

params = {
    'kappa': 1.0,  # Mean reversion rate
    'theta': 0.06,  # Long-term volatility
    'drift_emm': 0.00,  # Drift term
    'sigma': 0.3,  # Volatility of volatility
    'rho': -0.5,  # Correlation between asset and volatility
}
heston = Heston(spot=S0, vol_initial=V0, r=r, **params)

strike = 100
strike_hedging = 110
maturity = 1
maturity_hedging = 1.2
nbr_points = 252
nbr_simulations = 1000

portfolio, S, V, C = heston.delta_vega_hedging(
    strike,
    strike_hedging,
    maturity,
    maturity_hedging,
    nbr_points,
    nbr_simulations
)
Computing option prices ...
Computing vegas ...
Computing deltas ...
100%|██████████| 251/251 [00:00<00:00, 9276.82it/s]

Replication errors#

Sanity check of the replication

[9]:
ST = S[:, -1]
VT = portfolio[:, -1]

plt.figure(figsize=(5, 5))
plt.title("Réplication du payoff")
plt.grid(linestyle="--", dashes=(5, 10), color="gray", linewidth=0.5)
plt.minorticks_on()
plt.xlabel(r"$S_T$")
plt.ylabel("payoff")
plt.scatter(ST, VT, s=0.8, color="red")
x = np.linspace(min(ST), max(ST))
payoff = np.maximum(0, x - strike)
plt.plot(x, payoff, color="blue")
plt.show()
../../_images/examples_hedging_hedging_heston_6_0.png

Sanity check of the replication

[10]:
ST = S[:, -1]
VT = portfolio[:, -1]

from scipy.stats import norm

cash_flows = np.maximum(0, ST - strike)
hedging_errors = VT - cash_flows
hedging_errors = hedging_errors[np.abs(hedging_errors) < 5]

plt.figure(figsize=(15, 8))
plt.hist(hedging_errors, bins="fd", density=True, color="gray", alpha=0.8)
plt.axvline(np.mean(hedging_errors), color="black", label="mean", alpha=0.8)

x = np.linspace(start=min(hedging_errors), stop=max(hedging_errors), num=100)
plt.plot(
    x,
    norm.pdf(x, loc=np.mean(hedging_errors), scale=np.std(hedging_errors)),
    label="normal density",
    color="blue",
)
plt.xlabel(r"Hedging errors: $V_T - (S_T - K)^+$")
plt.grid(linestyle="--", dashes=(5, 10), color="gray", linewidth=0.5)
plt.minorticks_on()
plt.legend()
plt.tight_layout()
plt.show()
../../_images/examples_hedging_hedging_heston_8_0.png

Evolution of the replication portfolio#

[11]:
time = np.linspace(start=0, stop=maturity, num=nbr_points + 1)

path = -10

fig, (ax1, ax2) = plt.subplots(2, figsize=(15, 8))

plt.suptitle("Portefeuille de réplication")

ax1.plot(time, C[path, :], label="target call")
ax1.plot(time, portfolio[path, :], label="portfolio")
ax1.grid(linestyle="--", dashes=(5, 10), color="gray", linewidth=0.5)
ax1.minorticks_on()
ax1.legend()

ax2.axhline(y=strike, label="Target strike", linestyle="dashed", color='black', linewidth=0.7)
ax2.axhline(y=strike_hedging, label="Hedging strike", linestyle="dashed", color='black', linewidth=0.7)
ax2.plot(time, S[path, :], label="Underlying")
ax2.grid(linestyle="--", dashes=(5, 10), color="gray", linewidth=0.5)
ax2.minorticks_on()
ax2.set_xlabel("Time")
ax2.legend()

plt.tight_layout()
plt.show()
../../_images/examples_hedging_hedging_heston_10_0.png

More fancy examples

[13]:
nbr_simulations_to_plot = 5
time = np.linspace(start=0, stop=maturity, num=nbr_points + 1)
paths = range(nbr_simulations_to_plot)

for path in paths:

    fig, (ax1, ax2, ax3) = plt.subplots(3, figsize=(15, 10))

    plt.suptitle(f"Portefeuille de réplication - simulation {path}")

    # Tracé avec des styles différents
    ax1.plot(time, portfolio[path, :], label="Portfolio", color='blue', marker='+')
    ax1.plot(time, C[path, :], label="Call", color='red', marker='+')
    ax1.grid(linestyle="--", dashes=(5, 10), color="gray", linewidth=0.5)
    ax1.minorticks_on()
    ax1.legend()

    # Tracé avec des styles différents
    ax2.plot(time, S[path, :], label="Risky asset", color='red', marker='+')
    ax2.grid(linestyle="--", dashes=(5, 10), color="gray", linewidth=0.5)
    ax2.minorticks_on()
    ax2.legend()

    # Tracé du sous-jacent et des strikes
    ax3.plot(time, V[path, :]*100, label="Variance", color='red', marker='+')
    ax3.grid(linestyle="--", dashes=(5, 10), color="gray", linewidth=0.5)
    ax3.minorticks_on()
    ax3.set_xlabel("Time")
    ax3.set_ylabel("%")
    ax3.legend()

    plt.tight_layout()
    plt.show()
../../_images/examples_hedging_hedging_heston_12_0.png
../../_images/examples_hedging_hedging_heston_12_1.png
../../_images/examples_hedging_hedging_heston_12_2.png
../../_images/examples_hedging_hedging_heston_12_3.png
../../_images/examples_hedging_hedging_heston_12_4.png