/**
 * Moving-window indicators, as pure functions over a series of numbers.
 *
 * Lifted out of apexstock, where the same maths sat behind an OHLC bar shape:
 * every loop read `series[i].y[3]` for the close and `y[1]` / `y[2]` for the
 * high and low. That coupling was an accessor repeated twenty times rather
 * than anything structural, so the generalisation is simply to take the values
 * the caller already has. A stock chart passes its closes, a line chart passes
 * its y values, and neither needs to know about the other.
 *
 * Everything here is windowed and stateless. The streaming twins in apexstock's
 * `IndicatorStep` stay there: they exist for `appendData()` on a live feed, are
 * pinned to the batch versions by an exactness test, and nothing outside that
 * product has a use for them.
 *
 * ## Gaps
 *
 * Every function takes `Array<number | null>` and returns the same length, with
 * null wherever a value is not defined. A window containing a gap yields null
 * rather than an average of however many values happened to be present, which
 * would quietly compute a mean of four and present it beside means of ten. The
 * apexstock originals had no gap handling at all: a null summed to NaN and
 * poisoned the window silently. A charted series has gaps in a way an OHLC feed
 * does not, so the stricter rule travels with the move.
 *
 * @module indicators
 */
/** A value that may be missing, which is what a charted series actually holds. */
type Maybe = number | null;
/**
 * Trailing simple moving average, aligned to the last position in each window.
 *
 * Null for the first `period - 1` positions, which have no complete window
 * behind them, and null for any window containing a gap.
 *
 * ## Why each window is summed from scratch
 *
 * A running sum (add the entering value, subtract the leaving one) computes
 * this in one pass instead of `period` passes, and it is the obvious way to
 * write it. It also makes the result depend on how much history it was given.
 * The accumulator at position i carries the rounding error of every add and
 * subtract before it, so the same window averaged inside a long series and
 * averaged on its own are not the same float, and after rounding for display
 * they are occasionally not the same number either: over a corpus of price-like
 * series, about one value in 140 landed a cent apart.
 *
 * That is a bad property for an indicator. Two charts showing the same window
 * should agree, and a value at position i should be a function of the window at
 * position i and nothing else. Summing from scratch buys exactly that: the
 * result is slice-invariant, which is pinned by a test. It is also what makes a
 * streaming consumer possible at all, since recomputing the tail window is only
 * equal to the batch answer if the batch answer does not depend on its history.
 *
 * The cost is O(n * period) rather than O(n). For the sizes charts actually
 * hold this does not register, and it buys a property that cannot be recovered
 * afterwards.
 */
export declare function sma(values: ReadonlyArray<Maybe>, period: number): Maybe[];
/**
 * Exponential moving average, seeded from the first complete simple window.
 *
 * Seeded rather than started from the first value: starting from a single
 * observation makes the first several outputs mostly an echo of one number,
 * and the choice of seed is visible in the curve for roughly `period`
 * positions. The simple mean of the first window is the conventional seed and
 * is what a spreadsheet or a charting terminal will agree with. It is also what
 * the apexstock original did, so adopting this there is not a change of
 * behaviour, only of where the loop lives.
 *
 * A gap after the seed ends the run: the recursion has no defined value to
 * carry forward, and substituting the previous output would invent an
 * observation. The series restarts at the next complete window.
 */
export declare function ema(values: ReadonlyArray<Maybe>, period: number): Maybe[];
export interface Bands {
    middle: Maybe[];
    upper: Maybe[];
    lower: Maybe[];
}
/**
 * Bollinger bands: a simple moving average with a moving standard deviation
 * either side of it.
 *
 * The band FOLLOWS the data, which is what separates it from a control limit.
 * A control limit is one level computed from the whole series and asks whether
 * the process is stable; this is a window that moves, and asks whether the last
 * few points are unusual relative to the few before them.
 *
 * The deviation is the population form (divided by n, not n-1), because the
 * window is the whole population being described rather than a sample drawn
 * from something larger. That is also the convention every charting package
 * uses for this band, so the numbers agree with what a reader compares them to.
 * Note that it differs from `summarize`, which reports the sample form for
 * exactly the opposite reason.
 */
export declare function bollinger(values: ReadonlyArray<Maybe>, period: number, deviations?: number): Bands;
export {};
//# sourceMappingURL=indicators.d.ts.map