Algorithmic & Quant Trading
Chapter: 6.1 Algorithmic & Quant Trading Time limit: 90 minutes Total marks: 60 Instructions: Answer ALL three questions. Show derivations, proofs and pseudocode/code where asked. Use / for mathematics.
Question 1 — Pairs Trading, Cointegration & Mean-Reversion (24 marks)
You are researching a pair of stocks and with log-prices .
(a) Define the hedge ratio via the regression . Explain precisely why cointegration (rather than mere correlation) is the correct statistical condition for a tradeable pair, and state what property the spread must have. (4 marks)
(b) Assume the spread follows an Ornstein–Uhlenbeck (mean-reverting) process Derive the expression for the expected value and show that the half-life of mean reversion is (6 marks)
(c) In discrete time the OU process is estimated by the AR(1) regression . Given an estimated on daily data, compute the half-life in trading days (numeric). State the relationship between and used. (4 marks)
(d) Design a complete signal-generation rule set for this pair using the z-score . Specify entry, exit and stop-loss rules, and prove that under the pure OU model (no stop) the strategy's expected holding period is bounded. Discuss ONE reason a fixed can be dangerous in live trading. (10 marks)
Question 2 — Momentum Strategy, Backtest Statistics & Overfitting (22 marks)
(a) A cross-sectional momentum strategy ranks assets by their trailing 12-month return (skipping the most recent month) and goes long the top decile, short the bottom decile. Explain the "skip-a-month" convention and give the microstructure/behavioural justification. (4 marks)
(b) A backtest of a single strategy configuration produces daily returns with mean , standard deviation . Compute the annualised Sharpe ratio (252 trading days, risk-free = 0). Show the formula and the number. (4 marks)
(c) A researcher tries independent strategy variants on the same data and reports only the best one. Assuming each variant's Sharpe estimate is under the null of no skill, derive the expected maximum Sharpe (use the approximation ) and compute it numerically. Explain what this proves about the reported result and name the phenomenon. (6 marks)
(d) Define deflated Sharpe ratio conceptually and explain how walk-forward analysis and a proper train/validation/test split reduce curve-fitting. Then write pseudocode for a walk-forward optimisation loop over folds that reports out-of-sample performance only. (8 marks)
Question 3 — Building a Trading System & ML Caution (14 marks)
(a) Draw (as a labelled block diagram in text/ASCII) the components of a complete algorithmic trading system, from data ingestion to execution and risk management. Briefly state the role of each block. (6 marks)
(b) A team fits a random-forest classifier to predict next-day up/down using 300 features on 500 days of data and reports 82% in-sample accuracy. Give THREE distinct, technically-specific reasons this result is untrustworthy, and for each give one concrete mitigation. (5 marks)
(c) Explain why "look-ahead bias" and "survivorship bias" in the dataset can silently inflate ML backtest results even when the model code is correct. (3 marks)
Answer keyMark scheme & solutions
Question 1
(a) [4 marks]
- = OLS slope of on ; it is the number of units of to short per unit of long so the combined position is dollar/price neutral in the common factor. (1)
- Correlation measures co-movement of returns/changes but two random walks can be highly correlated yet drift apart without bound. (1)
- Cointegration means a linear combination of two (unit-root) series is (stationary) — the spread does not wander off, it reverts. This is the property required for a bounded, tradeable spread. (1)
- The spread must be stationary (mean-reverting, ) — constant mean & variance, so deviations are temporary. (1)
(b) [6 marks] Solve the OU SDE. Consider : (2) Integrate : Taking expectation kills the Itô integral term (mean 0): (1) (1) Half-life = time for deviation to halve: (2)
(c) [4 marks]
- Discrete AR(1): so (with day). (1)
- . (1)
- , . (1)
- trading days. (1)
(d) [10 marks] Rule set (award up to 5):
- Entry: short spread when (e.g. ): sell , buy of . Long spread when . (2)
- Exit: close when reverts toward 0 (e.g. or crosses mean). (1)
- Stop-loss: exit if (e.g. ) or if cointegration test fails / holding time > cap. (2)
Boundedness of expected holding period (up to 3):
- The spread process is a positive-recurrent OU/AR(1) with ; a stationary ergodic mean-reverting process visits every neighbourhood of the mean in finite expected time. (1)
- Formally the expected first-passage (hitting) time from level to the exit band is finite because the OU process has a proper stationary distribution and drift pushes it toward 0; hence . (2)
Fixed- danger (up to 2):
- The cointegrating relationship / hedge ratio is not constant — regime changes, corporate actions, changing fundamentals cause to drift, so the "spread" stops being stationary and the position accumulates unbounded loss. Mitigation: rolling/Kalman-filtered and periodic re-testing of cointegration. (2)
Question 2
(a) [4 marks]
- Rank on months to , skip month before forming the portfolio held in . (2)
- Justification: the most recent month exhibits short-term reversal (bid-ask bounce, liquidity/microstructure effects, one-month mean reversion); including it contaminates the momentum signal. Skipping isolates the persistent intermediate-horizon momentum. (2)
(b) [4 marks] (2) (2)
(c) [6 marks]
- Under the null each of trials has SR ; picking the best is an extreme-value (maximum) selection. (1)
- . (1)
- , , . (2)
- So even with zero true skill, the best of 200 tries has expected Sharpe ≈ 3.26 — an impressive-looking number that is pure selection artefact. The reported best is not evidence of skill. (1) Phenomenon: multiple-testing / data-snooping bias (backtest overfitting, selection bias). (1)
(d) [8 marks]
- Deflated Sharpe ratio (DSR): adjusts the observed Sharpe by (i) the number of trials , (ii) skew/kurtosis of returns and (iii) sample length, giving the probability the true Sharpe exceeds 0 after accounting for multiple testing — it "deflates" the naive SR toward the selection-corrected benchmark. (2)
- WFA / splits: parameters are tuned only on training/validation windows; the test window is never seen during optimisation, so reported performance is genuinely out-of-sample and reflects the model's ability to generalise, not memorise. Rolling windows also detect non-stationarity. (2)
Pseudocode (up to 4):
data sorted by time; define K folds by time
oos_results = []
for k in 1..K:
train = data[fold_start(k) : fold_train_end(k)] # in-sample
test = data[fold_train_end(k) : fold_test_end(k)] # unseen, later in time
best_params = None; best_score = -inf
for params in param_grid:
score = backtest(strategy, train, params) # optimise on TRAIN only
if score > best_score:
best_score, best_params = score, params
oos = backtest(strategy, test, best_params) # evaluate on TEST only
oos_results.append(oos)
report( aggregate(oos_results) ) # report ONLY out-of-sample metrics
Marks: correct time-ordered no-shuffle split (1), optimise on train only (1), evaluate fixed params on future test (1), report only OOS (1).
Question 3
(a) [6 marks] — 1 mark per block correctly named + role (max 6):
[Market Data Feed] -> [Data Cleaning/Storage] -> [Signal/Alpha Model]
-> [Portfolio Construction/Sizing] -> [Risk Management]
-> [Execution/Order Router] -> [Broker/Exchange]
^ |
|__________ [Monitoring / P&L / Logging] <--
- Data feed: ingest real-time & historical prices/fundamentals.
- Cleaning/storage: handle missing data, adjustments, survivorship-free DB.
- Signal/alpha model: generate trading signals from strategy logic.
- Portfolio construction/sizing: convert signals to target positions, apply capital allocation.
- Risk management: limits, exposure, stop-losses, drawdown control.
- Execution/router: slice & send orders, minimise slippage/impact.
- Monitoring/logging: track live vs expected performance, alerts.
(b) [5 marks] — any three, 1 mark reason + shared mark for mitigation (max 5):
- Curse of dimensionality / overfitting: 300 features vs 500 samples → model memorises noise. Mitigation: feature selection / regularisation / fewer features, more data.
- In-sample evaluation: 82% is on training data; no honest estimate of generalisation. Mitigation: purged/embargoed cross-validation or walk-forward OOS test.
- Serial correlation / non-IID data: standard CV leaks temporal info; financial data is non-stationary with autocorrelation. Mitigation: time-series CV, purge & embargo.
- Low signal-to-noise: market returns are ~random; 82% accuracy on direction is implausibly high → data leakage suspected. Mitigation: audit features for look-ahead. (Award 5 for three sound reason+mitigation pairs.)
(c) [3 marks]
- Look-ahead bias: using data not available at decision time (e.g. same-day close to trade at that close, restated fundamentals) inflates accuracy because the model effectively "sees the future." (1.5)
- Survivorship bias: dataset contains only firms that survived; delisted/bankrupt names removed, so backtest overstates returns and understates risk — the model is trained on a rosier universe than reality. (1.5)
- Both operate through the data, so even bug-free model code produces optimistic, non-reproducible live results.
[
{"claim":"OU half-life for AR(1) b=0.94 is ~11.2 days","code":"from sympy import log, N; b=0.94; H=log(2)/(-log(b)); result = abs(N(H)-11.2)<0.1"},
{"claim":"Annualised Sharpe = 0.0006/0.011*sqrt(252) ~ 0.866","code":"from sympy import sqrt, N; SR=(0.0006/0.011)*sqrt(252); result = abs(N(SR)-0.866)<0.01"},
{"claim":"Expected max Sharpe over 200 trials ~ 3.26","code":"from sympy import log, sqrt, N; e=sqrt(2*log(200)); result = abs(N(e)-3.255)<0.01"},
{"claim":"Half-life formula: e^(-theta*H)=1/2 gives H=ln2/theta","code":"from sympy import symbols, Eq, solve, log, exp; theta,H=symbols('theta H',positive=True); sol=solve(Eq(exp(-theta*H),0.5),H)[0]; result = sol.equals(log(2)/theta)"}
]