Level 5 — MasteryChart Patterns

Chart Patterns

90 minutes60 marksprintable — key stays hidden on paper

Subject: Stock-Market · Chapter: 3.5 Chart Patterns Difficulty: Level 5 — Mastery (cross-domain: math + quantitative reasoning + coding + proof) Time limit: 90 minutes Total marks: 60

Instructions: Answer all three questions. Show full reasoning. Where code is requested, write clean, runnable Python (pseudocode acceptable only if syntactically consistent). Use ...... notation for mathematics.


Question 1 — Measured Moves, Geometry & Proof (20 marks)

A symmetrical triangle continuation pattern forms on a stock. The pattern is bounded by two converging trendlines. At the pattern's left edge (time t=0t=0) the upper line passes through price 120120 and the lower line through price 100100. The upper line descends at 0.50.5 price-units per day; the lower line ascends at 0.30.3 price-units per day.

(a) Derive an expression for the vertical height h(t)h(t) of the triangle at time tt, and find the apex time t\*t^\* where the lines meet. (4 marks)

(b) The "measured move" (pattern-height) target for a breakout is computed by projecting the height of the pattern at its widest point in the breakout direction from the breakout price. Price breaks upward through the upper trendline at t=10t=10 days. Compute the breakout price and the measured-move target. (5 marks)

(c) A classical Head-and-Shoulders top has left shoulder peak LL, head peak HH, right shoulder peak RR, and a neckline. Prove algebraically that if the neckline is horizontal at level NN, the measured downside target T=N(HN)T = N-(H-N) can be written as T=2NHT = 2N - H, and state the condition on H,NH, N for the target to remain a positive price. (4 marks)

(d) State and justify a general rule connecting the volatility (average bar range) during a triangle to the reliability of its measured-move target. Reference at least two distinct chart-pattern subtopics in your justification. (7 marks)


Question 2 — Coding a Pattern Detector (22 marks)

You are given a daily closing-price series as a Python list prices.

(a) Write a function find_local_extrema(prices, k) that returns two lists — indices of local maxima and local minima — where a point ii is a local maximum if prices[i] is strictly greater than all points within a window of kk bars on each side (and symmetrically for minima). Handle boundaries. (6 marks)

(b) Using detected extrema, write is_double_top(peaks, prices, tol) that returns True when two consecutive peaks are within relative tolerance tol of each other in price and separated by a trough. Give the mathematical tolerance condition you enforce. (7 marks)

(c) Write measured_target(pattern_type, neckline, extreme) that returns the projected target price for pattern_type in {"double_top", "double_bottom", "head_shoulders", "inverse_hs"}. Explain how sign handling distinguishes reversal-up from reversal-down patterns. (5 marks)

(d) Explain one false-positive failure mode of your is_double_top detector and propose a volume-based filter to reduce it, tying it to the distinction between continuation and reversal patterns. (4 marks)


Question 3 — Classification, Reasoning & Model Critique (18 marks)

(a) Classify each of the following as continuation or reversal, and give a one-line structural reason: rising wedge (in uptrend), falling wedge (in downtrend), bull flag, inverse head-and-shoulders, ascending triangle (in uptrend), rounding bottom. (6 marks)

(b) A trader claims: "A cup-and-handle and an inverse head-and-shoulders give identical measured-move targets whenever the cup depth equals the head depth." Evaluate this claim rigorously, defining each pattern's measurement convention and identifying under what precise geometric condition the claim holds or fails. (6 marks)

(c) Design a falsifiable back-test to determine whether rectangles/ranges produce reliable breakout targets. Specify: the entry rule, the target rule (measured move), the stop rule, and the statistic you would compute to accept/reject reliability. State your null hypothesis. (6 marks)

Answer keyMark scheme & solutions

Question 1

(a) Upper line: u(t)=1200.5tu(t)=120-0.5t. Lower line: l(t)=100+0.3tl(t)=100+0.3t. Height h(t)=u(t)l(t)=(1200.5t)(100+0.3t)=200.8th(t)=u(t)-l(t)=(120-0.5t)-(100+0.3t)=20-0.8t. (2 marks: correct lines + subtraction) Apex when h(t\*)=0200.8t\*=0t\*=25h(t^\*)=0 \Rightarrow 20-0.8t^\*=0 \Rightarrow t^\*=25 days. (2 marks)

(b) Widest point is at t=0t=0: height =20=20. (1) Breakout price = upper line at t=10t=10: u(10)=1200.5(10)=115u(10)=120-0.5(10)=115. (2) Measured-move target (upward) = breakout price + pattern height = 115+20=135115+20=135. (2)

(c) Downside target T=N(HN)T=N-(H-N). Expand: T=NH+N=2NHT=N-H+N=2N-H. (2 marks for algebra) Condition for positivity: T>02NH>0H<2NT>0 \Rightarrow 2N-H>0 \Rightarrow H<2N. So the head must be less than twice the neckline level (equivalently the drop HNH-N must be smaller than NN). (2 marks)

(d) (7 marks — indicative content)

  • Measured-move magnitude scales with pattern height; if average bar range (volatility) is a large fraction of pattern height, the trendlines are poorly defined and the breakout price / height estimate carries large error → lower reliability. (2)
  • Low intra-pattern volatility (contracting range, as in triangles/pennants 3.5.4/3.5.5) with a sharp volume-backed breakout tends to give cleaner, more reliable targets. (2)
  • A rectangle/range (3.5.6) measured over noisy wide bars gives ambiguous height; a clean narrow-bodied consolidation gives a crisp height. Reference to continuation vs reversal (3.5.11): continuation patterns forming after a strong trend with declining volatility are statistically more reliable. (2)
  • Coherent linking of ≥2 subtopics and a stated rule. (1)

