AnyLearn
All lessons
Businessintermediate

Does it work? Testing supply and demand zones honestly

Decades of research on support, resistance and chart rules find effects that are real, small and fragile. This lesson reviews that evidence, shows why a bounce rate is not a profit, and builds a mechanical zone detector in Python so the method's own predictions can be tested.

Updated · AI-authored, review-gated · how lessons are made

Not signed in: your progress and quiz score won't be saved.
Progress1 / 10

What would count as evidence

The first lesson ended with the method's central problem: its rules use words like tight base and decisive departure that have no fixed thresholds, so no two traders draw quite the same zones. The second showed that some levels genuinely stall price, largely because stop and profit orders cluster at round numbers.

Testing whether zones work needs three things the method does not supply on its own.

  1. A mechanical definition, so a zone is the same zone every time the rule is applied.
  2. A comparison group, because price reverses often even at meaningless levels.
  3. A profit measure after costs, because how often a trade works is not the same as whether it makes money.

Key idea: Most claims about chart methods fail on the second point. A strategy that bounces at 60% of zones sounds strong until you learn that random levels bounce at 56%.

Full lesson text

All 10 steps on one page, for reading, reference, and search.

Show

1. What would count as evidence

The first lesson ended with the method's central problem: its rules use words like tight base and decisive departure that have no fixed thresholds, so no two traders draw quite the same zones. The second showed that some levels genuinely stall price, largely because stop and profit orders cluster at round numbers.

Testing whether zones work needs three things the method does not supply on its own.

  1. A mechanical definition, so a zone is the same zone every time the rule is applied.
  2. A comparison group, because price reverses often even at meaningless levels.
  3. A profit measure after costs, because how often a trade works is not the same as whether it makes money.

Key idea: Most claims about chart methods fail on the second point. A strategy that bounces at 60% of zones sounds strong until you learn that random levels bounce at 56%.

2. The study that made the case

The most cited early test is Brock, Lakonishok and LeBaron, published in the Journal of Finance in 1992. They applied two families of simple rules to the Dow Jones Industrial Average from 1897 to 1986:

  • Moving average rules, buying when a short average crosses above a long one.
  • Trading range break rules, buying when price breaks above a recent high and selling below a recent low. These are support and resistance rules written mechanically.

Using bootstrap methods, they found that buy signals were followed by higher returns than sell signals, by more than common models of random price movement could explain. It was strong evidence that simple chart rules had captured something real in almost a century of data.

In practice: The study tested rules defined precisely enough to be re-run by anyone. That is exactly the property a supply and demand zone lacks until someone writes it down, and it is why a paper this old is still the reference point.

3. Then the data-snooping correction

Seven years later, Sullivan, Timmermann and White revisited the result in the Journal of Finance. Their question was not whether the rules had worked, but how many rules had been tried before those ones were reported.

They built a universe of 7,846 rules across five families, including support and resistance rules and channel breakouts, and applied White's Reality Check, a bootstrap that asks how good the best rule from a large search would look if none of them had any real power.

Over the decade after 1986, which the original study had not seen, the rules showed little profitability once the full search was accounted for. Later reviews summarise the paper more bluntly: judged against the whole universe of rules that could have been tried, no simple trading rule is reliably profitable on the Dow.

Gotcha: Search enough rules and one will look brilliant by chance. That is data snooping, and it applies to anyone who tries several base lengths and departure sizes until a zone rule backtests well. The fix is to count every variant you tried, not only the one you kept.

4. A direct test of levels, with a control

The closest published test to the zone idea is Carol Osler's July 2000 paper in the Federal Reserve Bank of New York's Economic Policy Review. She took support and resistance levels that firms actually published to their clients for intraday currency trading, and asked how often price stopped when it hit them.

Crucially, she compared them against arbitrary levels, so the baseline rate of reversals was measured rather than assumed.

How often an intraday trend stopped at a level
Share of hits where the trend stopped (% bounced)02040608060.856.2Published support and resistanceArbitrary levels
Source: Osler, FRBNY Economic Policy Review, July 2000

