feature

Remembering values across bars

Scripts often need memory across bars — an EMA, a session open, a “was above yesterday” flag. That memory belongs in ctx.accum, not in a module-level let.

If you skip this, lint fails and your values reset or behave unpredictably. Use this page whenever a calculation depends on what happened on earlier bars.

Signature

// Indicator
ctx.accum<T>(id: string, init: T, update: (prev: T) => T): T

// Definition — init may be a value or a thunk
ctx.accum<T>(id: string, init: T | (() => T), update: (prev: T) => T): T

Example

function onBar(ctx) {
  const k = 2 / (ctx.params.length + 1);
  const ema = ctx.accum("ema", null, (prev) =>
    prev == null ? ctx.close : prev + k * (ctx.close - prev)
  );
  ctx.plot("ema", ema);
}

Rules

  • Stable string id per accumulator

  • Return the next value from update (do not rely on mutating shared objects unless you understand the runtime)

  • Studies: no ctx.accum — use ctx.collect across events instead

Agent note

Inventing let ema = … at module scope is the most common agent mistake on indicators and definitions.

Next

  1. Settings inputs and dialog

  2. Price and bar data