Supply and Demand Zones: Retests, Role Reversals, and Risk

Video: The ONLY Supply & Demand Trading Strategy You’ll Ever Need
Creator: Emmanuel Malyarovich
Original Video: Watch the original video
Difficulty: Advanced

The Big Idea

A supply or demand zone is a place to evaluate price behavior. It does not automatically authorize a short or a long.

Emmanuel Malyarovich distinguishes several responses: repeated defense of a clear level, consolidation near an edge that may precede a break, and a broken level that changes roles on a later retest. He also uses higher-timeframe zones to assess available reward before entry and manage positions as they approach obstacles.

This guide explains those decisions, separates visible reactions from assumptions about orders, and provides a Pine Script research test of a prior-high role reversal. The source’s reported profits are not independently verified performance or expected returns.

A Zone Describes an Area, Not a Guaranteed Fill

The source uses demand as an area where declines have been bought and supply as an area where rallies have met selling. This overlaps with support and resistance terminology.

A chart can show previous responses. It cannot establish the amount of unfilled buying or selling still present. A moving average can be a useful reference, but it is not itself a measurement of resting institutional orders.

A wide zone also creates an entry problem. Buying its upper edge with a tight stop can produce a loss even if price turns upward from its lower edge. Placing the stop beyond the whole zone increases the risk distance and can reduce reward relative to that risk.

Define the boundaries and the required response before entry. Changing the zone after a loss can make every outcome appear consistent with the original idea.

Repeated Defense and Edge Pressure Are Different

Malyarovich argues that repeated successful retests demonstrate strength. He also describes price lingering near a zone’s boundary as a possible sign that the zone is weakening.

These observations require more than counting touches. A touch followed by a strong move away differs from several small bounces while price remains pressed against the same edge. Repeated testing can increase attention, but it can also accompany changing demand or supply. The number of touches alone does not settle which is happening.

BehaviorCandidate interpretationPossible response
Clear price repeatedly rejects with distanceThe level has been defendedConsider a precisely defined reaction setup
Price consolidates near a demand zone’s lowBuying has not produced a strong recoveryWatch for a breakdown instead of assuming a bounce
Price consolidates near a supply zone’s highSelling has not pushed price awayWatch for a breakout
A broken level holds on a later retestA role reversal may be developingEvaluate continuation with defined invalidation

The source allows direct reaction entries when a very clear price is repeatedly respected. That is different from buying anywhere inside a broad demand area.

A Role Reversal Needs a New Response

After resistance breaks, the source watches whether a later pullback finds support near the old resistance. After support breaks, it watches whether a bounce meets resistance near the old support.

The break alone does not establish the flip. Price needs to revisit the area and behave in a way consistent with the proposed new role. A long retest that closes back below the area provides different evidence from one that recovers above it.

Moving averages can add context. The source uses a nine-period EMA, a 20-period SMA, and a 200-period SMA, with different chart timeframes serving different jobs. A daily 200 SMA and an hourly 200 SMA represent different histories and can mark different obstacles.

Multiple indicators derived from the same price sequence are also not necessarily independent confirmations. Test whether an added moving-average condition contributes value rather than assuming that more aligned lines guarantee a better trade.

Map the Target Before Assessing Reward

Malyarovich looks left on higher timeframes for the next opposing area and generally wants at least 2:1 reward relative to risk before taking a trade.

In an original example, a long entry at 10.20 with a stop at 9.90 has 0.30 units of price risk. If the next supply area begins at 10.80, available reward is 0.60, exactly 2R before costs. If the fill deteriorates to 10.30 with unchanged stop and target, risk becomes 0.40 and reward 0.50, only 1.25R.

A 2R label based on the intended entry is insufficient when the actual fill changes. A target placed before the near boundary of a zone may also offer less reward than its center or far boundary. Record which price you use.

An opposing zone is a planning reference, not a guarantee that price will reach or reverse from it. The source becomes more defensive near those areas, taking profits or tightening management.

Very Tight Stops Can Carry Large Execution Risk

One source example describes approximately 8,000 shares with two cents of intended stop distance, implying $160 of price risk. That arithmetic is correct before execution costs.

In an original stress example, an extra cent of adverse exit movement on 8,000 shares adds $80: half the planned $160 loss. A narrow chart stop can therefore be sensitive to spread, slippage, and depth.

The source also reports receiving only a partial fill on another attempted position. Quantity requested, quantity filled, and average price must remain separate in the risk calculation. A displayed candle low does not prove that all intended shares could be bought there.

The SEC’s stop-order bulletin explains that a stop’s execution price can differ significantly from its trigger. A stop-limit order offers different price control but may fail to execute.

