Skip to content

Plots and more

implied vol

finmc.plots.impliedvol.plot_iv

Plot the implied volatility surface and forward curve.

Parameters:

Name Type Description Default
strikes array

The strike prices.

required
expirations array

The expiration times.

required
surface array

The implied volatility surface.

required

Examples:

>>> plot_iv(strikes, expirations, surface)
Source code in finmc\plots\impliedvol.py
def plot_iv(strikes, expirations, surface):
    """Plot the implied volatility surface and forward curve.

    Args:
        strikes (np.array): The strike prices.
        expirations (np.array): The expiration times.
        surface (np.array): The implied volatility surface.

    Examples:
        >>> plot_iv(strikes, expirations, surface)
    """

    X, Y = np.meshgrid(strikes, expirations)
    fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize=(6, 6))
    ax.plot_surface(
        X,
        Y,
        surface,
        cmap=cm.inferno,
        alpha=0.5,
    )
    # Add wireframes for each expiration
    ax.plot_wireframe(X, Y, surface, color="brown", rstride=1, cstride=0)

    (z0, z1) = ax.get_zlim()
    if z1 - z0 < 0.05:
        ax.set_zlim(z0, z0 + 0.05)

    ax.set_xlabel("Strike (K)")
    ax.set_ylabel("Maturity (years)")
    plt.show()

finmc.plots.impliedvol.plot_atmvols

Plot the implied volatility surface and forward curve.

Parameters:

Name Type Description Default
expirations array

The expiration times.

required
atm_vols array

The ATM volatilities.

required

Examples:

>>> plot_atmvols(expirations, atm_vols)
Source code in finmc\plots\impliedvol.py
def plot_atmvols(expirations, atm_vols):
    """Plot the implied volatility surface and forward curve.

    Args:
        expirations (np.array): The expiration times.
        atm_vols (np.array): The ATM volatilities.

    Examples:
        >>> plot_atmvols(expirations, atm_vols)
    """

    # Add atm vol curve
    fig, ax = plt.subplots(figsize=(5, 2))
    ax.plot(
        expirations, atm_vols, color="brown", label="Forward Curve", marker="o"
    )

    (y0, y1) = ax.get_ylim()
    if y1 - y0 < 0.05:
        ax.set_ylim(y0 - 0.01, y0 + 0.05)

    ax.set_xlabel("Maturity (years)")
    ax.set_ylabel("ATM Vol")
    plt.show()

(See Heston Notebook for complete example)

asset

finmc.plots.asset.plot_asset

Plot the progression of an asset in a model.

Parameters:

Name Type Description Default
model MCBase

The model to use.

required
asset_name str

The name of the asset to plot.

required
sample_idxs array

The indices of the sample paths to plot in the foreground. Defaults to the first three.

arange(0, 3, 1)
q_levels array

The quantiles to show in the background. Defaults to 25 levels from 2% to 98%.

linspace(0.02, 0.98, 25)
times array

The timesteps. Defaults to 1 year in 100 steps.

linspace(0, 1, 101)

Examples:

>>> plot_asset(model, "SPX")
Source code in finmc\plots\asset.py
def plot_asset(
    model: MCBase,
    asset_name: str,
    sample_idxs=np.arange(0, 3, 1),
    q_levels=np.linspace(0.02, 0.98, 25),
    times=np.linspace(0, 1, 101),
):
    """Plot the progression of an asset in a model.

    Args:
        model: The model to use.
        asset_name: The name of the asset to plot.
        sample_idxs (np.array, optional): The indices of the sample paths to plot in the foreground. Defaults to the first three.
        q_levels (np.array, optional): The quantiles to show in the background. Defaults to 25 levels from 2% to 98%.
        times (np.array, optional): The timesteps. Defaults to 1 year in 100 steps.

    Examples:
        >>> plot_asset(model, "SPX")
    """

    num_levels = len(q_levels)
    num_steps = len(times)

    samples = np.zeros((len(sample_idxs), num_steps))
    quantiles = np.zeros((len(q_levels), num_steps))

    # enumerate over the time steps and calculate the spot price
    model.reset()
    for i, t in enumerate(times):
        model.advance(t)
        spots = model.get_value(asset_name)
        quantiles[:, i] = np.quantile(spots, q_levels)
        samples[:, i] = spots[sample_idxs]

    fig, ax = plt.subplots(figsize=(8, 3))

    for i in range(num_levels >> 1):
        ax.fill_between(
            times,
            quantiles[i, :],
            quantiles[num_levels - 1 - i, :],
            color="darkred",
            alpha=1.5 / num_levels,
            edgecolor="none",
        )
    for sample in samples:
        ax.plot(times, sample)
    ax.set_xlabel("years")
    ax.set_ylabel(asset_name)
    ax.tick_params(axis="x", direction="in", pad=-15)

    for side in ["left", "bottom", "right", "top"]:
        ax.spines[side].set_visible(False)

    plt.show()

