ReadonlyperiodReadonlyplacementWhere the indicator renders (overlay vs. its own pane).
Optional ReadonlypriceWhich price scale an overlay-placement indicator projects through
(B2). 'right' (the default when undefined) is the primary scale
shared with the price series; 'left' binds the indicator to the
independent secondary scale, which the chart enables — reserving the
left axis strip — only while at least one indicator requests it.
Ignored for pane-placement indicators (they own their sub-pane axis).
Subclasses opt in by overriding this getter (or declaring a matching
readonly field).
Stable human-readable identifier, e.g. sma(20) or rsi(14). Used as
the cache key by the IndicatorRegistry and as a label in legends.
Read the buffer and return one or more aligned series. Every returned
Float64Array MUST have the same length as buffer.length so the
renderer can align values with candles index-for-index.
Memoized wrapper around compute. Returns the same cached array
reference while the SAME buffer's version and length are unchanged.
The buffer identity is part of the key so reusing one indicator
instance across two buffers (or swapping a chart's buffer) never
returns another buffer's stale series — important right after init when
distinct buffers can share version: 0 and the same length.
When the data did change but only via a single realtime tick — an
updateLast (same length) or one append (length + 1) on the SAME
buffer with an unmoved head (firstTime unchanged) — and the
subclass provides an updateTail hook, the tail is patched in O(tail)
instead of recomputing the whole series in O(n). firstTime is part
of the key precisely so a prepend/evictHead (which shifts the head
and renumbers every index) can never be mistaken for an append/update
and forces a full recompute.
Use this on render paths; use compute directly to force a fresh
computation.
ProtectedupdateIncremental tail patch. The EMA recurrence
out[i] = close[i]k + out[i-1](1-k)
needs only close[i] and the already-computed out[i-1], so a tick
that touches index i recomputes in O(1) — as long as i lies past
the seed (i > period-1). If the touched index falls on or before
the seed (i <= period-1) the value depends on the SMA-of-first-
period-closes seed rather than a prior EMA, which an incremental
step can't reconstruct, so we return null to force a full recompute.
Exponential Moving Average with multiplier k = 2/(period+1).
Convention: seeded at index
period-1with the SMA of the firstperiodcloses, then continues via recurrence ema[i] = close[i] * k + ema[i-1] * (1-k)Renders as a line overlay on the main price pane.