Markets: A Rigorous Course

Exercise · m08_mc.py

Monte Carlo under the risk-neutral measure, finite-difference Greeks, and numerical checks of Ito calculus

Run: cd exercises && .venv/bin/python -m pytest modules/M08-option-pricing/tests/test_m08_mc.py Use numpy.random.default_rng(seed) for all randomness so results are reproducible.

bs_price below is the course's reference Black-Scholes (toolkit.options), so this exercise does not depend on your m08_black_scholes being finished. Once your version passes its tests you can swap the import for from m08_black_scholes import bs_price.

Tests (7)

  • test_mc_within_three_standard_errors
  • test_standard_error_scales_like_inverse_sqrt_n
  • test_risk_neutral_forward
  • test_mc_parity_with_common_random_numbers
  • test_fd_greeks_match_analytic
  • test_quadratic_variation_converges_to_T
  • test_ito_drift_correction

Theory: M08 notes. Run with Ctrl/⌘+Enter.

not run yet

Not saved: sign up to keep your code
"""M08 exercise: Monte Carlo under the risk-neutral measure, finite-difference Greeks,
and numerical checks of Ito calculus (notes §8.5, §8.7, §8.9).

Run: cd exercises && .venv/bin/python -m pytest modules/M08-option-pricing/tests/test_m08_mc.py
Use numpy.random.default_rng(seed) for all randomness so results are reproducible.

bs_price below is the course's reference Black-Scholes (toolkit.options), so this exercise
does not depend on your m08_black_scholes being finished. Once your version passes its
tests you can swap the import for `from m08_black_scholes import bs_price`.
"""

from __future__ import annotations

import math

import numpy as np

from toolkit.options import bs_price  # noqa: F401  (provided)


def gbm_terminal(S0: float, T: float, r: float, sigma: float, n_paths: int, seed: int, q: float = 0.0,
                 antithetic: bool = False) -> np.ndarray:
    """Exact draws of S_T under the risk-neutral measure (notes eq. (8.20)):

        S_T = S0 exp((r - q - sigma^2/2) T + sigma sqrt(T) Z),  Z ~ N(0,1).

    If antithetic, draw n_paths//2 normals z and use the concatenation [z, -z].
    """
    raise NotImplementedError


def mc_price(S: float, K: float, T: float, r: float, sigma: float, kind: str = "call", q: float = 0.0,
             n_paths: int = 200_000, seed: int = 0) -> tuple[float, float]:
    """Risk-neutral Monte Carlo price e^{-rT} E[payoff(S_T)] using gbm_terminal (no antithetics).
    Return (estimate, standard_error) where standard_error = sample sd (ddof=1) of the discounted
    payoffs / sqrt(n_paths). The test requires |estimate - bs_price| < 3 * standard_error."""
    raise NotImplementedError


def mc_parity_residual(S: float, K: float, T: float, r: float, sigma: float, q: float = 0.0,
                       n_paths: int = 100_000, seed: int = 0) -> float:
    """Using ONE set of draws S_T, compute MC call C, MC put P and the MC forward value
    e^{-rT}(mean(S_T) - K). Return C - P - forward. Explain (notes §8.2) why this is zero to
    rounding error path by path, even though each of C and P has Monte Carlo error."""
    raise NotImplementedError


def fd_greeks(S: float, K: float, T: float, r: float, sigma: float, kind: str = "call", q: float = 0.0,
              h_rel: float = 1e-4) -> dict:
    """Central finite-difference Greeks of bs_price, same keys and units as bs_greeks:
    delta and gamma with step h = h_rel*S; vega and rho with step 1e-5; theta = -dV/dT with step 1e-6.
    gamma = [V(S+h) - 2V(S) + V(S-h)] / h^2."""
    raise NotImplementedError


def quadratic_variation(T: float, n_steps: int, seed: int) -> float:
    """Simulate n_steps Brownian increments dW ~ N(0, T/n_steps) and return sum(dW^2).
    It converges to T as n_steps -> infinity (notes Prop. 8.5.1), with sd T sqrt(2/n_steps)."""
    raise NotImplementedError


def gbm_log_return_moments(mu: float, sigma: float, T: float, n_steps: int, n_paths: int, seed: int) -> tuple[float, float]:
    """Euler-simulate dS = mu S dt + sigma S dW from S0 = 1 with n_steps steps
    (S <- S (1 + mu dt + sigma sqrt(dt) Z)). Return (mean, sample variance with ddof=1) of ln S_T.
    Ito's lemma (notes §8.5) predicts mean (mu - sigma^2/2) T and variance sigma^2 T."""
    raise NotImplementedError

No runs yet

The stub's functions raise NotImplementedError until you write them. Fill in one, press Run tests, and watch its tests turn green.

Reference solution

Available after your first run, with an account approved for code runs.

Create a free account

Reading is open to everyone. An account keeps your progress, answers, notes and code drafts, and gives you the study plan, the journals and the simulator. Running code needs an account approved for it.