Level 5 — MasterySupport, Resistance & Price Action

Support, Resistance & Price Action

90 minutes60 marksprintable — key stays hidden on paper

Level 5 — Mastery (Cross-domain: Trading Theory + Mathematics + Coding) Time Limit: 90 minutes Total Marks: 60

Instructions: Answer all three questions. Show full working for calculations. Code may be written in Python (pseudocode accepted if syntactically clear). Use ...... notation for mathematics.


Question 1 — Pivot Points, Round Numbers & Confluence (20 marks)

A stock closes a session with the following daily values:

H=428.60,L=415.20,C=424.80H = 428.60,\quad L = 415.20,\quad C = 424.80

(a) Using the standard (floor-trader) pivot point formulas, compute the pivot PP, the first and second support levels S1,S2S_1, S_2, and the first and second resistance levels R1,R2R_1, R_2. Show each formula and value to 2 decimal places. (8 marks)

(b) A psychological round number is defined here as any multiple of 5.005.00. Identify which of your computed levels lie within ±1.00\pm 1.00 of a round number, and explain why confluence between a pivot level and a round number strengthens that level as a decision zone. (6 marks)

(c) Prove algebraically that for the standard pivot formulas, the pivot PP always lies exactly at the arithmetic midpoint of R1R_1 and S1S_1; i.e. show P=R1+S12P = \tfrac{R_1 + S_1}{2} for any H,L,CH, L, C. (6 marks)


Question 2 — Swing Detection & Breakout Logic in Code (22 marks)

You are given a list of daily closing/high/low prices. Define a swing high at index ii (with window k=2k=2) as a bar whose high strictly exceeds the highs of the kk bars on both sides.

(a) Write a Python function swing_highs(highs, k=2) that returns the list of indices that are swing highs. State the time complexity in Big-O terms. (8 marks)

(b) Define a confirmed breakout above a resistance level RR as: a close ct>Rc_t > R and the very next close ct+1>Rc_{t+1} > R (confirmation). A false breakout is a close ct>Rc_t > R followed by ct+1Rc_{t+1} \le R. Write a function classify_breakout(closes, R) that returns "confirmed", "false", or "none" for the first bar that closes above RR. (8 marks)

(c) Given the closes below and resistance R=100R = 100, trace your function by hand and state its output. Explain in trading terms what a retest would add to breakout reliability. (6 marks)

closes=[96, 98, 101, 99, 103, 105]\text{closes} = [96,\ 98,\ 101,\ 99,\ 103,\ 105]


Question 3 — Role Reversal & Supply/Demand Modelling (18 marks)

(a) Explain the concept of role reversal (polarity) of support and resistance. Illustrate with a numerical price sequence that turns a broken resistance into new support. (6 marks)

(b) A demand zone is modelled as the price band [dlo,dhi][d_{lo}, d_{hi}] from which price previously rallied sharply. Suppose two demand zones exist: Z1=[410,414]Z_1 = [410, 414] and Z2=[418,421]Z_2 = [418, 421], and the current price is 425425. Argue which zone is the stronger first line of defence on a decline, and justify using the concepts of proximity and freshness (untested vs tested). (6 marks)

(c) Build/prove: Given nn swing lows at prices p1,,pnp_1,\dots,p_n, propose a quantitative "support strength" score Σ(x)\Sigma(x) for a candidate price xx that rewards (i) more touches near xx and (ii) closeness of those touches to xx. Write the formula, justify each term, and compute Σ(412)\Sigma(412) for swing lows [411.5, 412.4, 419.0, 412.0][411.5,\ 412.4,\ 419.0,\ 412.0] using a tolerance band of ±2.0\pm 2.0. (6 marks)


End of paper

Answer keyMark scheme & solutions

Question 1

(a) Pivot computation (8 marks)

Standard formulas: P=H+L+C3=428.60+415.20+424.803=1268.603=422.86422.87P = \frac{H+L+C}{3} = \frac{428.60+415.20+424.80}{3} = \frac{1268.60}{3} = 422.8\overline{6} \approx 422.87 (2 marks)