The published levels stopped price 60.8% of the time. Arbitrary levels did so 56.2% of the time. The difference was statistically significant, so the levels carried real information. It was also 4.6 percentage points on top of a baseline that was already above one half.

5. Why a bounce rate is not a profit

Osler's result is often quoted as proof that levels work. It is proof that they carry information, which is a different thing.

Predict first

A trader buys every time price touches a level that bounces 60.8% of the time. Is that a profitable strategy?

The number that decides a strategy is its expectancy: the average result per trade after costs, combining how often it wins, how much it wins and how much it loses.

E=p⋅W−(1−p)⋅L−cE = p \cdot W - (1 - p) \cdot L - c

where pp is the win rate, WW and LL the average win and loss, and cc the cost per trade.

6. What the literature adds up to

Park and Irwin's 2007 survey in the Journal of Economic Surveys is the standard map of this literature. It splits the work into early studies and modern ones, which used more careful testing.

  • Early studies found technical rules profitable in currency and futures markets, but not in stock markets.
  • Modern studies found rules generated economic profits in a variety of speculative markets, at least until the early 1990s.

Of the 95 modern studies, the split was:

ResultStudies
Positive56
Negative20
Mixed19

The authors warned against reading 56 of 95 too literally. Many studies had data-snooping problems, rules were often chosen after seeing the data, and transaction costs and risk were handled unevenly, so the positive results are overstated by an unknown amount.

In practice: The honest summary across all of this work is that simple level-based rules have at times carried real information, most reliably in currencies and at short horizons, and that the effect is small, fragile, and prone to fade once it is widely known or properly tested out of sample.

7. Writing a zone down as code

To test the method you must first remove the judgement. Here is a mechanical demand-zone detector: a base is a run of bars whose ranges are all small relative to recent volatility, and a departure is a large up bar immediately after it. Volatility is measured by the average true range, ATR.

import pandas as pd

def atr(df, n=14):
    prev = df["close"].shift(1)
    tr = pd.concat([df["high"] - df["low"],
                    (df["high"] - prev).abs(),
                    (df["low"] - prev).abs()], axis=1).max(axis=1)
    return tr.rolling(n).mean()

def demand_zones(df, base_len=3, base_max=0.5, depart_min=1.5):
    a = atr(df)
    rng = df["high"] - df["low"]
    zones = []
    for i in range(base_len, len(df)):
        base = slice(i - base_len, i)
        if (rng.iloc[base] < base_max * a.iloc[i]).all():
            bar = df.iloc[i]
            if bar["close"] - bar["open"] > depart_min * a.iloc[i]:
                zones.append({"formed": df.index[i],
                              "top": df["high"].iloc[base].max(),
                              "bottom": df["low"].iloc[base].min()})
    return pd.DataFrame(zones)

Three parameters now stand in for three vague words: base_len for a tight base, base_max for small bars, depart_min for a decisive departure. Run it twice and it draws identical zones.

8. A test design that can actually fail

Each stage removes one way of fooling yourself. Skipping any of them is how most published backtests of chart methods end up looking better than live trading.

flowchart TD
  A["Fix the zone rule and parameters in advance"] --> B["Detect zones on the first part of the data"]
  B --> C["Record every later touch, numbered by touch count"]
  C --> D["Build control levels matched on volatility"]
  D --> E["Compare bounce rates: zones against controls"]
  E --> F["Compute expectancy after spread and costs"]
  F --> G["Repeat once on held-out data, unchanged"]

9. The test only this method proposes

Most of that design applies to any level-based rule. One part belongs to supply and demand trading specifically, and it is the most useful thing you can run.

The method's distinctive claim is that zones weaken with each touch, while classic support and resistance says levels strengthen. Numbering touches in the test above makes that directly measurable: compute the bounce rate for first touches, second touches and third touches separately.

If the data showsIt supports
Bounce rate falls with each touchthe zone method's freshness rule
Bounce rate rises with each touchclassic support and resistance
No pattern, and zones match controlsneither: the zones carry no information