Question 2

(a) (6 marks)

def find_local_extrema(prices, k):
    maxima, minima = [], []
    n = len(prices)
    for i in range(n):
        lo, hi = max(0, i-k), min(n-1, i+k)
        window = prices[lo:hi+1]
        others = prices[lo:i] + prices[i+1:hi+1]
        if others and prices[i] > max(others):
            maxima.append(i)
        elif others and prices[i] < min(others):
            minima.append(i)
    return maxima, minima

Marks: window bounds/boundary handling (2), strict comparison excluding self (2), returns both lists (2).

(b) (7 marks)

def is_double_top(peaks, prices, tol):
    for a, b in zip(peaks, peaks[1:]):
        pa, pb = prices[a], prices[b]
        # relative price agreement
        if abs(pa - pb) / max(pa, pb) <= tol:
            # require a trough (lower low) between them
            trough = min(prices[a+1:b]) if b > a+1 else None
            if trough is not None and trough < min(pa, pb):
                return True
    return False

Tolerance condition: PaPbmax(Pa,Pb)tol\dfrac{|P_a-P_b|}{\max(P_a,P_b)}\le \text{tol} (2), consecutive peaks (2), intervening trough below both peaks (2), returns bool (1).

(c) (5 marks)

def measured_target(pattern_type, neckline, extreme):
    height = abs(extreme - neckline)
    if pattern_type in ("double_top", "head_shoulders"):
        return neckline - height   # downside reversal
    elif pattern_type in ("double_bottom", "inverse_hs"):
        return neckline + height   # upside reversal
    raise ValueError("unknown pattern")

Sign handling: top/head patterns are bearish reversals → subtract height below neckline; bottom/inverse patterns are bullish reversals → add height above neckline. extreme is the head/peak (tops) or trough (bottoms). Marks: correct formula (2), correct sign per pattern (2), explanation (1).

(d) (4 marks) False positive: two similar peaks in a strong uptrend continuation (e.g., a bull flag or minor pullback) can mimic a double top without a genuine reversal. Filter: require declining volume on the second peak and a volume surge on neckline break — reversal patterns typically show volume divergence, while continuation patterns keep trend-direction volume. Marks: valid failure mode (2), volume filter tied to continuation vs reversal (2).


Question 3

(a) (6 marks, 1 each)

  • Rising wedge (uptrend): reversal (bearish) — converging up-slanting lines with weakening momentum.
  • Falling wedge (downtrend): reversal (bullish) — converging down-slanting lines, momentum fades.
  • Bull flag: continuation — brief counter-trend consolidation within an uptrend.
  • Inverse head-and-shoulders: reversal (bullish) — three troughs, middle deepest, at a bottom.
  • Ascending triangle (uptrend): continuation — flat top, rising lows, breaks up.
  • Rounding bottom: reversal (bullish) — gradual U-shaped base.

(b) (6 marks)

  • Cup-and-handle: measured move = cup depth projected up from breakout of the cup's rim/resistance. Target =R+Dcup=R+D_{cup}.
  • Inverse H&S: measured move = head depth (neckline - head) projected up from neckline break. Target =N+Dhead=N+D_{head}.
  • The claim holds only if both the projection base (rim RR vs neckline NN) and depth (Dcup=DheadD_{cup}=D_{head}) coincide. Equal depth alone is insufficient because the breakout/projection reference levels differ (RNR\neq N in general). Condition: R=NR=N and Dcup=DheadD_{cup}=D_{head} ⇒ identical targets; otherwise the targets differ by RNR-N. (claim as stated is FALSE without the reference-level condition — award full marks for identifying this).

(c) (6 marks)

  • Entry rule: enter on close beyond the range boundary (long above resistance, short below support) with a confirmation filter (e.g., close >> boundary by \ge tol).
  • Target rule: measured move = range height (resistance − support) projected in breakout direction.
  • Stop rule: place stop at the opposite boundary (or mid-range).
  • Statistic: over NN historical rectangle breakouts, compute the fraction hitting target before stop, or mean RR-multiple; compare to a random-entry benchmark.
  • Null hypothesis H0H_0: rectangle breakout targets are hit no more often than a random-timing benchmark (expected hit-rate = baseline); reject if observed hit-rate significantly exceeds it (e.g., binomial/one-sided test, p<0.05p<0.05). Marks: entry (1), target (1), stop (1), statistic (1.5), null hypothesis (1.5).
[
  {"claim":"Triangle height h(t)=20-0.8t is zero at apex t*=25","code":"t=symbols('t'); h=(120-Rational(1,2)*t)-(100+Rational(3,10)*t); ts=solve(h,t)[0]; result = (h==20-Rational(4,5)*t) and (ts==25)"},
  {"claim":"Breakout price 115 and measured target 135","code":"bp=120-Rational(1,2)*10; height=20; target=bp+height; result = (bp==115) and (target==135)"},
  {"claim":"HS downside target simplifies to 2N-H and positive iff H<2N","code":"N,H=symbols('N H'); T=N-(H-N); result = (simplify(T-(2*N-H))==0)"},
  {"claim":"measured_target sign logic: double_top below neckline, inverse_hs above","code":"neck=100; ext_top=130; ext_bot=70; dt=neck-abs(ext_top-neck); ihs=neck+abs(neck-ext_bot); result = (dt==70) and (ihs==130)"}
]