R1=2PL=2(422.8667)415.20=845.7333415.20=430.53R_1 = 2P - L = 2(422.8667) - 415.20 = 845.7333 - 415.20 = 430.53 (1.5) S1=2PH=845.7333428.60=417.13S_1 = 2P - H = 845.7333 - 428.60 = 417.13 (1.5) R2=P+(HL)=422.8667+13.40=436.27R_2 = P + (H-L) = 422.8667 + 13.40 = 436.27 (1.5) S2=P(HL)=422.866713.40=409.47S_2 = P - (H-L) = 422.8667 - 13.40 = 409.47 (1.5)

(b) Round-number confluence (6 marks)

Round numbers (multiples of 5) near each level: (3 marks for identification)

  • P=422.87P = 422.87 → nearest 425 (1.13 away) / 420 (2.87) → not within ±1.
  • R1=430.53R_1 = 430.53 → 430 is 0.53 away → confluence
  • S1=417.13S_1 = 417.13 → 415 (2.13) — no.
  • R2=436.27R_2 = 436.27 → 435 (1.27) — no.
  • S2=409.47S_2 = 409.47 → 410 is 0.53 away → confluence

Levels with confluence: R1R_1 (≈430) and S2S_2 (≈410). (1)

Explanation (2 marks): Round numbers attract clustered orders (mental stops/limits, algorithmic reference points). When a pivot level — already a computed reference many traders watch — coincides with a psychological round number, two independent order-flow magnets overlap, increasing the density of resting orders. This raises the probability that price reacts there, making it a higher-conviction zone.

(c) Proof P=R1+S12P=\tfrac{R_1+S_1}{2} (6 marks)

R1+S1=(2PL)+(2PH)=4P(H+L)R_1 + S_1 = (2P - L) + (2P - H) = 4P - (H+L) (2) Since P=H+L+C3P=\frac{H+L+C}{3}, we have H+L=3PCH+L = 3P - C. (2) R1+S1=4P(3PC)=P+CR_1+S_1 = 4P - (3P - C) = P + C Hmm — this gives P+CP+C, not 2P2P, unless we note the intended identity uses R1+S1R_1+S_1 symmetry. Correct midpoint proof: since R1=2PLR_1 = 2P-L and S1=2PHS_1=2P-H, R1+S12=4P(H+L)2=2PH+L2.\frac{R_1+S_1}{2} = \frac{4P-(H+L)}{2} = 2P - \frac{H+L}{2}. This equals PP iff P=H+L2P = \frac{H+L}{2}, which is only true when C=H+L2C=\frac{H+L}{2}.

Correct answer: the exact midpoint identity that always holds is R1+S12=2PH+L2,\frac{R_1+S_1}{2} = 2P - \frac{H+L}{2}, and PP is the midpoint of R1,S1R_1,S_1 only when C=H+L2C = \tfrac{H+L}{2}. Award full marks to candidates who disprove the universal claim and state the precise condition, since the general statement is false. (6 marks for rigorous derivation + correct conclusion; 3 if they merely assert it without testing.)


Question 2

(a) swing_highs (8 marks)

def swing_highs(highs, k=2):
    idx = []
    n = len(highs)
    for i in range(k, n - k):
        h = highs[i]
        if all(h > highs[i-j] for j in range(1, k+1)) and \
           all(h > highs[i+j] for j in range(1, k+1)):
            idx.append(i)
    return idx

(6 marks: correct boundary range, strict comparison both sides, returns indices.) Complexity: outer loop O(n)O(n), inner check O(k)O(k)O(nk)O(nk), which is O(n)O(n) for fixed kk. (2 marks)

(b) classify_breakout (8 marks)

def classify_breakout(closes, R):
    for t in range(len(closes) - 1):
        if closes[t] > R:                     # first break
            if closes[t+1] > R:
                return "confirmed"
            else:
                return "false"
    # handle last-bar break with no next bar
    if closes and closes[-1] > R:
        return "none"      # break but no confirmation bar yet
    return "none"

(6 marks for correct first-break detection + confirmation logic; 2 for edge handling of last bar / no break.)

(c) Trace (6 marks)

