When to Trade — Timing & Sessions
Level 5 — Mastery Examination (Cross-Domain: Quantitative Finance + Statistics + Coding)
Time limit: 90 minutes Total marks: 60 Instructions: Answer ALL three questions. Show full derivations. Code may be written in Python/pseudo-code but must be logically complete. Use for math.
Question 1 — Opening Range & Session Volatility Model (20 marks)
Intraday volatility is empirically U-shaped: high at the open (opening range, 09:15–09:45), low during the midday lull, high again in the power hour (closing session).
Model the instantaneous variance rate over a normalized trading session as:
where controls the U-curvature and is the midday floor variance rate.
(a) The total session variance is . Derive a closed-form expression for in terms of and . (4 marks)
(b) Given empirical measurements: the midday-lull minimum variance rate is (per unit ) and the total session variance is , solve for . (4 marks)
(c) Define the opening range variance fraction as the proportion of total session variance realized during the first 30 minutes. If the session is 375 minutes long (Indian equity cash session 09:15–15:30), the opening range maps to . Compute the fraction using the values from (b). (6 marks)
(d) Interpret the result in (c) for a trader: argue quantitatively why avoiding the first 30 minutes discards a disproportionate/ proportionate share of the day's realizable move, and connect it to the "times to avoid" principle. (6 marks)
Question 2 — Gap Risk, Expiry Volatility & Position Sizing (22 marks)
An overnight-held long position faces a gap return (close-to-open log return). Assume with .
(a) On a normal night, . On an earnings-announcement night, empirical evidence shows the gap standard deviation inflates by a factor . Compute the 1-day 99% overnight Value-at-Risk (VaR) as a fraction of position value for both cases. Use . (6 marks)
(b) A trader caps overnight VaR at 2% of account equity. Position value is , account equity is . Derive the maximum allowed on a normal night and on an earnings night, and state the ratio. (6 marks)
(c) On monthly options expiry day, realized volatility clusters. Model expiry-day intraday returns as a mixture: with probability (a "pin/unwind" regime) variance is , otherwise variance is , where . Derive the effective (mixture) variance and the effective standard deviation, then compute the excess kurtosis contribution qualitatively (state whether the mixture is leptokurtic and why). (6 marks)
(d) Write a Python function expiry_var(P, sigma0, p, z) that returns the expiry-day 1-day VaR using the mixture variance from (c). Then state what it returns for , , , . (4 marks)
Question 3 — Economic Calendar Event Study & Session Backtest (18 marks)
You are given a list of intraday 1-minute bars and an economic-calendar timestamp for a high-impact release (e.g., RBI policy at 10:00).
(a) Define the event window around release time with half-width minutes. Explain, with reference to volatility windows, why should be asymmetric in practice (pre vs post). (4 marks)
(b) Write a function event_move(bars, tau, w) that computes the absolute price move and the average per-minute volume inside the window, given bars as a list of dicts {"t":int_minutes, "price":float, "vol":int}. Handle missing bars gracefully. (8 marks)
(c) Prove/argue: if the event-window absolute move exceeds average-day standard deviations, a rule to avoid entering positions in the 5 minutes before release strictly reduces expected slippage cost. State assumptions and give the inequality that must hold. (6 marks)
Answer keyMark scheme & solutions
Question 1
(a) Expand and integrate: At : ; at : . Difference . Marks: integral setup (2), correct evaluation (2).
(b) Marks: substitution (2), (2).
(c) Opening-range variance: At : , ; at : . Difference . Times : . Plus . Numerator . Marks: integral setup (2), cube evaluations (2), (2).
(d) The first 30 minutes is of clock time but carries of the day's variance — nearly 1.9× its time-share. So it is a disproportionately high-move (and high-risk) window. A risk-averse or slippage-sensitive trader who "avoids the first 30 minutes" thus discards a large slice of realizable move; conversely a scalper seeking movement should trade it. This quantifies the "times to avoid" principle: avoidance decisions should be weighted by variance density, not clock minutes. Full marks require: (i) compare 8% vs 14.9% (2), (ii) compute the ~1.9× ratio (2), (iii) link to trader style / times-to-avoid (2).
Question 2
(a) VaR (fraction) (since ).
- Normal: .
- Earnings: ; VaR . Marks: formula (2), normal value (2), earnings value (2).
(b) Constraint: .
- Normal: .
- Earnings: .
- Ratio (equals , since VaR scales linearly with ). Marks: constraint (2), both (2), ratio = 3.5 with reasoning (2).
(c) Mixture variance (mean return in each regime): With : , so . The mixture of two zero-mean normals with different variances is leptokurtic (excess kurtosis ): the high-variance regime fattens the tails and the low-variance regime peaks the center — hence "fat tails" on expiry, justifying wider stops / smaller size. Marks: mixture formula (2), & (2), leptokurtic argument (2).
(d)
import math
def expiry_var(P, sigma0, p, z):
var_eff = sigma0**2 * (1 + 8*p) # mixture variance
sigma_eff = math.sqrt(var_eff)
return z * sigma_eff * PFor : ; VaR . Marks: correct mixture var in code (2), returned value (2).
Question 3
(a) Event window . Asymmetry rationale: pre-release volatility is suppressed (traders flatten/hedge, spreads widen but moves are small — "calm before"), while post-release volatility spikes as the surprise is priced in and can persist for many minutes. So the effective volatility window is longer after ; a symmetric either wastes the quiet pre-window or truncates the post-move. Practically use . Marks: window definition (2), asymmetry pre/post reasoning (2).
(b)
def event_move(bars, tau, w):
lut = {b["t"]: b for b in bars} # index by minute
def nearest(target): # graceful missing-bar handling
if target in lut: return lut[target]
cands = [b for b in bars if abs(b["t"]-target) <= 2]
if not cands: return None
return min(cands, key=lambda b: abs(b["t"]-target))
lo, hi = nearest(tau - w), nearest(tau + w)
if lo is None or hi is None:
return None
abs_move = abs(hi["price"] - lo["price"])
window = [b for b in bars if tau - w <= b["t"] <= tau + w]
vols = [b["vol"] for b in window]
avg_vol = sum(vols)/len(vols) if vols else 0.0
return {"abs_move": abs_move, "avg_vol": avg_vol}Marks: correct endpoint prices & abs move (3), average volume over window (2), missing-bar handling / empty guard (3).
(c) Assumptions: (i) slippage cost per trade where = half-spread, monotone increasing in local volatility; (ii) in the pre-release minute spreads widen and depth thins, so ; (iii) expected fill quality worsens as move magnitude grows. Let day standard deviation be . If the event window absolute move satisfies then expected adverse slippage of entering just before is (partial fill at post-jump prices), while deferring entry to caps slippage at the (lower) post-event spread cost . Since is elevated and jump exposure is avoided, the deferral rule gives which holds whenever ; with (spreads normalize after the print) the RHS is , so the inequality holds for any . Hence avoidance strictly reduces expected slippage. Marks: assumptions (2), inequality construction (2), conclusion under stated condition (2).
[
{"claim":"Q1a total variance V = a/12 + b via integration of a(t-1/2)^2+b on [0,1]","code":"t,a,b=symbols('t a b'); V=integrate(a*(t-Rational(1,2))**2+b,(t,0,1)); result= simplify(V-(a/12+b))==0"},
{"claim":"Q1b solving 0.0009=a/12+0.0004 gives a=0.006","code":"a=symbols('a'); sol=solve(Eq(Rational(9,10000),a/12+Rational(4,10000)),a)[0]; result= sol==Rational(6,1000)"},
{"claim":"Q1c opening range variance fraction f ~ 0.1487","code":"t=symbols('t'); a=Rational(6,1000); b=Rational(4,10000); num=integrate(a*(t-Rational(1,2))**2+b,(t,0,Rational(8,100))); f=num/Rational(9,10000); result= abs(float(f)-0.14869)<0.001"},
{"claim":"Q2a earnings overnight VaR = 2.326*0.028 = 0.065128","code":"result= abs(2.326*0.028-0.065128)<1e-9"},
{"claim":"Q2b position ratio normal/earnings equals 3.5","code":"pn=20000/(2.326*0.008); pe=20000/(2.326*0.028); result= abs(pn/pe-3.5)<1e-9"},
{"claim":"Q2c effective mixture variance = 2.6*sigma0^2 for p=0.2","code":"s0,p=symbols('s0 p'); veff=p*9*s0**2+(1-p)*s0**2; result= simplify(veff.subs(p,Rational(2,10))-Rational(26,10)*s0**2)==0"},
{"claim":"Q2d expiry VaR ~ 3750.55 for P=1e5,sigma0=0.01,p=0.2,z=2.326","code":"import math; var=(0.01**2)*(1+8*0.2); v=2.326*math.sqrt(var)*100000; result= abs(v-3750.55)<0.5"}
]