The brief
A systematic trading desk runs a strategy that makes $20,000 on about 53% of days and loses $20,000 on the rest. Risk management cuts any strategy whose P&L falls $400,000 below its high. Before giving it capital for another year, the head of trading wants to know how deep and how long its drawdowns get.
The last 60 days have been rough: the strategy is up only $40,000, and spent most of them below its high. Is that bad luck, or a sign that the edge has gone?
Your task
An equity curve is a list of cumulative P&L values, one per day, and its first point counts as a high. Its drawdown at a point is how far it is below the highest point so far, in dollars.
- Write
drawdowns(equity): the drawdown at every point, as a NumPy array. RaiseValueErrorfor an empty curve. - Write
max_drawdown(equity), the deepest drawdown, andlongest_drawdown(equity), the longest run of consecutive points with a drawdown above 0. - Write
simulate_pnl(n_paths, n_days, p, step, seed=None): an array with one random walk per row andn_days + 1columns. Each row starts at 0, then moves up bystepwith probabilitypand down bystepotherwise. Usenp.random.default_rng(seed). - Write
drawdown_risk(n_paths, n_days, p, step, limit, seed=None): simulate the paths and return a dict of statistics.median_depthanddepth_95are the median and 95th percentile of each path's deepest drawdown, andmedian_lengthandlength_95the same for its longest.prob_limitis the share of paths whose drawdown reacheslimit.
simulate_pnl and drawdown_risk raise ValueError if p is outside or step is not positive. They also raise it if n_paths or n_days is not a whole number of at least 1, and drawdown_risk if limit is not positive.
The data
WIN_PROB, STEP, DAYS and LIMIT hold the strategy's model, a trading year of 252 days and the limit. RECENT_PNL holds the last 60 days of P&L, oldest first; the equity curve starts at 0 before the first of them. The record is synthetic.
Hint: Where to start
The P&L is lesson 5.11.1's random walk, with steps of $20,000. After days its mean is steps and its standard deviation steps, a check on simulate_pnl.
Hint: Whole arrays at once
The tests simulate 10,000 years, so avoid a Python loop over the paths. Lesson 5.11.1 builds thousands of walks at once, one per row, with cumsum(axis=1). np.maximum.accumulate(paths, axis=1) gives every path's running high in the same way.
Hint: An exact check
The drawdown is itself a Markov chain (lesson 5.11.2). At a high an up step leaves it at 0; otherwise each day moves it one step up or down. Stepping its distribution forward, as lesson 5.11.1 does for first passage, gives the exact chance of reaching the limit.