Support, Resistance & Price Action
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:
(a) Using the standard (floor-trader) pivot point formulas, compute the pivot , the first and second support levels , and the first and second resistance levels . Show each formula and value to 2 decimal places. (8 marks)
(b) A psychological round number is defined here as any multiple of . Identify which of your computed levels lie within 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 always lies exactly at the arithmetic midpoint of and ; i.e. show for any . (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 (with window ) as a bar whose high strictly exceeds the highs of the 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 as: a close and the very next close (confirmation). A false breakout is a close followed by . Write a function classify_breakout(closes, R) that returns "confirmed", "false", or "none" for the first bar that closes above . (8 marks)
(c) Given the closes below and resistance , trace your function by hand and state its output. Explain in trading terms what a retest would add to breakout reliability. (6 marks)
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 from which price previously rallied sharply. Suppose two demand zones exist: and , and the current price is . 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 swing lows at prices , propose a quantitative "support strength" score for a candidate price that rewards (i) more touches near and (ii) closeness of those touches to . Write the formula, justify each term, and compute for swing lows using a tolerance band of . (6 marks)
End of paper
Answer keyMark scheme & solutions
Question 1
(a) Pivot computation (8 marks)
Standard formulas: (2 marks)
(1.5) (1.5) (1.5) (1.5)
(b) Round-number confluence (6 marks)
Round numbers (multiples of 5) near each level: (3 marks for identification)
- → nearest 425 (1.13 away) / 420 (2.87) → not within ±1.
- → 430 is 0.53 away → confluence ✓
- → 415 (2.13) — no.
- → 435 (1.27) — no.
- → 410 is 0.53 away → confluence ✓
Levels with confluence: (≈430) and (≈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 (6 marks)
(2) Since , we have . (2) Hmm — this gives , not , unless we note the intended identity uses symmetry. Correct midpoint proof: since and , This equals iff , which is only true when .
Correct answer: the exact midpoint identity that always holds is and is the midpoint of only when . 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 , inner check → , which is for fixed . (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 ≤ 100.
- : 98 ≤ 100.
- : → first break. Next → returns "false". (3 marks)
Retest explanation (3 marks): A retest occurs when, after breaking , 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 .
(b) Zone selection (6 marks)
- Proximity: is nearer to price 425 (≈4 pts) than (≈11 pts). On a decline, price meets first, so 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: is the stronger first line of defence by proximity provided it is still fresh; if has already been tested and is fresh, 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 ): Justification (2 marks): the sum counts touches (term (i) — more touches → higher score); the weight decays linearly to 0 at the band edge so closer touches contribute more (term (ii)); touches outside contribute nothing.
Compute , , lows : (4 marks)
- : →
- : →
- : → excluded
- : →
[
{"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"}
]