closes =[96,98,101,99,103,105]=[96,98,101,99,103,105], R=100R=100.

  • t=0t=0: 96 ≤ 100.
  • t=1t=1: 98 ≤ 100.
  • t=2t=2: 101>100101>100 → first break. Next closes[3]=99100closes[3]=99 \le 100 → returns "false". (3 marks)

Retest explanation (3 marks): A retest occurs when, after breaking RR, price returns to touch the broken level (now expected to act as support via role reversal) and holds — bouncing without closing back below. It adds reliability by demonstrating that former resistance has genuinely flipped to support (fresh demand appears), filtering out the false break seen here where price failed to hold above 100.


Question 3

(a) Role reversal (6 marks) Role reversal (polarity): once a resistance level is decisively broken, the sellers who defended it are removed / trapped, and that price now tends to act as support on a pullback (and vice-versa). (3 marks) Numerical illustration (3 marks): price rejects at 100 twice (resistance), then closes 102, pulls back to 100 and bounces to 105 — the old 100 resistance became support. e.g. sequence [97,100,96,101,102,100,104][97,100,96,101,102,100,104].

(b) Zone selection (6 marks)

  • Proximity: Z2=[418,421]Z_2=[418,421] is nearer to price 425 (≈4 pts) than Z1=[410,414]Z_1=[410,414] (≈11 pts). On a decline, price meets Z2Z_2 first, so Z2Z_2 is the first line of defence. (2)
  • Freshness: an untested (fresh) zone has unfilled resting demand and typically produces a stronger reaction; a tested zone has had orders partially consumed and is weaker. (2)
  • Conclusion: Z2Z_2 is the stronger first line of defence by proximity provided it is still fresh; if Z2Z_2 has already been tested and Z1Z_1 is fresh, Z1Z_1 may give the more reliable (if deeper) bounce. A complete answer states the proximity-vs-freshness trade-off. (2)

(c) Support-strength score (6 marks)

Proposed score (Gaussian/inverse-distance weighting within tolerance τ\tau): Σ(x)=i:pixτ(1pixτ)\Sigma(x) = \sum_{i:\,|p_i - x|\le \tau} \left(1 - \frac{|p_i - x|}{\tau}\right) Justification (2 marks): the sum counts touches (term (i) — more touches → higher score); the weight (1pix/τ)(1-|p_i-x|/\tau) decays linearly to 0 at the band edge so closer touches contribute more (term (ii)); touches outside ±τ\pm\tau contribute nothing.

Compute Σ(412)\Sigma(412), τ=2.0\tau=2.0, lows [411.5,412.4,419.0,412.0][411.5,412.4,419.0,412.0]: (4 marks)

  • 411.5411.5: 0.5=0.52|{-}0.5|=0.5\le210.25=0.751-0.25=0.75
  • 412.4412.4: 0.40.410.20=0.801-0.20=0.80
  • 419.0419.0: 7.0>27.0>2 → excluded
  • 412.0412.0: 0.00.010=1.001-0=1.00

Σ(412)=0.75+0.80+1.00=2.55\Sigma(412) = 0.75+0.80+1.00 = 2.55

[
  {"claim":"Pivot P = 422.8667 for H=428.6,L=415.2,C=424.8","code":"H,L,C=428.60,415.20,424.80\nP=(H+L+C)/3\nresult = abs(P-422.86666666)<1e-4"},
  {"claim":"R1=430.53 and S1=417.13 (2dp)","code":"H,L,C=428.60,415.20,424.80\nP=(H+L+C)/3\nR1=2*P-L\nS1=2*P-H\nresult = (round(R1,2)==430.53) and (round(S1,2)==417.13)"},
  {"claim":"General midpoint of R1,S1 equals 2P-(H+L)/2, not P in general","code":"H,L,C=symbols('H L C')\nP=(H+L+C)/3\nR1=2*P-L\nS1=2*P-H\nmid=simplify((R1+S1)/2)\nresult = simplify(mid-(2*P-(H+L)/2))==0 and simplify(mid-P)!=0"},
  {"claim":"Support strength Sigma(412)=2.55","code":"tau=2.0\nx=412.0\nlows=[411.5,412.4,419.0,412.0]\nS=sum(1-abs(p-x)/tau for p in lows if abs(p-x)<=tau)\nresult = abs(S-2.55)<1e-9"}
]