Several prices and moving-average references in the transcript are inconsistent or appear to have lost decimal points. This guide does not treat those fragments as a reliable execution ledger or reconstruct exact profits from them.

Adding Changes the Entire Position

The source adds on a later psychological-level breakdown and on a favorable retest in another trade. An add creates new exposure even if the original entry already has open profit.

For an original example, 100 shares bought at 50 with a 49.50 stop have $50 of price risk. Adding another 100 at 51 while keeping that stop exposes the new shares to $150, bringing combined entry-to-stop loss to $200.

Moving a common stop to 50.50 would theoretically offset the original shares’ $50 gain against the new shares’ $50 loss. That is approximate gross breakeven, not guaranteed safety: costs and a gap can produce a loss, while substantial open profit can still be surrendered.

After every add or partial sale, recalculate remaining quantity, average cost, stop quantities, net loss at the planned stop, and potential giveback from current equity. Do not manage the enlarged position using the original trade’s risk number.

Pine Script: Prior-High Role-Reversal Test

Expand the complete Pine Script research strategy

//@version=6
strategy("Gap above prior high, role-flip retest - research proxy", overlay=true,
     initial_capital=25000, pyramiding=0, margin_long=100,
     commission_type=strategy.commission.percent, commission_value=0.01,
     slippage=2, calc_on_order_fills=true, calc_on_every_tick=false,
     process_orders_on_close=false)

toleranceATR = input.float(0.10, "Frozen zone half-width / prior ATR", minval=0)
useEMA = input.bool(true, "Require bullish 9 EMA confirmation")
reward = input.float(2, "Target R from actual fill", minval=0.1)
cashRisk = input.float(100, "Estimated cash risk before costs", minval=1)
maxShares = input.int(1000, "Maximum shares", minval=1)
maxEntries = input.int(1, "Maximum submitted entries per session", minval=1)
flattenMinute = input.int(960, "NY closing minute (780 for 13:00)", minval=1, maxval=1440)

if barstate.isfirst and (not chart.is_standard or not timeframe.isintraday)
    runtime.error("Use standard intraday US equity candles.")
if session.ispremarket or session.ispostmarket
    runtime.error("Disable extended hours for this regular-session experiment.")

regularTicker = ticker.new(syminfo.prefix, syminfo.ticker, session.regular)
priorHigh = request.security(regularTicker, "D", high[1],
     gaps=barmerge.gaps_off, lookahead=barmerge.lookahead_on)
ema9 = ta.ema(close, 9)
atr = ta.atr(14)
firstBar = hour(time, "America/New_York") == 9 and minute(time, "America/New_York") == 30

varip bool qualifyingGap = false
varip float fixedLevel = na
varip float halfWidth = na
varip int openingBar = na
varip int entries = 0
varip float tradeStop = na
varip float tradeTarget = na
varip float seenPosition = 0.0
varip int lastFillBar = na

fillPass = strategy.position_size != seenPosition
seenPosition := strategy.position_size
if fillPass
    lastFillBar := bar_index
    if strategy.position_size > 0
        distance = strategy.position_avg_price - tradeStop
        if distance > 0
            tradeTarget := strategy.position_avg_price + reward * distance
        else
            tradeTarget := na
            strategy.close("L", comment="Fill beyond stop", immediately=true)

if not fillPass and barstate.isconfirmed
    if firstBar
        qualifyingGap := open > priorHigh and not na(atr[1])
        fixedLevel := priorHigh
        halfWidth := atr[1] * toleranceATR
        openingBar := bar_index
        entries := 0

    minutesClose = hour(time_close, "America/New_York") * 60 + minute(time_close, "America/New_York")
    inWindow = minutesClose > 570 and minutesClose < flattenMinute
    touched = low <= fixedLevel + halfWidth and high >= fixedLevel - halfWidth
    recovered = close > fixedLevel + halfWidth and close > open
    emaOK = not useEMA or (close > ema9 and ema9 > ema9[1])
    if strategy.position_size == 0 and (na(lastFillBar) or bar_index > lastFillBar) and
         qualifyingGap and bar_index > openingBar and entries < maxEntries and
         inWindow and touched and recovered and emaOK
        candidateStop = low - syminfo.mintick
        riskPerShare = (close - candidateStop) * syminfo.pointvalue
        shares = riskPerShare > 0 ? math.floor(math.min(maxShares, cashRisk / riskPerShare)) : 0
        if shares >= 1
            tradeStop := candidateStop
            tradeTarget := na
            entries += 1
            strategy.entry("L", strategy.long, qty=shares)
            strategy.exit("L-bracket", "L", stop=tradeStop)

    if minutesClose == flattenMinute
        strategy.cancel_all()
        strategy.close_all(comment="Session flatten", immediately=true)