Try it: Run demand_zones on several years of hourly data for one liquid currency pair, fix the parameters before looking at results, and tabulate bounce rate by touch number against volatility-matched random levels. Whatever it shows, you will have tested the claim rather than inherited it.

For the statistical traps in reading the result, the backtesting cursus on why most profitable-looking strategies are not covers selection bias and the deflated Sharpe ratio in detail.

10. A fair conclusion

Put the three lessons together and the picture is neither the one the method's teachers give nor the dismissal it often receives.

Prices do react at particular levels, and the reaction has a mechanism: exit orders that cluster at round numbers and at levels many traders watch, stalling price at the level and cascading through it once it breaks. Rigorous tests have measured that effect. They have also found it to be small, strongest in currencies and at short horizons, and liable to fade out of sample.

The method's own story, of unfilled institutional orders parked at the base of a sharp move, is mostly not how large orders are executed, and its most specific prediction, that zones weaken with each touch, has not been established by the research reviewed here.

Key idea: Treat supply and demand zones as a hypothesis with a partly real mechanism and an untested core claim. The only way to know whether a particular version has an edge after costs is to define it mechanically and test it against a control, on data you did not use to design it.

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. Published support and resistance levels stopped intraday trends 60.8% of the time. Why is that not enough to call them a profitable strategy?
    • The study only covered stock markets
    • Arbitrary levels stopped trends 56.2% of the time, and a bounce rate ignores the size of wins, losses and costs
    • The figure was not statistically significant
    • Support and resistance levels are no longer published by firms
  2. What did Sullivan, Timmermann and White show about the rules tested by Brock, Lakonishok and LeBaron?
    • The rules had never been profitable, even in the original sample
    • The rules became more profitable after 1986
    • Once the full universe of 7,846 rules was accounted for, the rules showed little profitability in the decade after 1986
    • The rules only worked when applied to currency markets
  3. You test 200 combinations of base length and departure size and report the best one. What is the main risk?
    • The best result may be luck selected from a large search, which is data snooping
    • The zones will be drawn differently on each run
    • The average true range will be computed incorrectly
    • The strategy will have too few trades to measure
  4. Which test result would specifically support the zone method's freshness rule?
    • Zones bounce more often than volatility-matched random levels
    • Bounce rates rise with each successive touch of the same level
    • Zones formed on higher timeframes bounce more often
    • Bounce rates fall with each successive touch of the same zone
  5. In Park and Irwin's 2007 survey, what did the early studies find about where technical rules were profitable?
    • In currency and futures markets rather than stock markets
    • In stock markets rather than currency markets
    • Only in studies that ignored transaction costs entirely
    • Equally well across every asset class

Related lessons

Business
intermediate

Supply and demand zones: what the method claims

Supply and demand trading marks price areas where a market left a small base and moved away hard, then trades the return to them. This lesson sets out the method as its practitioners teach it: the four zone patterns, what makes a zone strong, and how entries and stops are placed.

9 steps·~14 min
Business
intermediate

What really sits at a price level: orders, clustering and stops

The supply and demand story says unfilled institutional orders wait at old prices. This lesson checks each part against how orders actually work: order splitting is real, parked leftovers mostly are not, and levels do matter, largely because stop and profit orders cluster at round numbers.

9 steps·~14 min
Programming
beginner

Debugging and Problem Solving: What to Do When Code Breaks

Every program breaks, so learn to fix one fast: the three kinds of error, reading a traceback from the bottom up, the beginner errors and their exact messages, print and debugger techniques for logic bugs, tests with assert, and a problem-solving routine plus a way to keep practising.

10 steps·~15 min
Programming
beginner

Functions, Lists, and Dictionaries: Organising a Program

Split a program into named functions with parameters and return values, and hold data in lists and dictionaries. Learn why return is not print, what local scope protects, the accumulator pattern, how to choose list or dictionary, and the aliasing trap, then build a monthly budget checker.

10 steps·~15 min