Skip to content
Level 1 · Chart ReaderLessonPart 06 · page 7 of 1122 min
22Minutes
5AFL functions
5Sources
StandardRequires
AFL functions taught here5

The Stochastic Oscillator

The stochastic oscillator answers one question: where did the market close, relative to the range it has been trading in? That is a genuinely different question from the one RSI asks, and it comes with a different failure mode — one that has nothing to do with trends and everything to do with division.

The published construction of the raw oscillator is a position within a range. Take the highest high and the lowest low of the last n bars. Ask where today’s close sits between them, as a percentage. A close at the top of the range gives 100, a close at the bottom gives 0, a close halfway gives 50.

In AFL primitives that is:

Fragment — not a complete formula

// The textbook raw %K, built from documented parts.
Period = 14;
RangeHigh = HHV( High, Period );
RangeLow = LLV( Low, Period );
RawK = 100 * ( Close - RangeLow ) / ( RangeHigh - RangeLow );

That expression contains the whole indicator and, if you look at it for a moment, both of its weaknesses. The numerator is bounded above by the denominator, so the result is confined to 0 to 100 — another bounded oscillator, with the same obligation to saturate. And the denominator is a range, which can become very small.

Raw %K jumps around violently, so the published indicator smooths it, and then smooths the smoothing:

Stage What it is The AmiBroker function
Raw %K Position of the close within the n-bar range none — build it from HHV and LLV, or pass ksmooth = 1
Slow %K Raw %K averaged over KSmooth bars StochK( periods = 14, ksmooth = 3 )
Slow %D Slow %K averaged over DSmooth bars StochD( periods = 14, Ksmooth = 3, Dsmooth = 3 )

The stage that many other platforms call fast %D is the stage AmiBroker calls StochK.

The standard readings, again as convention rather than finding:

  • Above 80 is called overbought, below 20 oversold.
  • %K crossing above %D is read as a turn upward, and the reverse downward.
  • Those crossings are said to “count for more” when they happen in the outer bands.
  • Divergence between the oscillator and price is read the same way it is for MACD, with the same methodological problems described in that lesson.

The two limitations that come from the construction

Section titled “The two limitations that come from the construction”

It saturates in a trend, for the same reason RSI does

Section titled “It saturates in a trend, for the same reason RSI does”

A market advancing steadily closes near the top of its recent range most days, so %K sits near 100 most days. This is not the indicator warning you about anything; the close being near the high of the last fourteen bars is what an advance is. Expect long stretches pinned in the upper band during a trend, and expect the crossings inside that band to be numerous and mostly meaningless.

It becomes hypersensitive when the range is small

Section titled “It becomes hypersensitive when the range is small”

This one is specific to the stochastic and worth more attention than it usually gets. The denominator is HHV( High, n ) - LLV( Low, n ). In a very quiet market that number becomes tiny, and a tiny denominator turns a trivial price change into a full-scale swing of the oscillator.

Consider an instrument whose fourteen-day range is 0.4 per cent of its price. A move of 0.1 per cent — noise, a rounding of the closing auction, a slightly wider spread — travels a quarter of the whole oscillator scale. %K swings from 20 to 90 and back while the chart looks like a flat line.

A third, milder point: because the range is built from HHV and LLV, a single extreme bar fixes the denominator for n bars and then drops out abruptly. The oscillator can jump on a quiet day because an old spike left the window. This is the same drop-out artefact as a simple moving average, but sharper, because an extreme moves the whole range rather than one fourteenth of an average.

Fast, slow, and why the naming is such a mess

Section titled “Fast, slow, and why the naming is such a mess”

The historical vocabulary is genuinely confusing, and it is worth untangling once rather than being caught by it repeatedly.

“Fast stochastic” originally meant the pair raw %K and a short average of raw %K. That was found to be too jittery to look at, so the convention shifted: take the smoothed line as the new %K, and average it again for the new %D. That second pair is the “slow stochastic”. The line in the middle — the average of raw %K — therefore has two names depending on which pair you are talking about: it is the fast %D and it is the slow %K. They are the same numbers.

AmiBroker resolved the ambiguity by shipping only the slow pair and naming them plainly. So StochK gives you that middle line, and StochD gives you the average of it. If a description elsewhere refers to “%K” and you cannot tell which stage is meant, count the smoothings — that is the only thing that distinguishes them.

Choosing the lookback is the same trade-off as choosing any window. A shorter periods narrows the range being measured, so the close reaches the edges of it more often and the oscillator spends more time saturated. A longer one measures position within a wider range, which changes the meaning of “near the top” considerably: the top of a 5-day range and the top of a 60-day range are different statements about the market. Write the period down whenever you quote a reading.

It is a 0-to-100 oscillator, so it needs its own pane. Insert it by double-clicking the entry in Window -> Charts, or apply a formula. The Parameters window’s Axes & Grid tab offers 20/80 among its fixed grid levels, which is the usual pair for this indicator and saves you writing them.

From a formula:

Fragment — not a complete formula

