Appends twelve columns. Nothing is combined: the study is the twelve
averages, and the reading is visual — the short ribbon compressing and
expanding is short-term agreement and disagreement, the long ribbon is the
investor view, and the two crossing while the long ribbon stays spread is
Guppy's trend-change signal. A chart draws them as a ribbon; the data
layer's job is the twelve columns.
The twelve periods are the study — there is no "which periods" option
They are named, published constants (exported as
GUPPY_SHORT_PERIODS / GUPPY_LONG_PERIODS so a chart can
label the ribbon without restating them), and a periods option would make
guppy() a generic "stack of moving averages" wearing Guppy's name. A
caller who wants their own stack has movingAverage called as many
times as they like with their own output names — clearer at the call site
and honest about not being GMMA. The one knob that is Guppy-compatible is
which average (chart platforms ship the stack on simple averages too), so
type takes the whole shared MaType menu and defaults to 'ema'.
type, not maType: the appended columns are the moving averages, as
movingAverage's are. The maType spelling is for the studies where
an average is an ingredient of something else (keltner,
disparityIndex, envelope, movingAverageDeviation).
Definition, verified
TA-Lib has no GMMA, but it has EMA at every one of the twelve periods,
so the oracle checks each column against talib.MA rather than only the
assembly. As everywhere else in the package the EMAs are pond's — seeded on
the first sample, not on the SMA of the first n (the macd
precedent) — so the generator splits the question the way the K2 engine's
own case does: the formula is rebuilt on TA-Lib's SMA seed and required
to agree bit-exactly, and pond's seed transient is then required to be
exactly geometric at (1 − α), which is what the difference of two
EMAs sharing a rate must be.
The usual "decayed to under 0.5% of scale over the last 20 bars" bound
cannot be used at period 60: only 21 bars of the 80-bar fixture are
shared, so the transient has not finished decaying and is still 0.367%
at the last bar (measured). The geometric check is the stronger statement
anyway — a wrong α leaves a residue 1e12× larger (measured: 3.15
relative against 1e-12 for the correct rate).
Warm-up — per column, and that is the point
Each column starts where its own average does: on gap-free input and
type: 'ema', ${prefix}S3 at bar 2 and ${prefix}L60 at bar 59, with
the ten others in between. Masking the ribbon back to its slowest member
would discard 57 real values of the fastest one, and the ribbon's whole
reading is how the members sit relative to each other as they arrive.
Other types move every column together, per the table on
movingAverageValues (dema twice as late, hull and kama later
again).
Edges
Linear in price, not scale-invariant: every column is a moving
average, so scaling the input scales all twelve and shifting it shifts
all twelve (both pinned as property tests).
A leading gap shifts each column's start for every type except
'sma', which keeps sma()'s row-counting window — the column door's
documented asymmetry.
An interior gap costs whatever the chosen type costs, per column:
ema skips the bar, the window types recover once it leaves the window,
smma and kama propagate to the end.
Twelve columns is twelve passes. At 1M bars guppy() costs roughly
twelve ema() calls (measured — see scripts/perf-studies.mjs); there is
no shared work between periods to save.
Guppy Multiple Moving Average (Daryl Guppy, Trend Trading) — two ribbons of six exponential averages each, plotted together:
Appends twelve columns. Nothing is combined: the study is the twelve averages, and the reading is visual — the short ribbon compressing and expanding is short-term agreement and disagreement, the long ribbon is the investor view, and the two crossing while the long ribbon stays spread is Guppy's trend-change signal. A chart draws them as a ribbon; the data layer's job is the twelve columns.
The twelve periods are the study — there is no "which periods" option
They are named, published constants (exported as GUPPY_SHORT_PERIODS / GUPPY_LONG_PERIODS so a chart can label the ribbon without restating them), and a
periodsoption would makeguppy()a generic "stack of moving averages" wearing Guppy's name. A caller who wants their own stack has movingAverage called as many times as they like with their ownoutputnames — clearer at the call site and honest about not being GMMA. The one knob that is Guppy-compatible is which average (chart platforms ship the stack on simple averages too), sotypetakes the whole shared MaType menu and defaults to'ema'.type, notmaType: the appended columns are the moving averages, as movingAverage's are. ThemaTypespelling is for the studies where an average is an ingredient of something else (keltner,disparityIndex,envelope,movingAverageDeviation).Definition, verified
TA-Lib has no GMMA, but it has
EMAat every one of the twelve periods, so the oracle checks each column againsttalib.MArather than only the assembly. As everywhere else in the package the EMAs are pond's — seeded on the first sample, not on the SMA of the firstn(the macd precedent) — so the generator splits the question the way the K2 engine's own case does: the formula is rebuilt on TA-Lib's SMA seed and required to agree bit-exactly, and pond's seed transient is then required to be exactly geometric at(1 − α), which is what the difference of two EMAs sharing a rate must be.The usual "decayed to under 0.5% of scale over the last 20 bars" bound cannot be used at
period 60: only 21 bars of the 80-bar fixture are shared, so the transient has not finished decaying and is still 0.367% at the last bar (measured). The geometric check is the stronger statement anyway — a wrongαleaves a residue 1e12× larger (measured: 3.15 relative against 1e-12 for the correct rate).Warm-up — per column, and that is the point
Each column starts where its own average does: on gap-free input and
type: 'ema',${prefix}S3at bar 2 and${prefix}L60at bar 59, with the ten others in between. Masking the ribbon back to its slowest member would discard 57 real values of the fastest one, and the ribbon's whole reading is how the members sit relative to each other as they arrive. Othertypes move every column together, per the table on movingAverageValues (dematwice as late,hullandkamalater again).Edges
typeexcept'sma', which keepssma()'s row-counting window — the column door's documented asymmetry.typecosts, per column:emaskips the bar, the window types recover once it leaves the window,smmaandkamapropagate to the end.guppy()costs roughly twelveema()calls (measured — seescripts/perf-studies.mjs); there is no shared work between periods to save.