if strategy.position_size > 0 and not na(tradeTarget)
    strategy.exit("L-bracket", "L", stop=tradeStop, limit=tradeTarget)

plot(ema9, "9 EMA", color=color.orange)
plot(qualifyingGap ? fixedLevel : na, "Frozen prior high", color=color.blue, style=plot.style_linebr)
plot(qualifyingGap ? fixedLevel + halfWidth : na, "Zone upper edge", color=color.new(color.blue, 60), style=plot.style_linebr)
plot(qualifyingGap ? fixedLevel - halfWidth : na, "Zone lower edge", color=color.new(color.blue, 60), style=plot.style_linebr)
plot(strategy.position_size > 0 ? tradeStop : na, "Stop", color=color.red, style=plot.style_linebr)
plot(strategy.position_size > 0 ? tradeTarget : na, "Target", color=color.green, style=plot.style_linebr)

The following original long-only strategy tests one idea from the source: a stock opens above the prior regular-session high, then pulls back to that old resistance and shows a bullish recovery.

Our definitions: the first 9:30 New York candle establishes whether the opening gap clears the prior high. The zone is fixed at that high ±0.10 of the previous chart bar’s ATR(14). A later candle must overlap the zone, close above its upper edge, and close bullish. Optional confirmation requires price above a rising nine EMA.

The stop is one tick below the rejection candle’s low. The default target is 2R from the actual fill, replacing the source’s hand-selected higher-timeframe supply target. This tests a role-flip entry pattern; it cannot determine whether the original next supply zone offered 2R.

Default quantity is estimated from $100 cash risk, capped at 1,000 shares, with one submitted entry per session. These are research settings, not the source’s position sizes.

Execution QA

Run on standard intraday US equity candles with extended hours disabled and bars aligned to the 9:30 opening. Five- or 15-minute charts are useful starting points. The daily request explicitly uses regular-session data and the previous completed daily high; the historical offset prevents using the current day’s final high prematurely.

The opening decision is made at the first candle’s close using its known opening price. It does not use a premarket shortlist. Entries require a later candle; the opening candle cannot serve as its own retest. The day’s role-flip level and zone width remain fixed.

A confirmed rejection submits a market order normally filled at the next bar’s open. The initial stop is submitted alongside entry. A fill-only recalculation sets the target from actual entry and the frozen stop without using that fill bar’s completed high or low to select another setup. A fill beyond the stop prompts an immediate simulated exit.

Quantity is estimated from the signal close, so a gap can increase actual cash risk. The full-fill emulator does not reproduce the source’s partial fills, variable depth, or low-float execution. The 100% margin setting can reject an order for insufficient buying power.

Commission defaults to 0.01% per fill and slippage to two ticks, adjustable in Strategy Properties. Spreads and halt reopening behavior require additional stress. The configured session-close flatten uses an immediate simulated closing fill, an optimistic assumption. Set the closing minute to 780 for a 13:00 early close; holidays are not automatically detected.

The code has been reviewed for its stated logic but has not been compiled or backtested in TradingView. It omits shorts, discretionary zones, higher-timeframe target selection, repeated-touch grading, adds, and partial exits. No profitability result is claimed.

Backtest Lab

ComparisonControlled changeEvaluate
Moving-average confirmationToggle the nine EMA filterNet expectancy and opportunities excluded
Zone definitionVary the frozen ATR allowanceSensitivity to tolerance and stop distance
Repeat attemptsIncrease entries allowed per sessionLater-attempt results and cumulative losses
Execution stressIncrease slippage and commissionWhether tight-stop results survive costs

Use the same symbols and dates, include losers, and validate unchanged rules on an unseen period. Separately record the next higher-timeframe supply zone before each entry to evaluate the source’s reward filter. A profitable fixed-R proxy does not validate that omitted filter.

Final Takeaway

The framework works as a set of questions: is the area being defended or pressured, has a broken level actually changed roles, and does a realistic entry leave enough room to the next opposing zone? Defined boundaries and responses make those questions reviewable. Actual fills and the risk of the complete position determine what the trade can cost.


Risk Disclosure: This material is for educational and research purposes only and is not financial or investment advice. Trading can result in substantial losses. Backtests are hypothetical, depend heavily on their assumptions, and cannot reproduce every aspect of live execution. Commissions, spreads, slippage, liquidity, partial fills, gaps, trading halts, order behavior, market regime changes, and discretionary decision-making can materially affect real-world results. Low-float stocks, leverage, and short selling carry additional risks. Historical results do not guarantee future performance.

This article is an independent educational companion to the video and is not affiliated with, sponsored by, endorsed by, or authorized by Emmanuel Malyarovich.

As an Amazon Associate I earn from qualifying purchases.