Period = Param( "Stochastic period", 14, 2, 100, 1 );
KSmooth = Param( "K smoothing", 3, 1, 20, 1 );
DSmooth = Param( "D smoothing", 3, 1, 20, 1 );
SlowK = StochK( Period, KSmooth );
SlowD = StochD( Period, KSmooth, DSmooth );
Plot( SlowK, "%K", colorBlue, styleLine | styleThick );
Plot( SlowD, "%D", colorRed, styleLine );
PlotGrid( 80, colorGrey40, 9, 1, True );
PlotGrid( 20, colorGrey40, 9, 1, True );
PlotGrid( 50, colorGrey40, 8, 1, False );

Checking what the function actually returns

Section titled “Checking what the function actually returns”

AmiBroker does not document the type of averaging used for the internal smoothing, nor the warm-up length. So verify rather than assume:

Fragment — not a complete formula

Period = 14;
RawK = 100 * ( Close - LLV( Low, Period ) ) / ( HHV( High, Period ) - LLV( Low, Period ) );
Plot( RawK, "Hand-built raw %K", colorGrey40, styleLine );
Plot( StochK( Period, 1 ), "StochK(14, 1)", colorBlue, styleLine | styleThick );
Plot( StochK( Period ), "StochK(14) default", colorRed, styleLine );
PlotGrid( 80, colorGrey40, 9, 1, True );
PlotGrid( 20, colorGrey40, 9, 1, True );

The conventional claim attaches meaning to a threshold, which imports an arbitrary number into the hypothesis. Avoid that by bucketing instead:

On my universe, over my chosen period, do 10-day forward returns differ between bars where slow %K closed in the bottom fifth of its range, the middle three fifths, and the top fifth?

Three buckets instead of one threshold does two useful things. It removes the argument about whether the line should be at 80 or at 75. And it shows you the shape of the relationship — whether returns change smoothly across the range, jump at the edges, or do nothing at all — rather than collapsing everything into a single yes-or-no comparison.

You should also record how many bars land in each bucket. In a trending instrument the top bucket may hold ten times as many bars as the bottom one, and an average computed from a handful of observations is not comparable to one computed from hundreds. The last lesson of this part builds a test of exactly this shape and spends as much time on reading the result as on producing it.

The stochastic oscillator measures where the close sits inside the highest-high to lowest-low range of the last n bars. AmiBroker’s StochK( periods = 14, ksmooth = 3 ) is the slow %K — already internally smoothed — and StochD( periods = 14, Ksmooth = 3, Dsmooth = 3 ) is the slow %D, double smoothed; neither takes an input array, and the internal averaging method and warm-up are undocumented. It saturates in trends, like every bounded oscillator, and it becomes hypersensitive when the recent range is small, because the range is the denominator. Build the raw version from HHV and LLV once, compare it against the built-in, and you will never again be confused about which of the three stages you are looking at.

Check your understanding

Question 1. What does StochK( 5 ) return in AmiBroker?
Show the answer and why

Answer: A 5-period %K slowed down 3 periods

AmiBroker’s StochK is the slow %K. Its page is titled "stochastic slow %K" and its own example states that stochk( 5 ) returns a 5-period %K slowed down 3 periods, because ksmooth defaults to 3. Pass StochK( 5, 1 ) if you want the unsmoothed version.

Question 2. An instrument has traded in a 0.4 per cent range for three weeks. Its slow %K swings repeatedly between 15 and 90. What is happening?
Show the answer and why

Answer: The denominator HHV(High,n) - LLV(Low,n) is very small, so tiny price changes travel most of the scale

The stochastic divides by the recent range. When that range is small, noise fills the scale. This is the failure mode specific to range-normalised oscillators and it is easiest to spot by looking at price rather than at the indicator.

Question 3. Which pair of calls computes %K and %D from the same underlying lookback and slowing?
Show the answer and why

Answer: StochK( 20, 5 ) and StochD( 20, 5, 3 )

StochD takes periods, Ksmooth and Dsmooth. Passing only the first argument leaves Ksmooth at 3, so it would be smoothing a differently slowed %K from the one you plotted. Parameterise both calls from the same variables.

Question 4. Why does this lesson suggest testing forward returns across three %K buckets rather than against a single 80 threshold?
Show the answer and why

Answer: Because bucketing removes an arbitrary parameter and reveals the shape of the relationship rather than one yes-or-no answer

A single threshold imports a free parameter into the hypothesis and hides whether the effect changes gradually or only at the extremes. Buckets also make the sample size in each group visible, which is essential when one group is far larger than another.

Sources for this lesson

5 verified · checked 2026-08-31

  1. 01AFL Function Reference — StochKamibroker.com/guide/afl/stochk.html2026-08-31
  2. 02AFL Function Reference — StochDamibroker.com/guide/afl/stochd.html2026-08-31
  3. 03AFL Function Reference — HHVamibroker.com/guide/afl/hhv.html2026-08-31
  4. 04AFL Function Reference — LLVamibroker.com/guide/afl/llv.html2026-08-31
  5. 05AmiBroker User's Guide — Parameters window§ Grid levelsamibroker.com/guide/w_param.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.