Chapter 9 — Equity Markets and Instruments
"In the short run, the market is a voting machine. In the long run, it is a weighing machine." — Benjamin Graham
After this chapter you will be able to:
- Explain how limit order books work and identify the five primary order types
- Compute arithmetic and log returns, and explain why log returns are preferred for quantitative analysis
- Adjust historical price series for splits and dividends to produce a total return index
- Price equity forwards using the cost-of-carry relationship and explain the no-arbitrage argument
- Estimate GARCH(1,1) parameters and compute conditional volatility forecasts
- Understand why equity implied volatility has a negative skew (the leverage effect and crash risk premium)
On 17 May 1792, 24 stockbrokers gathered under a buttonwood tree on Wall Street and signed an agreement to trade securities among themselves at fixed commissions. The New York Stock Exchange grew from that meeting, and today that same real estate hosts a market that trades over $20 billion in equities every day. The mechanism has changed — floor brokers have been replaced by matching engines processing millions of orders per second — but the purpose remains: to provide a continuous, transparent price for the fractional ownership of businesses.
Equities are not just assets to own; they are the raw material of derivatives. The price of every stock option, every equity-linked note, every variance swap depends on the statistical properties of the underlying equity return. Understanding how returns are distributed, how they deviate from Gaussian in their tails, how volatility clusters, and how traded prices relate to fundamental value is the prerequisite for everything in Part III. The most important empirical finding — that log returns are approximately Gaussian in the centre of the distribution but have far fatter tails than Gaussian in the extremes — was demonstrated dramatically on Monday 19 October 1987, when the Dow Jones Industrial Average fell 22.6% in a single session. Under Gaussian assumptions, this was a 20-standard-deviation event with a probability of roughly $10^{-88}$. In practice, it just needs a global panic.
This chapter builds the technical vocabulary and computational tools for equity instruments: price quotes, return calculations, corporate actions (dividends and splits), equity forward pricing via cost of carry, and the empirical return distribution. We end with a Total Return Swap implementation — a financial contract that will appear again in Chapter 15 when we discuss synthetic credit exposure.
9.1 Stock Markets Overview
Equity markets allow companies to raise capital and investors to own fractional stakes in businesses. The price of a share reflects market participants' collective assessment of the discounted future cash flows.
Key market participants:
- Market makers: quote bid/ask spreads, provide liquidity
- Institutional investors: pension funds, mutual funds, insurance companies
- Hedge funds: active trading, short selling, leverage
- Retail investors: direct ownership, ETFs, mutual funds
- Algorithmic traders: high-frequency trading, statistical arbitrage
9.1.1 Market Structure and Order Books
The mechanical heart of any equity market is the limit order book (LOB). Every share that changes hands was once an order sitting in a book, waiting to be matched against an opposite-side order. Understanding the order book's structure is prerequisite to understanding execution, market microstructure, and the liquidity properties that underpin options pricing and volatility estimation.
A limit order specifies a price at which the sender is willing to buy (bid) or sell (ask). Orders queue in the book sorted by price-time priority: the best bid (highest willingness to buy) and best ask (lowest willingness to sell) define the inside market. The difference between them is the bid-ask spread — the primary compensation for providing liquidity. A market order consumes whatever sits at the top of the book immediately, at the prevailing best price — or multiple price levels if the order is large enough to walk the book.
Five order types dominate modern electronic markets:
- Limit order: rest in the book at specified price until filled or cancelled
- Market order: fill immediately at the best available price; no price guarantee
- IOC (Immediate or Cancel): fill what can be matched instantly, cancel the remainder
- FOK (Fill or Kill): fill the full quantity at once or cancel entirely (used for block trades)
- Stop order: becomes a market order when the price crosses a trigger level
The bid-ask spread compensates market makers for two costs. Inventory risk is the exposure the market maker accepts between buying and selling: they must hold a position temporarily and the price may move against them. Adverse selection risk is the cost of trading with a counterparty who knows something the market maker does not (an informed trader). These two components were formalised by Glosten-Milgrom (1985) and Kyle (1985), which we develop formally in Chapter 22. Empirically, the spread is wider for less liquid stocks (harder to unwind inventory), smaller companies (more likely to have informed insiders), and around earnings announcements (information asymmetry peaks). The spread on a large-cap liquid stock like Apple is typically 1–2 basis points; on a small-cap it can be 50–200 basis points.
For a quantitative practitioner, the bid-ask spread is not merely a transaction cost — it is a measure of market quality. Strategies that require high-frequency rebalancing must generate gross alpha large enough to overcome the spread on every round trip. A strategy that turns over its entire portfolio daily at a 10bp spread needs to earn 10bp per day before it is profitable — approximately 25% per year in gross alpha, before any other costs.
(** A stock price quote *)
type quote = {
ticker : string;
bid : float;
ask : float;
last : float;
volume : int;
timestamp : int64; (* nanoseconds since epoch *)
}
(** Bid-ask spread in basis points *)
let spread_bps { bid; ask; last; _ } =
(ask -. bid) /. last *. 10_000.0
(** Mid price *)
let mid { bid; ask; _ } = (bid +. ask) /. 2.0
(** Market capitalisation *)
let market_cap ~price ~shares_outstanding = price *. float_of_int shares_outstanding
9.1.2 Equity Indices
An equity index aggregates the prices of a basket of stocks. Key weighting methods:
- Market-cap weighted (S&P 500, MSCI): larger companies dominate
- Price-weighted (DJIA): higher-priced stocks dominate
- Equal-weighted: each stock has equal weight
type index_constituent = {
ticker : string;
weight : float; (* normalised weight, sums to 1.0 *)
price : float;
shares : int; (* shares in index *)
}
let index_level constituents =
List.fold_left (fun acc { weight; price; _ } -> acc +. weight *. price) 0.0 constituents
let index_return_1d ~old_level ~new_level = (new_level -. old_level) /. old_level
9.2 Returns: Arithmetic vs Log Returns
Returns are the fundamental unit of analysis in equity finance.
9.2.1 Definitions
Arithmetic (simple) return:
$$R_t = \frac{P_t - P_{t-1}}{P_{t-1}} = \frac{P_t}{P_{t-1}} - 1$$
Log (continuously compounded) return:
$$r_t = \ln\frac{P_t}{P_{t-1}} = \ln P_t - \ln P_{t-1}$$
The relationship:
$$R_t = e^{r_t} - 1 \approx r_t + \frac{r_t^2}{2} \quad \text{for small } r_t$$
9.2.2 Why Log Returns?
- Temporal aggregation: multi-period log return = sum of single-period log returns $$r_{t,t+k} = r_t + r_{t+1} + \cdots + r_{t+k-1}$$
- Normal distribution: log returns are approximately normal (prices lognormal)
- No negative prices: $P_t = P_0 \cdot e^{\sum r_i} > 0$ always
let arithmetic_returns prices =
let n = Array.length prices in
Array.init (n - 1) (fun i ->
(prices.(i + 1) -. prices.(i)) /. prices.(i)
)
let log_returns prices =
let n = Array.length prices in
Array.init (n - 1) (fun i ->
log (prices.(i + 1) /. prices.(i))
)
let geometric_mean returns =
let n = Array.length returns in
let sum_log = Array.fold_left (fun a r -> a +. log (1.0 +. r)) 0.0 returns in
exp (sum_log /. float_of_int n) -. 1.0
(** Annualise returns and volatility *)
let annualise_stats ~daily_returns ~trading_days_per_year =
let n = float_of_int (Array.length daily_returns) in
let mean = Array.fold_left (+.) 0.0 daily_returns /. n in
let var = Array.fold_left (fun a r -> a +. (r -. mean) *. (r -. mean))
0.0 daily_returns /. (n -. 1.0) in
let ann_ret = mean *. float_of_int trading_days_per_year in
let ann_vol = sqrt (var *. float_of_int trading_days_per_year) in
let sharpe = ann_ret /. ann_vol in
(ann_ret, ann_vol, sharpe)
9.3 Dividends, Splits, and Corporate Actions
9.3.1 Dividend Adjustment
When a stock pays a dividend, its price drops by approximately the dividend amount on the ex-dividend date. Total return indices reinvest dividends.
type corporate_action =
| Dividend of { amount : float; ex_date : string }
| Split of { ratio : float; date : string } (* 2:1 split: ratio=2 *)
| Spinoff of { fraction : float; date : string }
(** Adjust historical price series for splits and dividends.
Returns total return index (dividends reinvested). *)
let adjust_prices prices actions =
let n = Array.length prices in
let adjusted = Array.copy prices in
let cumulative_factor = ref 1.0 in
List.iter (fun action ->
match action with
| Split { ratio; _ } ->
(* All historical prices divided by ratio to maintain continuity *)
let adj = 1.0 /. ratio in
cumulative_factor := !cumulative_factor *. adj;
Array.iteri (fun i p -> adjusted.(i) <- p *. adj) adjusted
| Dividend { amount; _ } ->
(* Adjustment factor: (P - div) / P applied to all earlier prices *)
let last = adjusted.(n - 1) in
let adj = (last -. amount) /. last in
cumulative_factor := !cumulative_factor *. adj;
Array.iteri (fun i p -> adjusted.(i) <- p *. adj) adjusted
| Spinoff _ -> () (* simplified: ignore spinoff *)
) actions;
(adjusted, !cumulative_factor)
9.4 Equity Forwards and Futures
9.4.1 Equity Forward Price
The forward price of a stock paying discrete dividends:
$$F(t, T) = (S - PV_{\text{dividends}}(t, T)) \cdot e^{r(T-t)}$$
For a continuous dividend yield $q$:
$$F(t, T) = S \cdot e^{(r - q)(T-t)}$$
(** Forward price with continuous dividend yield *)
let forward_price ~spot ~rate ~div_yield ~tau =
spot *. exp ((rate -. div_yield) *. tau)
(** Forward price with discrete dividends *)
let forward_price_discrete ~spot ~rate ~tau ~dividends =
let pv_divs = List.fold_left (fun acc (t_div, div) ->
if t_div > tau then acc
else acc +. div *. exp (-. rate *. t_div)
) 0.0 dividends in
(spot -. pv_divs) *. exp (rate *. tau)
(** Implied dividend yield from forward price *)
let implied_div_yield ~spot ~forward ~rate ~tau =
rate -. log (forward /. spot) /. tau
(** Fair value of futures vs spot (basis) *)
let futures_fair_value ~spot ~rate ~div_yield ~tau ~financing_cost =
spot *. exp ((rate +. financing_cost -. div_yield) *. tau)
let basis ~futures_price ~fair_value = futures_price -. fair_value
9.5 Statistical Properties of Equity Returns
9.5.1 Fat Tails
Empirical equity returns have excess kurtosis (fatter tails than the normal distribution). The probability of extreme daily moves is far higher than a Gaussian model predicts.
(** Empirical distribution analysis *)
let return_statistics returns =
let n = float_of_int (Array.length returns) in
let (`Mean mu, `Variance var, `Std std, `Skewness skew, `Excess_kurtosis kurt) =
moments returns in
let max_loss = Array.fold_left Float.min infinity returns in
let max_gain = Array.fold_left Float.max neg_infinity returns in
let sortino = let downside = Array.fold_left (fun a r ->
if r < 0.0 then a +. r *. r else a) 0.0 returns /. n in
mu /. sqrt downside in
Printf.printf "Mean: %.4f%%\n" (mu *. 100.0);
Printf.printf "Std: %.4f%%\n" (std *. 100.0);
Printf.printf "Skewness: %.4f\n" skew;
Printf.printf "Kurtosis: %.4f\n" kurt;
Printf.printf "Max loss: %.4f%%\n" (max_loss *. 100.0);
Printf.printf "Max gain: %.4f%%\n" (max_gain *. 100.0);
Printf.printf "Sortino: %.4f\n" sortino;
ignore var
9.5.2 Volatility Clustering
Financial returns exhibit volatility clustering: large moves are followed by large moves. This is modelled by GARCH processes.
(**
GARCH(1,1) model:
σ²_t = ω + α · r²_{t-1} + β · σ²_{t-1}
Constraints: ω > 0, α,β ≥ 0, α + β < 1 (stationarity)
*)
type garch_params = {
omega : float; (* long-run variance * (1 - alpha - beta) *)
alpha : float; (* weight on last shock *)
beta : float; (* weight on last variance *)
}
let garch_long_run_vol { omega; alpha; beta } =
sqrt (omega /. (1.0 -. alpha -. beta))
(** Filter GARCH(1,1) variances given returns and parameters *)
let garch_filter { omega; alpha; beta } returns =
let n = Array.length returns in
let variances = Array.make n 0.0 in
let long_run_var = omega /. (1.0 -. alpha -. beta) in
variances.(0) <- long_run_var; (* initialise at long-run variance *)
for t = 1 to n - 1 do
let r_prev = returns.(t - 1) in
variances.(t) <- omega
+. alpha *. r_prev *. r_prev
+. beta *. variances.(t - 1)
done;
variances
(** Forecast variance h steps ahead *)
let garch_forecast params ~current_var ~h_steps =
let persistence = params.alpha +. params.beta in
let long_run = garch_long_run_vol params ** 2.0 in
long_run +. (current_var -. long_run) *. persistence ** float_of_int h_steps
9.6 Total Return Swaps
A total return swap (TRS) transfers the total economic exposure of an asset without owning it. The total return receiver gets dividends and capital gains; the total return payer gets a fixed or floating rate.
type total_return_swap = {
notional : float;
reference : string; (* underlying asset ticker *)
rate : float; (* financing rate paid by receiver *)
tenor : float; (* years *)
is_receiver : bool; (* receiving total return? *)
}
(**
TRS value at inception = 0 (by construction).
Mid-life value = change in asset value + accrued dividends - accrued financing.
*)
let trs_npv { notional; rate; tenor; is_receiver; _ }
~initial_price ~current_price ~accrued_divs ~elapsed =
let capital_gain = notional *. (current_price -. initial_price) /. initial_price in
let div_income = notional *. accrued_divs in
let financing = notional *. rate *. elapsed in
let total_return_pv = capital_gain +. div_income in
let sign = if is_receiver then 1.0 else -. 1.0 in
sign *. (total_return_pv -. financing)
|> fun pv -> pv *. exp (-. rate *. (tenor -. elapsed)) (* discount residual *)
9.7 Chapter Summary
Equity markets are the most visible part of the financial system — stock prices are reported in the news daily — but the statistical properties underlying those prices require careful attention to model correctly. The central practical issue is the distribution of returns.
The chapter summary would be incomplete without addressing the volatility smile — the empirical observation that out-of-the-money equity options have higher implied volatility than at-the-money options. This is the signature of a market that prices left-tail risk explicitly. When calibrating Black-Scholes to a stock option, the implied volatility is not constant across strikes: OTM puts are expensive (high implied vol) because they provide insurance against crashes, while OTM calls are cheaper relative to theoretical. The shape is called a skew for single equities (monotonically declining implied vol as strike increases) and a smile for FX and some index products (U-shaped implied vol). Understanding this skew is the primary motivation for stochastic volatility models in Chapter 13. Black-Scholes, which assumes a flat vol surface, systematically misprices vanilla puts and calls at strikes away from the money.
Log returns are theoretically and computationally preferable to arithmetic returns for almost all purposes: they aggregate additively over time, they place a natural lower bound at $-100%$ (prices cannot go below zero), and they transform geometric Brownian motion into a simple additive random walk. However, even daily log returns have approximately 1.5 to 3 times more kurtosis than Gaussian, and equity return skewness is reliably negative — the left tail (crashes) is fatter than the right tail (rallies). This matters for options pricing: out-of-the-money puts are expensive precisely because the market prices this asymmetry. Black-Scholes, which assumes Gaussian log returns, consistently underprices left-tail protection.
The cost-of-carry forward pricing relationship $F = S e^{(r-q)T}$ is one of the cleanest arbitrage relationships in finance. If futures traded above fair value, a trader would sell the futures, buy the stock, and earn the risk-free rate on the dividend-adjusted position. The relationship holds in liquid markets within the width of transaction costs. Dividends require careful treatment in the discrete setting: the stock price drops by the dividend amount on the ex-date, creating a step in any time series that must be removed before computing returns or calibrating volatility.
GARCH and the empirical volatility tools developed here are used again in Chapter 13 (Volatility), where they are extended to the full implied volatility surface and professional calibration approaches.
Exercises
9.1 Download 3 years of daily AAPL data. Compute daily log returns, annualised return, Sharpe ratio, skewness, and excess kurtosis. Are returns normally distributed (use Jarque-Bera)?
9.2 Implement split-adjusted and dividend-adjusted price series. Given raw prices and a list of corporate actions, compute the total return index.
9.3 Calibrate GARCH(1,1) to S&P 500 daily returns using maximum likelihood. Plot conditional volatility vs 21-day rolling realised vol. What is the long-run vol?
9.4 Compute the fair value of a 3-month S&P 500 futures contract assuming: spot = 5200, r = 5%, q = 1.5%. If futures trade at 5210, is there an arbitrage? How would you exploit it?