Utility to calculate option prices or implied volatility surface from a MC Simulation, for any model. This is useful for calibrating the model to Black-Scholes option prices.

finmc.calc.impliedvol.iv_surface_mc

Calculate the implied volatility surface using MC Simulation.

Parameters:

Name Type Description Default
strikes

The strikes of the options.

required
expirations

The expirations of the options in years.

required
asset_name str

The name of the asset.

required
model MCBase

The model used to simulate the asset price.

required
is_log bool

if True, the strikes are in log, i.e. log(K/F).

False

Returns:

Type Description

The implied volatility surface as a 2D numpy array with a row for each strike and a column for each expiration.

Examples:

>>> strikes = np.linspace(2900, 3100, 3)
>>> expirations = [0.25, 0.5, 1]
>>> surface = iv_surface_mc(strikes, expirations, "SPX", model)
Source code in finmc\calc\impliedvol.py
def iv_surface_mc(
    strikes,
    expirations,  # in years, increasing order
    asset_name: str,
    model: MCBase,
    is_log: bool = False,
):
    """Calculate the implied volatility surface using MC Simulation.

    Args:
        strikes: The strikes of the options.
        expirations: The expirations of the options in years.
        asset_name: The name of the asset.
        model: The model used to simulate the asset price.
        is_log: if True, the strikes are in log, i.e. log(K/F).

    Returns:
        The implied volatility surface as a 2D numpy array with a row for each strike and a column for each expiration.

    Examples:
        >>> strikes = np.linspace(2900, 3100, 3)
        >>> expirations = [0.25, 0.5, 1]
        >>> surface = iv_surface_mc(strikes, expirations, "SPX", model)
    """

    iv_mat = np.zeros((len(expirations), len(strikes)))

    model.reset()
    for i, exp in enumerate(expirations):
        model.advance(exp)
        spots = model.get_value(asset_name)
        fwd = spots.mean()

        # calculate implied vols
        if is_log:
            iv_mat[i, :] = _iv_strike(spots, fwd * np.exp(strikes), fwd, exp)
        else:
            iv_mat[i, :] = _iv_strike(spots, strikes, fwd, exp)
    return iv_mat

finmc.calc.impliedvol.atmvols_mc

Calculate the atmvols using MC Simulation.

Parameters:

Name Type Description Default
expirations

The expirations of the options in years.

required
asset_name str

The name of the asset.

required
model MCBase

The model used to simulate the asset price.

required

Returns:

Type Description

A tuple containing the ATM volatilities, and the forward prices.

Examples:

>>> strikes = np.linspace(2900, 3100, 3)
>>> expirations = [0.25, 0.5, 1]
>>> atm_vols, fwds = atmvols_mc(expirations, "SPX", model)
Source code in finmc\calc\impliedvol.py
def atmvols_mc(
    expirations,  # in years, increasing order
    asset_name: str,
    model: MCBase,
):
    """Calculate the atmvols using MC Simulation.

    Args:
        expirations: The expirations of the options in years.
        asset_name: The name of the asset.
        model: The model used to simulate the asset price.

    Returns:
        A tuple containing the ATM volatilities, and the forward prices.

    Examples:
        >>> strikes = np.linspace(2900, 3100, 3)
        >>> expirations = [0.25, 0.5, 1]
        >>> atm_vols, fwds = atmvols_mc(expirations, "SPX", model)
    """

    iv_atm = []
    fwds = []
    model.reset()
    for i, exp in enumerate(expirations):
        model.advance(exp)
        spots = model.get_value(asset_name)
        fwd = spots.mean()

        # calculate atm vols
        atm_call = np.maximum(spots - fwd, 0).mean()
        # calculate implied vols and fwds
        fwds.append(fwd)
        iv_atm.append(impliedvol(atm_call, fwd, fwd, exp, True))
    return np.array(iv_atm), np.array(fwds)