A stochastic process is a sequence of random variables indexed by time. Finance models asset prices as stochastic processes because tomorrow's price depends on today's, plus noise you can't predict.
Random walks and their properties
A random walk starts at zero and at each step moves up or down by one with equal probability. After n steps the expected position is 0, but the expected distance from the origin grows as √n. This square-root scaling is the heartbeat of finance: volatility grows with the square root of time.
A Markov chain is memoryless: the next state depends only on the current state, not the history. A transition matrix P has entry P(i,j) = probability of moving from state i to state j. Multiply the matrix by itself n times to get n-step transition probabilities.
import numpy as np
# Bull/Bear transition matrix
P = np.array([[0.9, 0.1],
[0.3, 0.7]])
P2 = P @ P
print("P^2 =")
print(P2)
# Stationary distribution via eigenvalue
eigenvalues, eigenvectors = np.linalg.eig(P.T)
# Find eigenvector for eigenvalue 1
idx = np.argmin(np.abs(eigenvalues - 1))
pi = eigenvectors[:, idx].real
pi = pi / pi.sum()
print(f"Stationary distribution: {pi}")
Brownian motion as limit of random walks
Brownian motion B(t) is what you get when you take a random walk, shrink the step size, speed up the steps, and take the limit. Formally: scale n steps of size 1/√n over time [0,1]. The central limit theorem guarantees the limit is Gaussian. B(t) has independent increments, B(t) - B(s) ~ N(0, t-s), and continuous but nowhere-differentiable paths.
Scheme
; Brownian motion: variance grows linearly with time; B(t) - B(s) ~ N(0, t - s); So Var[B(t)] = t; Simulate scaled random walk approaching Brownian motion
(define (scaled-walk n seed)
; n steps, each of size 1/sqrt(n)
(define step-size (/ 1.0 (sqrt n)))
(define (walk k s pos)
(if (= k 0) pos
(let* ((new-s (modulo (+ (* 1103515245 s) 12345) (expt 231)))
(direction (if (= (modulo new-s 2) 0) 1-1)))
(walk (- k 1) new-s (+ pos (* direction step-size))))))
(walk n seed 0))
; More steps => final position has variance closer to 1
(display "n=10: final = ") (display (scaled-walk 1042)) (newline)
(display "n=100: final = ") (display (scaled-walk 10042)) (newline)
(display "n=1000: final = ") (display (scaled-walk 100042)) (newline)
(display "Theory: Var[B(1)] = 1")
Python
import random
importmath
random.seed(42)
def scaled_random_walk(n):
"""n-step random walk scaled to approximate B(1)"""
step_size = 1.0 / math.sqrt(n)
position = 0for _ inrange(n):
position += random.choice([1, -1]) * step_size
return position
for n in [10, 100, 1000, 10000]:
print(f"n={n:>5}: B(1) โ {scaled_random_walk(n):+.4f}")
print("Theory: Var[B(1)] = 1")
Martingales — fair games
A martingale is a stochastic process whose expected future value, given all past information, equals its current value: E[X(t+1) | history] = X(t). A symmetric random walk is a martingale. A stock price under the risk-neutral measure is a (discounted) martingale. This is the mathematical formalization of "you can't beat a fair game."
Scheme
; Martingale property: E[X(t+1) | X(t)] = X(t); For a symmetric random walk, each step has E = 0; Verify: average of many final positions โ starting position
(define (walk-final steps seed)
(if (= steps 0) 0
(let* ((new-seed (modulo (+ (* 1103515245 seed) 12345) (expt 231)))
(step (if (= (modulo new-seed 2) 0) 1-1)))
(+ step (walk-final (- steps 1) new-seed)))))
; Run 8 walks with different seeds, average their endpoints
(define endpoints
(map (lambda (s) (walk-final 20 (* s 7919)))
(list 12345678)))
(display "Endpoints: ") (display endpoints) (newline)
(define avg (/ (apply + endpoints) (length endpoints)))
(display "Average final position: ") (display avg) (newline)
(display "Martingale prediction: 0")
Python
import random
def simulate_walks(n_walks, steps):
endpoints = []
for i inrange(n_walks):
random.seed(i * 7919)
pos = 0for _ inrange(steps):
pos += random.choice([1, -1])
endpoints.append(pos)
return endpoints
endpoints = simulate_walks(1000, 50)
avg = sum(endpoints) / len(endpoints)
print(f"Average of {len(endpoints)} walk endpoints: {avg:.3f}")
print("Martingale prediction: 0")
print(f"Std dev: {(sum((x-avg)**2 for x in endpoints)/len(endpoints))**0.5:.2f}")
print(f"Theory std dev: {50**0.5:.2f}")