{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c15ea663",
   "metadata": {},
   "source": [
    "<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27de4862",
   "metadata": {},
   "source": [
    "This code simulates Geometric Brownian Motion (GBM) to model asset price paths over time, incorporating randomness and volatility in financial markets. It defines functions to generate a Wiener process (representing Brownian motion) and to compute GBM returns and price levels. Parameters such as initial stock price, volatility, drift, and the number of paths and time increments are used to create and visualize multiple simulated price trajectories. This is useful in practice for financial modeling, risk analysis, and forecasting asset prices."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a00ae207",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bcf516dd",
   "metadata": {},
   "source": [
    "Define initial stock price, volatility, and drift parameters for the Brownian motion"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f681a18e",
   "metadata": {},
   "outputs": [],
   "source": [
    "s0 = 131.00\n",
    "sigma = 0.25\n",
    "mu = 0.35"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99903829",
   "metadata": {},
   "source": [
    "Define simulation parameters including number of paths, time increment, and total simulation time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fb7fb1a0",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "paths = 1000\n",
    "delta = 1.0 / 252.0\n",
    "time = 252 * 5"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b39aae7c",
   "metadata": {},
   "source": [
    "Generate a Wiener process (or Brownian motion) using normally distributed random values. This process simulates the random fluctuations of an asset's price over time, which is essential for modeling the stochastic component of Geometric Brownian Motion."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b5088fe0",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "def wiener_process(delta, sigma, time, paths):\n",
    "    \"\"\"Returns a Wiener process\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    delta : float\n",
    "        The increment to downsample sigma\n",
    "    sigma : float\n",
    "        Percentage volatility\n",
    "    time : int\n",
    "        Number of samples to create\n",
    "    paths : int\n",
    "        Number of price simulations to create\n",
    "    \n",
    "    Returns\n",
    "    -------\n",
    "    wiener_process : np.array\n",
    "    \n",
    "    Notes\n",
    "    -----\n",
    "    This method returns a Wiener process. \n",
    "    The Wiener process is also called Brownian \n",
    "    motion. For more information about the \n",
    "    Wiener process check out the Wikipedia \n",
    "    page: http://en.wikipedia.org/wiki/Wiener_process\n",
    "    \"\"\"\n",
    "\n",
    "    # Generate a Wiener process using normally distributed random values\n",
    "    return sigma * np.random.normal(loc=0, scale=np.sqrt(delta), size=(time, paths))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "da8be9d1",
   "metadata": {},
   "source": [
    "Generate returns from a Geometric Brownian Motion (GBM) model by first creating a Wiener process to simulate random fluctuations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4a472551",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "def gbm_returns(delta, sigma, time, mu, paths):\n",
    "    \"\"\"Returns returns from a Geometric brownian motion\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    delta : float\n",
    "        The increment to downsample sigma\n",
    "    sigma : float\n",
    "        Percentage volatility\n",
    "    time : int\n",
    "        Number of samples to create\n",
    "    mu : float\n",
    "        Percentage drift\n",
    "    paths : int\n",
    "        Number of price simulations to create\n",
    "    \n",
    "    Returns\n",
    "    -------\n",
    "    gbm_returns : np.ndarray\n",
    "    \n",
    "    Notes\n",
    "    -----\n",
    "    This method constructs random Geometric Brownian \n",
    "    Motion (GBM).\n",
    "    \"\"\"\n",
    "\n",
    "    # Generate Wiener process for the simulation\n",
    "    process = wiener_process(delta, sigma, time, paths)\n",
    "\n",
    "    # Apply the geometric Brownian motion formula to generate returns\n",
    "    return np.exp(\n",
    "        process + (mu - sigma**2 / 2) * delta\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0bd6fb5",
   "metadata": {},
   "source": [
    "Calculate price paths starting from an initial stock price (s0) using Geometric Brownian Motion (GBM)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e095c104",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "def gbm_levels(s0, delta, sigma, time, mu, paths):\n",
    "    \"\"\"Returns price paths starting at s0\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    s0 : float\n",
    "        The starting stock price\n",
    "    delta : float\n",
    "        The increment to downsample sigma\n",
    "    sigma : float\n",
    "        Percentage volatility\n",
    "    time : int\n",
    "        Number of samples to create\n",
    "    mu : float\n",
    "        Percentage drift\n",
    "    paths : int\n",
    "        Number of price simulations to create\n",
    "    \n",
    "    Returns\n",
    "    -------\n",
    "    gbm_levels : np.ndarray\n",
    "    \"\"\"\n",
    "\n",
    "    # Generate GBM returns for the given parameters\n",
    "    returns = gbm_returns(delta, sigma, time, mu, paths)\n",
    "\n",
    "    # Stack an array of ones with the returns and compute cumulative product to get price levels\n",
    "    stacked = np.vstack([np.ones(paths), returns])\n",
    "    return s0 * stacked.cumprod(axis=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "997935cd",
   "metadata": {},
   "source": [
    "Generate price paths using the defined GBM model and plot them"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa8a0403",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_paths = gbm_levels(s0, delta, sigma, time, mu, paths)\n",
    "plt.plot(price_paths, linewidth=0.25)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d99436d",
   "metadata": {},
   "source": [
    "Generate price paths with zero drift to observe behavior and plot them"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58e1b03e",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_paths = gbm_levels(s0, delta, sigma, time, 0.0, paths)\n",
    "plt.plot(price_paths, linewidth=0.25)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c1d6887",
   "metadata": {},
   "source": [
    "<a href=\"https://pyquantnews.com/\">PyQuant News</a> is where finance practitioners level up with Python for quant finance, algorithmic trading, and market data analysis. Looking to get started? Check out the fastest growing, top-selling course to <a href=\"https://gettingstartedwithpythonforquantfinance.com/\">get started with Python for quant finance</a>. For educational purposes. Not investment advise. Use at your own risk."
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "main_language": "python",
   "notebook_metadata_filter": "-all"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
