{ "metadata": { "name": "", "signature": "sha256:71f7ca75a56fc9f5581dec973f6780669c121890a809f9bd5c590fdbb376dad2" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Stochasic Processes in Python" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "by Stuart Reid (www.stuartreid.co.za)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more information about these stochastic and their applications in Quantitative Finance please check out my blog post, Random Walks Down Wall Street, Stochastic Processes in Python. This notebook contains the code presented in the article for four stochastic processes often used to model the evolution of asset prices and two mean-reverting stochastic processes often used to model the evolution of interest rates. Thes models include Brownian Motion (a Wiener Process), Geometric Brownian Motion, the Merton Jump Diffusion Model, the Heston Stochastic Volatility Model, the Cox Ingersoll Ross (CIR) process, and the Ornstein Uhlenbeck Model.\n", "\n", "A random event is any event which has a chance of happening. Probability is the measure of that chance. Random variables are functions which receive a random event and return a real number. Random variables may be discrete or continuous; discrete random variables are ones with a countable number of possible outcomes; continuous random variables are ones which have an infinite number of possible outcomes. In the context of finance, a stochastic process is a collection of random variables which describe the evolution of a system over some period of time.\n", "\n", "The beauty of random variables and stochastic processes is that they can be used to describe what is happening in the world around us. Often this is done by simulating multiple outcomes from a stochastic process in a Monte Carlo simulation. Example applications include the simulation of gambling games (Poker and Blackjack for sure), fluid and particle dynamics (which is often used in computer graphics for animations), in genetics to determine the likelihood of phylogenetic trees (how species relate), and even the evolution of stock prices and interest rates over time." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Initial Setup" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The initial setup involves importing some very helpful Python packages which we can use to generate and analyze random numbers, creating a model parameters class for encapsulating the parameter values for the stochastic processes, and some useful helper methods for working with log returns or normal returns" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import math\n", "import numpy\n", "import random\n", "import decimal\n", "import scipy.linalg\n", "import numpy.random as nrand\n", "import matplotlib.pyplot as plt" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "heading", "level": 5, "metadata": {}, "source": [ "The model parameters class" ] }, { "cell_type": "code", "collapsed": false, "input": [ "class ModelParameters:\n", " \"\"\"\n", " Encapsulates model parameters\n", " \"\"\"\n", "\n", " def __init__(self,\n", " all_s0, all_time, all_delta, all_sigma, gbm_mu,\n", " jumps_lamda=0.0, jumps_sigma=0.0, jumps_mu=0.0,\n", " cir_a=0.0, cir_mu=0.0, all_r0=0.0, cir_rho=0.0,\n", " ou_a=0.0, ou_mu=0.0,\n", " heston_a=0.0, heston_mu=0.0, heston_vol0=0.0):\n", " # This is the starting asset value\n", " self.all_s0 = all_s0\n", " # This is the amount of time to simulate for\n", " self.all_time = all_time\n", " # This is the delta, the rate of time e.g. 1/252 = daily, 1/12 = monthly\n", " self.all_delta = all_delta\n", " # This is the volatility of the stochastic processes\n", " self.all_sigma = all_sigma\n", " # This is the annual drift factor for geometric brownian motion\n", " self.gbm_mu = gbm_mu\n", " # This is the probability of a jump happening at each point in time\n", " self.lamda = jumps_lamda\n", " # This is the volatility of the jump size\n", " self.jumps_sigma = jumps_sigma\n", " # This is the average jump size\n", " self.jumps_mu = jumps_mu\n", " # This is the rate of mean reversion for Cox Ingersoll Ross\n", " self.cir_a = cir_a\n", " # This is the long run average interest rate for Cox Ingersoll Ross\n", " self.cir_mu = cir_mu\n", " # This is the starting interest rate value\n", " self.all_r0 = all_r0\n", " # This is the correlation between the wiener processes of the Heston model\n", " self.cir_rho = cir_rho\n", " # This is the rate of mean reversion for Ornstein Uhlenbeck\n", " self.ou_a = ou_a\n", " # This is the long run average interest rate for Ornstein Uhlenbeck\n", " self.ou_mu = ou_mu\n", " # This is the rate of mean reversion for volatility in the Heston model\n", " self.heston_a = heston_a\n", " # This is the long run average volatility for the Heston model\n", " self.heston_mu = heston_mu\n", " # This is the starting volatility value for the Heston model\n", " self.heston_vol0 = heston_vol0\n" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "heading", "level": 5, "metadata": {}, "source": [ "Example Usage" ] }, { "cell_type": "code", "collapsed": false, "input": [ "mp = ModelParameters(all_s0=1000,\n", " all_r0=0.5,\n", " all_time=800,\n", " all_delta=0.00396825396,\n", " all_sigma=0.125,\n", " gbm_mu=0.058,\n", " jumps_lamda=0.00125,\n", " jumps_sigma=0.001,\n", " jumps_mu=-0.2,\n", " cir_a=3.0,\n", " cir_mu=0.5,\n", " cir_rho=0.5,\n", " ou_a=3.0,\n", " ou_mu=0.5,\n", " heston_a=0.25,\n", " heston_mu=0.35,\n", " heston_vol0=0.06125)\n", "\n", "paths = 15" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 5 }, { "cell_type": "heading", "level": 5, "metadata": {}, "source": [ "A plotting helper class" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def plot_stochastic_processes(processes, title):\n", " \"\"\"\n", " This method plots a list of stochastic processes with a specified title\n", " :return: plots the graph of the two\n", " \"\"\"\n", " plt.style.use(['bmh'])\n", " fig, ax = plt.subplots(1)\n", " fig.suptitle(title, fontsize=16)\n", " ax.set_xlabel('Time, t')\n", " ax.set_ylabel('Simulated Asset Price')\n", " x_axis = numpy.arange(0, len(processes[0]), 1)\n", " for i in range(len(processes)):\n", " plt.plot(x_axis, processes[i])\n", " plt.show()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 }, { "cell_type": "heading", "level": 5, "metadata": {}, "source": [ "Two helper classes for working with returns" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def convert_to_returns(log_returns):\n", " \"\"\"\n", " This method exponentiates a sequence of log returns to get daily returns.\n", " :param log_returns: the log returns to exponentiated\n", " :return: the exponentiated returns\n", " \"\"\"\n", " return numpy.exp(log_returns)\n", "\n", "\n", "def convert_to_prices(param, log_returns):\n", " \"\"\"\n", " This method converts a sequence of log returns into normal returns (exponentiation) and then computes a price\n", " sequence given a starting price, param.all_s0.\n", " :param param: the model parameters object\n", " :param log_returns: the log returns to exponentiated\n", " :return:\n", " \"\"\"\n", " returns = convert_to_returns(log_returns)\n", " # A sequence of prices starting with param.all_s0\n", " price_sequence = [param.all_s0]\n", " for i in range(1, len(returns)):\n", " # Add the price at t-1 * return at t\n", " price_sequence.append(price_sequence[i - 1] * returns[i - 1])\n", " return numpy.array(price_sequence)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 7 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Brownian Motion" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Brownian motion is the random motion exhibited by particles which have been suspended in a gas or liquid. This random motion is caused by the collision of the particles with the atoms or molecules in the liquid or gas. Brownian Motion is named after the Botanist Robert Brown who observed the random movements in 1827. The relationship between Brownian Motion and financial markets dates back to a paper written many years later, in 1900, by Louis Bachelier entitled The Theory of Speculation. His paper was the first to propose the use of Brownian Motion to evaluate stock options. The paper did not surface until later works in deriving the famous Black Scholes options pricing formula developed by Fisher Black and Myron Scholes in 1973. In the context of stochastic processes used in finance, Brownian Motion is often described as a Wiener process, denoted by $W_t$. A Wiener process is described by the following properties,\n", "\n", "