Market Structure: Trends, Ranges and Transitions
“The trend is up” is the most frequently asserted sentence in technical analysis and one of the least often defined. This lesson gives it a definition, applies the definition mechanically, and then does the thing that most treatments skip: shows you what the definition is resting on, so that when someone disagrees with your classification you can find out whether you disagree about the market or merely about the parameters.
By the end you will be able to classify any chart into one of three states using a stated rule, state how late that classification necessarily is, and use the regime vocabulary that Parts 12, 27 and 35 depend on.
The four comparisons
Section titled “The four comparisons”Take the confirmed swing points from the previous lesson and line them up in time. The structure vocabulary is built from exactly four comparisons between consecutive swings of the same kind:
| Comparison | Meaning |
|---|---|
| Higher high | The latest confirmed swing high is above the one before it |
| Higher low | The latest confirmed swing low is above the one before it |
| Lower high | The latest confirmed swing high is below the one before it |
| Lower low | The latest confirmed swing low is below the one before it |
Combining them gives the familiar labels. Higher highs and higher lows together are what most people mean by an uptrend. Lower highs and lower lows together are a downtrend. And the combinations that are left over — higher highs with lower lows (expanding), lower highs with higher lows (contracting), and every case where one comparison is a tie — are not trends at all.
That last group is the interesting one, because it is where a great deal of market time actually sits, and because most chart commentary quietly reassigns it to whichever trend the commentator already believed in.
Drawn, the four comparisons stop being vocabulary and become two things you can measure with a ruler:
Higher highs and higher lows
- Close above open
- Close below open
- Swing high
- Swing low
Show the numbers behind this chart
| Bar | Open | High | Low | Close |
|---|---|---|---|---|
| 1 | 100 | 101 | 99 | 100 |
| 2 | 100 | 102 | 100 | 102 |
| 3 | 102 | 104 | 102 | 104 |
| 4 | 104 | 107 | 104 | 106 |
| 5 | 106 | 106 | 105 | 105 |
| 6 | 105 | 105 | 103 | 103 |
| 7 | 103 | 103 | 101 | 101 |
| 8 | 101 | 103 | 101 | 103 |
| 9 | 103 | 106 | 103 | 106 |
| 10 | 106 | 109 | 106 | 109 |
| 11 | 109 | 112 | 109 | 111 |
| 12 | 111 | 111 | 109 | 109 |
| 13 | 109 | 109 | 107 | 107 |
| 14 | 107 | 107 | 105 | 105 |
| 15 | 105 | 108 | 105 | 108 |
| 16 | 108 | 111 | 108 | 111 |
| 17 | 111 | 114 | 111 | 114 |
| 18 | 114 | 117 | 114 | 116 |
What the label asserts, and what it does not
Section titled “What the label asserts, and what it does not”Read the definition again and notice how modest it is. “Higher highs and higher lows” is a statement about two pairs of numbers taken from the past. It asserts that the most recent confirmed swing high exceeded the previous one and the most recent confirmed swing low exceeded the previous one. That is all it says.
It does not say the next swing will also be higher. It does not say a rise is more likely than a fall from here. It does not say anything about how long the condition will persist. Those are all separate claims — some of them testable, none of them contained in the classification itself.
Ranges are a real answer, not a failure to classify
Section titled “Ranges are a real answer, not a failure to classify”A range is what you have when the swing highs and swing lows are not consistently moving in the same direction. It deserves a name of its own for a practical reason: almost every technique that works on directional structure behaves differently inside a range, and many behave badly. Moving-average crossovers whipsaw. Breakout entries fail repeatedly at the same level. Momentum oscillators oscillate, which is when they look most convincing and mean least.
There is no bright line between “trend” and “range”, and pretending otherwise is where
a lot of self-deception starts. What you can do is refuse to force a third answer into
one of the first two. The formula in this lesson has an explicit third label,
Unclassified, and on most instruments it is on screen more often than either
directional label. That is not the formula being unhelpful. That is the chart.
Structure breaks
Section titled “Structure breaks”A structure break is the bar on which the pattern of comparisons changes: the first lower low after a run of higher lows, or the first higher high after a run of lower highs. It is the transition, and it is the thing traders most want to catch early.
Two cautions travel with it.
First, it is an event in the precise sense the course uses that word, whereas the classification either side of it is a state. The distinction sounds pedantic here and becomes the difference between a working formula and a broken one in Part 9. A state is true over a span of bars; an event is the bar on which something became true. Asking “is the structure up?” and asking “did the structure just turn up?” are different questions requiring different code.
Here is the same series continued. Nothing about the first eighteen bars has changed; the chart is longer, and one comparison has flipped.
The same series, eight bars later
- Close above open
- Close below open
- Swing high
- Swing low
- Lower low - the structure break
Second, a structure break is only as timely as the swings it is made of. If your swing strength is 5, the lower low that constitutes the break was confirmed 5 bars after it happened — and the “break” you are reacting to is therefore at least 5 bars old before you ever see it.
What an “uptrend” claim actually rests on
Section titled “What an “uptrend” claim actually rests on”The layers under one word
- "The trend is up"What gets said out loud
- Comparison of the last two of each swingHigher high AND higher lowno free parameters
- Set of confirmed swing pointsOne Boolean per barlagged by n bars
- Swing definition and its strength nChosen by you, not by the marketthe free parameter
- Price series at one intervalDaily, weekly, 5-minute…also chosen by you
- The trades that actually happenedThe only layer that is not a choice
This diagram is the argument of the lesson. When someone says a chart is in an uptrend and you think it is not, the productive question is never “who is right?” It is “what swing strength and what interval are you using?” More often than not the disagreement dissolves, and when it does not, you have learned something specific about how sensitive the conclusion is.
The regime vocabulary this course uses
Section titled “The regime vocabulary this course uses”From here on, these words carry fixed meanings. They are used consistently in every later part, and the later parts will not redefine them.
| Term | Meaning in this course |
|---|---|
| Market regime | A classification of overall market conditions, used as a gate on whether to act at all |
| State | A condition true over a span of bars, such as higher highs and higher lows |
| Event | The single bar on which something became true, such as a structure break |
| Setup | The conditions that make an instrument a candidate |
| Trigger | The specific event that turns a candidate into an entry |
| Timeframe | The conceptual horizon, such as weekly context with daily setups |
| Interval | The concrete bar size — inDaily, five-minute — as AmiBroker means it |
The distinction between timeframe and interval matters more than it looks. “I trade the
daily timeframe” is a statement about horizon; inDaily is a setting. Part 14 spends a
whole part on the machinery for using two intervals at once without accidentally
reading the future.
The formula
Section titled “The formula”Take the confirmed swing points, keep the last two of each kind, apply the four comparisons, and display the resulting label continuously — in words, and as a background ribbon — together with the four swing prices the label was derived from. The purpose is not to have a trend indicator. It is to make your visual classification falsifiable: when the ribbon disagrees with your eye, one of you is applying a different rule, and now you can find out which.
Complete formula
Section titled “Complete formula”Complete runnable AFL
// market-structure.afl// Part 4 - Market Structure: Trends, Ranges and Transitions//// Classifies the chart into one of three labels using the confirmed swing// points from the previous lesson://// higher highs and higher lows -> "up structure"// lower highs and lower lows -> "down structure"// anything else -> "unclassified"//// The classification is a definition applied consistently. It describes what// the recent swing points did. It says nothing about what comes next.//// Assumptions:// - Swing strength is the only free parameter. Change it and the labels// change; comparing two settings is the honest way to use this formula.// - Every label is late by at least Strength bars, because a swing point// cannot be confirmed until Strength bars have printed after it.// - "Unclassified" is a real answer and, on most instruments, a common one.
_SECTION_BEGIN("Market structure");
Strength = Param( "Swing strength (bars either side)", 5, 1, 25, 1 );Window = 2 * Strength + 1;
BarNumber = Cum( 1 );HasWindow = BarNumber >= Window;
CandidateHigh = Ref( High, -Strength );CandidateLow = Ref( Low, -Strength );
SwingHigh = HasWindow AND CandidateHigh == HHV( High, Window );SwingLow = HasWindow AND CandidateLow == LLV( Low, Window );
// ValueWhen's third argument selects the n-th most recent occurrence:// 1 is the latest, 2 is the one before it. Two of each is the minimum needed// to say whether highs and lows are rising or falling.HighNow = ValueWhen( SwingHigh, CandidateHigh, 1 );HighPrev = ValueWhen( SwingHigh, CandidateHigh, 2 );LowNow = ValueWhen( SwingLow, CandidateLow, 1 );LowPrev = ValueWhen( SwingLow, CandidateLow, 2 );
HigherHigh = HighNow > HighPrev;HigherLow = LowNow > LowPrev;LowerHigh = HighNow < HighPrev;LowerLow = LowNow < LowPrev;
UpStructure = HigherHigh AND HigherLow;DownStructure = LowerHigh AND LowerLow;
Plot( Close, "Price", colorDefault, styleCandle );
// The ribbon is a convenience, not the message. Colour is never the only way to// read the classification here: the title states it in words as well, which is// also what makes the chart usable by a reader who cannot distinguish the hues.RibbonColour = IIf( UpStructure, colorPaleGreen, IIf( DownStructure, colorRose, colorLightGrey ) );
Plot( 2, "Structure", RibbonColour, styleOwnScale | styleArea | styleNoLabel | styleNoTitle, -0.5, 100 );
StructureText = WriteIf( UpStructure, "Higher highs and higher lows", WriteIf( DownStructure, "Lower highs and lower lows", "Unclassified - the swings disagree" ) );
_N( Title = Name() + " - " + Interval( 2 ) + StrFormat( " - structure at swing strength %g\n", Strength ) + StructureText + "\n" + StrFormat( "Swing highs: %g then %g\n", HighPrev, HighNow ) + StrFormat( "Swing lows: %g then %g\n", LowPrev, LowNow ) + StrFormat( "This label could not have been known until %g bars " + "after the newer swing formed.", Strength ) );
_SECTION_END();How it works
Section titled “How it works”The first half is the swing detector from the previous lesson, unchanged. The second half is new and short.
ValueWhen() takes a condition, an array, and an occurrence number. Called with 1 it
gives the value the array had at the most recent bar where the condition was true;
called with 2, the occurrence before that. Four calls therefore give the last two
confirmed swing highs and the last two confirmed swing lows, each carried forward
across every bar until a newer one replaces it — a step-shaped series, which is exactly
what a classification needs.
The four comparisons are then plain array comparisons producing one Boolean per bar,
and the two labels are AND combinations of them. Anything that is neither is left
unlabelled rather than being assigned to the nearest available trend.
The ribbon uses the documented idiom from AmiBroker’s own styles tutorial: plot a
constant with styleOwnScale | styleArea, where the constant is the ribbon height as a
percentage of the pane, and pass a colour array rather than a colour, so the colour
changes bar by bar. The minimum and maximum arguments are only used by
styleOwnScale plots, which is why they appear here and nowhere else in the part.
Key functions
Section titled “Key functions”ValueWhen( expression, array, n )— condition first, then the array, then which occurrence. The official page notes thatnalso accepts zero and negative values, which reference future occurrences; that is a look-ahead trap, and this formula uses only 1 and 2.WriteIf( expression, "true text", "false text" )returns one of two strings. Despite the name it writes nothing; it is a conditional text chooser, and nesting two of them gives the three-way label.Plot( array, name, colour, style, minvalue, maxvalue )— the fifth and sixth arguments are documented as being used bystyleOwnScaleplots, which is what makes the ribbon sit at a fixed height regardless of the price scale.IIf( condition, valueIfTrue, valueIfFalse )selects element-wise, per bar. Nested here to build the three-colour array.
Expected result
Section titled “Expected result”Test it
Section titled “Test it”Do not test this by looking at whether it “gets the trends right” — that judgement is exactly the subjective thing the formula exists to replace. Test it against its own definition:
- Select a bar where the label is “higher highs and higher lows”. Read the four swing prices from the title. Confirm by arithmetic that the newer high exceeds the older and the newer low exceeds the older.
- Find a bar where the label is “unclassified” and read the four prices. Confirm that at least one of the two comparisons fails.
- Find the exact bar where the label changes. Confirm that a new swing was confirmed on that bar — the label can only change when new information about a swing arrives.
Common errors
Section titled “Common errors”- The ribbon is grey for the entire chart. Almost always too few confirmed swings:
either the strength is too high for the loaded history, or you are looking at fewer
bars than
4 × Strengthand the second occurrence of a swing does not exist yet. - The label changes on a bar with no new swing. It cannot, by construction. If it appears to, you are reading the ribbon at a different bar from the title — the title reports the selected bar, and with no selection it reports the last visible bar.
- The ribbon covers the candles. Plot order inside a Z-order layer runs in reverse call order by default, so the last plot in the code is drawn furthest back. If you reorder the plots and the ribbon comes forward, that is why.
ValueWhenarguments swapped.ValueWhen( CandidateHigh, SwingHigh )compiles perfectly and returns nonsense. The condition always comes first.
Extension
Section titled “Extension”Add a second classification using a different swing strength — 3 alongside 10 — and plot both ribbons in separate thin bands. The bars where the two disagree are the honest answer to “is this a trend?”, which is: it depends on the scale you are asking about, and here is exactly where that matters.
Run it twice before you believe it
Section titled “Run it twice before you believe it”Whatever the ribbon says at strength 5, run it again at strength 2 and at strength 12 on the same chart, and note the three answers.
If all three agree, you have a classification that is robust to the parameter, and you can quote it with some confidence. If they disagree, you have learned that the label is an artefact of a setting rather than a description of the instrument, and the correct thing to say out loud is “unclear at this scale” rather than picking the setting whose answer you preferred.
This two-line habit — vary the parameter, report the spread of answers — is the cheapest robustness check in the whole course, and it generalises directly to optimisation in Part 31, where the same idea appears in a much more expensive form.
What changed
Section titled “What changed”You now have a three-way classification built from four comparisons between confirmed swing points, and you know precisely what it rests on: an interval you chose, a swing strength you chose, and arithmetic that has no opinions. You know it is late by at least the swing strength, that the third category is not a failure, and that the way to settle a disagreement about a chart is to compare parameters rather than convictions.
The lab that follows turns all of this into a procedure with an order and an output, so that reading a chart becomes something you do the same way twice.
Check your understanding
Sources for this lesson
4 verified · checked 2026-08-31
- 01AFL Function Reference — ValueWhenamibroker.com/guide/afl/valuewhen.html2026-08-31
- 02AFL Function Reference — WriteIfamibroker.com/guide/afl/writeif.html2026-08-31
- 03AFL Function Reference — Plot§ style constantsamibroker.com/guide/afl/plot.html2026-08-31
- 04AmiBroker User's Guide — Using colors, styles, titles and parameters in indicators§ Ribbon exampleamibroker.com/guide/h_indbuilder2.html2026-08-31
Every technical claim on this page was checked against the official AmiBroker documentation on the date shown. Where the course disagrees with folklore, the source is how you can tell which one to trust.