Level 3 — ProductionAlgorithmic & Quant Trading

Algorithmic & Quant Trading

45 minutes60 marksprintable — key stays hidden on paper

Level: 3 — Production (from-scratch derivations, code-from-memory, explain-out-loud) Time Limit: 45 minutes Total Marks: 60


Question 1 — Trading System Architecture (10 marks)

An algorithmic trading system moves an idea from research into live capital.

(a) From memory, draw/list the core components of an end-to-end trading system in the order data flows through them. For each component write one line on its responsibility. (6 marks)

(b) Explain out loud (in writing) why the execution/order-management layer is kept separate from the signal-generation layer. Give two concrete failure modes prevented by this separation. (4 marks)


Question 2 — Pairs Trading & Cointegration (14 marks)

You are researching a pair of stocks AA and BB with log-prices pAp_A and pBp_B.

(a) Derive from scratch the spread used in a cointegration-based pairs trade. Define the hedge ratio β\beta and state the regression you run to estimate it. (4 marks)

(b) State the difference between correlation and cointegration, and explain why cointegration is the correct property for a mean-reverting pairs trade. (3 marks)

(c) Given the spread st=pA,tβpB,ts_t = p_{A,t} - \beta\, p_{B,t} with estimated mean μ=0\mu = 0 and standard deviation σ=0.04\sigma = 0.04, you use entry threshold z=±2z = \pm 2 and exit at z=0z = 0. Compute the entry spread levels and state the trade direction (long/short each leg) at each. (4 marks)

(d) Name one statistical test you would run to confirm the spread is stationary, and state the null hypothesis. (3 marks)


Question 3 — Mean-Reversion Model from Scratch (10 marks)

(a) Write down the discrete Ornstein–Uhlenbeck / AR(1) form of a mean-reverting series and identify which coefficient controls the speed of reversion. (4 marks)

(b) Given an AR(1) fit xt=0.6xt1+εtx_{t} = 0.6\,x_{t-1} + \varepsilon_t (mean 0), compute the half-life of mean reversion. Show the formula and the arithmetic. (6 marks)


Question 4 — Momentum Strategy Signal Code (10 marks)

Write, from memory, a clear pseudocode (or Python-like) function that generates a cross-sectional momentum signal: rank a universe of stocks by their trailing 12-month return (skipping the most recent month), go long the top decile and short the bottom decile.

  • State inputs, the lookback convention, and the output. (6 marks)
  • Explain in one or two sentences why the most recent month is skipped. (4 marks)

Question 5 — Overfitting & Walk-Forward (10 marks)

(a) Define overfitting / curve-fitting in a backtest and list three warning signs that a strategy is overfit. (4 marks)

(b) Describe the walk-forward analysis procedure from scratch: define the in-sample (train) and out-of-sample (test) windows, the rolling mechanism, and what metric aggregation you report. (6 marks)


Question 6 — Machine Learning Caution (6 marks)

Explain out loud two reasons machine learning models are dangerous in trading that do NOT apply (or apply less) to ordinary ML domains like image classification. Reference data-related and regime-related issues.


Answer keyMark scheme & solutions

Question 1 (10 marks)

(a) Components in data-flow order (6 marks — 1 per correct component/role, max 6):

  1. Market data handler — ingests live/historical price & reference data, normalises it.
  2. Signal / alpha model — transforms data into predictive signals (strategy logic).
  3. Portfolio / position sizing — converts signals into target positions (risk-weighting, capital allocation).
  4. Risk management — enforces limits (max position, drawdown, exposure) before orders.
  5. Execution / order management (OMS) — routes orders, handles fills, slippage minimisation.
  6. Monitoring / logging / backtester — records state, PnL, reconciliation, alerts.

Marks: 1 per component correctly named and described, in roughly correct order.

(b) Separation of execution from signal (4 marks):

  • Modularity/testability: signal logic can be tested independently of broker connectivity (1).
  • Prevents a broker/API bug or latency spike from corrupting signal state (1).
  • Failure mode 1: a stuck fill or partial execution should not cause the signal engine to re-fire or double-count positions (1).
  • Failure mode 2: execution outages must be handled (retry/cancel) without the alpha model wrongly assuming a position exists (1).

Question 2 (14 marks)

(a) Spread derivation (4 marks):

  • Cointegration assumes a linear combination of pAp_A and pBp_B is stationary (1).
  • Run OLS regression pA,t=α+βpB,t+εtp_{A,t} = \alpha + \beta\, p_{B,t} + \varepsilon_t (1).
  • Hedge ratio β\beta = slope; it is the number of units of BB per unit of AA (1).
  • Spread st=pA,tβpB,ts_t = p_{A,t} - \beta\, p_{B,t} (residual εt\varepsilon_t up to intercept) (1).

(b) Correlation vs cointegration (3 marks):

  • Correlation measures co-movement of returns/changes, short-term, can drift apart (1).
  • Cointegration means a linear combination of the levels is stationary — the spread reverts (1).
  • Mean-reversion trade needs the spread to return to its mean → cointegration guarantees a long-run equilibrium; correlation alone does not (1).

