{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6m5p_ELu9PWr"
      },
      "source": [
        "# Capstone Project: Modeling with Calculus\n",
        "## Part 1 — Python Notebook\n",
        "**Calculus II · STM 1002 · University of Austin · Spring 2026**\n",
        "\n",
        "This notebook covers Parts 1(a) and 1(d). Include your response to 1(e) in this notebook as well. Complete the hand computations and written responses for Parts 1(b) and 1(c) and submit them together with a PDF export of this notebook.\n",
        "\n",
        "---"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "a0di9w0N9PWs"
      },
      "outputs": [],
      "source": [
        "# Run this cell first — imports everything the notebook needs\n",
        "import yfinance as yf\n",
        "import numpy as np\n",
        "from scipy.stats import norm"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jjA3s8yf9PWs"
      },
      "source": [
        "## Project Parameters\n",
        "\n",
        "These are fixed for the project. Do not change them."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "id": "j9Drl4XN9PWs"
      },
      "outputs": [],
      "source": [
        "S0    = 7414       # SPX live level, 2026-05-13 11:17 EDT (index points)\n",
        "K     = 7900       # strike, in index points (fixed by contract)\n",
        "T     = 0.523      # time to expiration, in years (191 days / 365, May 13 -> Nov 20 2026)\n",
        "r     = 0.036      # 13-week T-bill rate, 2026-05-13 11:17 EDT (3.60%)\n",
        "C_mkt = 180.30     # bid-ask midpoint for SPX261120C07900000, 2026-05-13 11:17 EDT (bid 179.80, ask 180.80)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kUE1Hc6n9PWt"
      },
      "source": [
        "---\n",
        "## Part 1(a) — Estimate σ from Historical SPX Data\n",
        "\n",
        "Your one task here: choose how many calendar days of historical data to use, run the code, and record your σ estimate.\n",
        "\n",
        "In your written submission, report:\n",
        "- Your value of `lookback_days` and a brief justification for why you chose it\n",
        "- The number of daily returns the download produced\n",
        "- Your estimated σ"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "7DYlpECF9PWt",
        "outputId": "3050d080-d4f6-477e-cb2c-6b3652dc25be",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Calendar days requested:       3650\n",
            "Daily returns computed:        3649\n",
            "\n",
            "Daily std dev of log-returns:  0.010612\n",
            "Annualized volatility (σ):     0.1685  (16.85%)\n"
          ]
        }
      ],
      "source": [
        "# ── YOUR CHOICE ──────────────────────────────────────────────────────────────\n",
        "# How many calendar days of historical data do you want to use?\n",
        "# A longer window gives a more stable estimate; a shorter window is more recent.\n",
        "# Try a few values and think about the trade-off before settling on one.\n",
        "\n",
        "lookback_days = 3650   # <-- fill in your choice (e.g. 90, 180, 252, 365)\n",
        "\n",
        "# ── DATA DOWNLOAD ─────────────────────────────────────────────────────────────\n",
        "# Download daily closing prices for the S&P 500 index from Yahoo Finance\n",
        "spx = yf.download(\"^GSPC\", period=f\"{lookback_days}d\", auto_adjust=True, progress=False)\n",
        "\n",
        "# Extract just the closing prices as a simple series\n",
        "closes = spx[\"Close\"].squeeze()\n",
        "\n",
        "# ── LOG-RETURNS ───────────────────────────────────────────────────────────────\n",
        "# Compute the daily log-return: r_t = ln(S_t / S_{t-1})\n",
        "# This is the natural log of today's close divided by yesterday's close.\n",
        "# .shift(1) shifts the series one day back, so closes / closes.shift(1) = S_t / S_{t-1}\n",
        "# .dropna() removes the first row, which has no previous day to compare to\n",
        "log_returns = np.log(closes / closes.shift(1)).dropna()\n",
        "\n",
        "n_days = len(log_returns)\n",
        "print(f\"Calendar days requested:       {lookback_days}\")\n",
        "print(f\"Daily returns computed:        {n_days}\")\n",
        "\n",
        "# ── VOLATILITY ESTIMATE ───────────────────────────────────────────────────────\n",
        "# The sample standard deviation of log-returns measures day-to-day variability.\n",
        "daily_std = log_returns.std()\n",
        "\n",
        "# \"Annualize\" means: re-express the volatility as if it described variability\n",
        "# over a full year, rather than over a single day. We need this because the\n",
        "# Black-Scholes formula uses T measured in years, so σ must be on the same scale.\n",
        "#\n",
        "# Why sqrt(252) and not just 252?\n",
        "# If daily returns are independent, variances add: the variance over n days is\n",
        "# n × (daily variance). Standard deviation is the square root of variance, so\n",
        "# the standard deviation over n days is daily_std × sqrt(n).\n",
        "# A trading year has ~252 days, so the annual std dev is daily_std × sqrt(252).\n",
        "sigma = daily_std * np.sqrt(252)\n",
        "\n",
        "print(f\"\\nDaily std dev of log-returns:  {daily_std:.6f}\")\n",
        "print(f\"Annualized volatility (σ):     {sigma:.4f}  ({sigma*100:.2f}%)\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7-kestYT9PWt"
      },
      "source": [
        "---\n",
        "## Part 1(d) — Black-Scholes in Python\n",
        "\n",
        "*Complete Parts 1(b) and 1(c) by hand before working on this section.*\n",
        "\n",
        "**What to do:**\n",
        "1. Write a function `black_scholes_call(S0, K, r, sigma, T)` that computes the Black-Scholes call price using `norm.cdf` for Φ.\n",
        "2. Run a sanity check: verify it returns approximately \\$10.45 for the standard test inputs.\n",
        "3. Run the function on the project parameters and report two comparisons:\n",
        "   - Your Taylor Φ(d₁) and Φ(d₂) from Part 1(b) vs. `norm.cdf(d1)` and `norm.cdf(d2)` — they should agree to at least three decimal places.\n",
        "   - Your hand-computed C from Part 1(c) vs. the Python output — they should agree to within rounding."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4iga3wuJ9PWt"
      },
      "outputs": [],
      "source": [
        "# ── YOUR CODE HERE ────────────────────────────────────────────────────────────\n",
        "\n",
        "def black_scholes_call(S0, K, r, sigma, T):\n",
        "    \"\"\"Compute the Black-Scholes price of a European call option.\"\"\"\n",
        "    # YOUR CODE HERE\n",
        "    pass #remove this line once you have written your function.\n",
        "\n",
        "\n",
        "# ── SANITY CHECK ──────────────────────────────────────────────────────────────\n",
        "# This standard test case has a known answer of approximately $10.45.\n",
        "# If your function is correct, the line below should print something close to 10.45.\n",
        "\n",
        "test_price = black_scholes_call(S0=100, K=100, r=0.05, sigma=0.20, T=1)\n",
        "print(f\"Sanity check (expect ~10.45): {test_price:.4f}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "U75qAkiD9PWt"
      },
      "outputs": [],
      "source": [
        "# ── PROJECT PARAMETERS ────────────────────────────────────────────────────────\n",
        "# Run the function on the actual option. Use the sigma you estimated in Part 1(a).\n",
        "\n",
        "# YOUR CODE HERE\n",
        "# Compute d1 and d2, then call norm.cdf, then compute C.\n",
        "# Print your results and compare to your hand calculations from Parts 1(b) and 1(c)."
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.11.0"
    },
    "colab": {
      "provenance": []
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}