(c) Entry levels (4 marks):

  • Entry spread = μ±zσ=0±2(0.04)=±0.08\mu \pm z\sigma = 0 \pm 2(0.04) = \pm 0.08 (2).
  • Upper: s=+0.08s = +0.08 → spread rich → short A, long B (revert down) (1).
  • Lower: s=0.08s = -0.08 → spread cheap → long A, short B (revert up) (1).

(d) Test (3 marks):

  • Augmented Dickey–Fuller (ADF) test on the spread (or Engle–Granger / Johansen) (2).
  • Null hypothesis H0H_0: the series has a unit root (is non-stationary) (1).

Question 3 (10 marks)

(a) AR(1)/OU form (4 marks):

  • xt=ϕxt1+εtx_t = \phi\, x_{t-1} + \varepsilon_t (mean-centred), or with mean: xt=μ+ϕ(xt1μ)+εtx_t = \mu + \phi(x_{t-1}-\mu)+\varepsilon_t (2).
  • The coefficient ϕ\phi (or θ=1ϕ\theta = 1-\phi) controls reversion speed; ϕ<1|\phi|<1 required for stationarity/reversion (2).

(b) Half-life (6 marks):

  • Formula: t1/2=ln(0.5)ln(ϕ)t_{1/2} = \dfrac{\ln(0.5)}{\ln(\phi)} (or ln2/lnϕ-\ln 2 / \ln\phi) (2).
  • With ϕ=0.6\phi = 0.6: ln0.6=0.5108\ln 0.6 = -0.5108, ln0.5=0.6931\ln 0.5 = -0.6931 (2).
  • t1/2=0.6931/0.5108=1.357t_{1/2} = -0.6931 / -0.5108 = 1.357 periods 1.36\approx 1.36 (2).

Question 4 (10 marks)

(a) Pseudocode (6 marks):

def cross_sectional_momentum(prices):      # prices: DataFrame [date x ticker]
    # lookback: 12 months, skip most recent 1 month (12-1)
    mom = prices.shift(21) / prices.shift(252) - 1   # ~12m ret ending 1m ago
    ranks = mom.rank(axis=1, pct=True)               # cross-sectional rank
    longs  = ranks >= 0.9                             # top decile
    shorts = ranks <= 0.1                             # bottom decile
    weights = longs.astype(float) - shorts.astype(float)
    weights = weights.div(weights.abs().sum(axis=1), axis=0)  # normalise
    return weights

Marks: inputs stated (1); 12-1 lookback (1); cross-sectional ranking (1); top/bottom decile selection (1); long−short weighting (1); normalisation/output (1).

(b) Why skip recent month (4 marks):

  • Short-term (1-month) returns exhibit reversal, not continuation (2).
  • Including the last month contaminates the momentum signal / adds microstructure & liquidity noise, weakening returns (2).

Question 5 (10 marks)

(a) Overfitting (4 marks):

  • Definition: tuning parameters so the model fits noise/idiosyncrasies of historical data, giving great backtest but poor live performance (1).
  • Warning signs (1 each, max 3): too many parameters vs data; unrealistically smooth/high Sharpe; performance collapses out-of-sample; sensitivity to small parameter changes; strategy relies on a few outlier trades.

(b) Walk-forward (6 marks):

  • Split data into consecutive segments (1).
  • In-sample (train) window: optimise/fit parameters (1).
  • Out-of-sample (test) window immediately following: apply frozen params, record performance (1).
  • Roll forward the window (anchored or rolling) by the test length and repeat (1).
  • Concatenate the out-of-sample results only — never re-use test data for fitting (1).
  • Aggregate OOS metrics (Sharpe, drawdown, return) across all folds to judge robustness (1).

Question 6 (6 marks)

  • Low signal-to-noise / non-stationarity (3): financial data is noisy with a low, unstable signal; unlike images, the "labels" (future returns) are near-random, so ML easily fits noise and the data-generating process shifts (regime change) so training distribution ≠ live distribution.
  • Feedback / adversarial & small effective sample (3): markets adapt — an edge disappears once traded (non-stationary target), and independent samples are few (autocorrelated, limited history), so cross-validation assumptions break and models overfit; look-ahead/leakage is easy and costly.

Award 3 marks per distinct, correct data/regime-related reason.


[
  {"claim":"Pairs entry levels at z=2, sigma=0.04 are +/-0.08","code":"sigma=Rational(4,100); z=2; upper=z*sigma; lower=-z*sigma; result=(upper==Rational(8,100) and lower==Rational(-8,100))"},
  {"claim":"Half-life for phi=0.6 is approx 1.357 periods","code":"import sympy as sp; hl=sp.log(sp.Rational(1,2))/sp.log(sp.Rational(6,10)); result=abs(float(hl)-1.3569)<0.001"},
  {"claim":"Momentum lookback offsets: 252 trading days ~12m, 21 days ~1m skip","code":"result=(252-21==231)"},
  {"claim":"phi=0.6 satisfies stationarity condition |phi|<1","code":"phi=sp.Rational(6,10); result=abs(phi)<1"}
]