Quickstart: Node
Verified against the Rust reference. Every one of Wickra's 514 indicators is replayed through all 10 languages and checked bit-for-bit against the Rust core's golden fixtures in CI — the math here is provably identical to every other binding (how).
A five-minute tour of the Wickra Node.js binding. The binding is generated by napi-rs, so it's a native addon — no WASM, no slow JS reimplementation.
Install
npm install wickraWindows install (0.2.1+ x64, 0.2.7+ arm64). Earlier patch releases were blocked on Windows because the platform-specific sub-packages (
wickra-win32-x64-msvc,wickra-win32-arm64-msvc) were held back by npm's automated spam filter, sorequire('wickra')threwError: Cannot find module 'wickra-win32-<arch>-msvc'after a successfulnpm install. npm Support released the x64 name on 2026-05-22 (first usable from0.2.1) and the arm64 name on 2026-05-24 (first usable from0.2.7). Burned version numbers cannot be republished — see the npm registry pages for the two sub-packages. Linux x64, Linux arm64 and macOS (x64 + arm64) were unaffected throughout.
A first run
const wickra = require('wickra');
console.log('wickra', wickra.version());
// Simple moving average over a fixed window.
const sma = new wickra.SMA(3);
console.log(sma.batch([2, 4, 6, 8, 10]));
// -> [ NaN, NaN, 4, 6, 8 ]Two things to notice:
- The
batchreturn type is a regular JavaScriptArray<number>. Warmup slots areNaN, notnullorundefined, so the array isNumber.isFinite-checkable in one pass. new wickra.SMA(0)does not throw. Constructors in the Node binding currently cannot raise errors from JS (a napi-rs 2.16 limitation), so pathological values likeperiod = 0are clamped to the smallest valid window. This is exactly the behaviour pinned bybindings/node/__tests__/smoke.test.js("zero period is clamped to a valid window").
Streaming
const wickra = require('wickra');
const sma = new wickra.SMA(3);
for (const price of [2, 4, 6, 8, 10]) {
const value = sma.update(price);
console.log('update', price, '->', value);
}Output:
update 2 -> null
update 4 -> null
update 6 -> 4
update 8 -> 6
update 10 -> 8update returns either a JavaScript number or null while the indicator is still warming up. (Compare with batch, where warmup slots are NaN. The asymmetry exists because the streaming API surfaces "no value yet" through the JS type system, whereas the batch result is shaped as a numeric array for downstream numeric code.)
MACD: streaming and batch
MACD is the canonical multi-output indicator. The Node API surfaces this in two shapes:
update(price)returns eithernull(during warmup) or{ macd, signal, histogram }.batch(prices)returns a flatArray<number>of lengthprices.length * 3, laid out as[macd_0, signal_0, hist_0, macd_1, signal_1, hist_1, ...], with each warmup row written as threeNaNs.
Streaming form:
const wickra = require('wickra');
const macd = new wickra.MACD(12, 26, 9);
let last = null;
for (let i = 0; i < 40; i++) {
last = macd.update(100 + i * 0.5);
}
console.log(last);
// -> { macd: 3.5, signal: 3.500000000000001, histogram: -8.881784197001252e-16 }Batch form (note the flat layout):
const wickra = require('wickra');
const prices = Array.from({ length: 40 }, (_, i) => 100 + i * 0.5);
const macd = new wickra.MACD(12, 26, 9);
const flat = macd.batch(prices);
console.log('total values:', flat.length); // -> 120 (= 40 * 3)
console.log('row 33 :', flat.slice(99, 102)); // -> [ 3.5, 3.5, 0 ]
console.log('row 39 :', flat.slice(117, 120)); // -> [ 3.5, 3.5000000..., -8.88e-16 ]
// Reshape into 3-tuples if you want:
const rows = [];
for (let i = 0; i < flat.length; i += 3) {
rows.push({ macd: flat[i], signal: flat[i + 1], histogram: flat[i + 2] });
}MACD(12, 26, 9) emits its first non-NaN row at index 33 because the underlying Rust warmup_period() is slow + signal − 1 = 34 (the first ready row is warmup_period - 1 in 0-indexed terms).
The opt-in fast batch
Every batch accepts a Float64Array (read in place, without a copy) as well as a plain array. The single-output indicators — plus MACD, MACDFIX, Bollinger Bands, ATR, the Chaikin oscillator and Pearson correlation — add batchFast, which returns a Float64Array, and batchInto / batchFastInto, which write into one you reuse:
const input = Float64Array.from(prices);
const out = new Float64Array(input.length);
const fast = new wickra.EMA(20).batchFast(input); // Float64Array, NaN during warmup
new wickra.SMA(20).batchInto(input, out); // exact, no allocation
new wickra.EMA(20).batchFastInto(input, out);batch itself still returns a plain Array. The output of the Into forms must be as long as the result, must not overlap an input and must not be backed by a SharedArrayBuffer.
The fast batch runs a SIMD kernel where the indicator has one (moving averages, RSI, ATR, MACD and MACDFIX, Bollinger Bands, the Chaikin oscillator, skewness, Pearson correlation and more). The kernel reassociates the arithmetic, so each value agrees with the exact batch to within a few units in the last place rather than bit for bit; NaN placement and length are identical, and the result is the same on every platform. Where an indicator has no kernel, the fast batch is the exact batch. Keep the exact batch wherever you compare against streaming bit for bit; reach for the fast one when throughput is the point. See Streaming vs Batch.
API surface
The complete TypeScript definitions live at bindings/node/index.d.ts. Every indicator class exposes some subset of:
| Member | Notes |
|---|---|
constructor(...) | Pathological values are clamped, not thrown. |
update(...) | Returns the indicator output or null during warmup. |
batch(...) | Single-output: flat Array<number> with NaN warmup.Multi-output: flat interleaved Array<number>. |
reset() | Returns to a freshly-constructed state. |
isReady() | true once the first value has been emitted. |
warmupPeriod() | Present on every indicator class (single- and multi-output, scalar- and candle-input) since 0.2.1. |
A complete reference run lives in bindings/node/__tests__/smoke.test.js:
cd bindings/node
npm install
npm run build # only needed if you cloned the repo (Windows: see above)
npm testBuilding from source (Windows workaround)
If you are on Windows x64 and want to use Wickra today, build the binding locally from the repository:
git clone https://github.com/wickra-lib/wickra
cd wickra/bindings/node
npm install
npm run build # requires a Rust toolchain (rustup) on PATH
npm testnpm run build produces wickra.win32-x64-msvc.node in the binding directory; the platform loader in index.js then picks it up before falling through to the npm sub-package and the install just works.
See also
- Quickstart: Python — sibling binding with zero third-party deps (
array.array/Matrixresults). - Streaming vs Batch — why
updateis the primary entry point, notbatch. - Warmup Periods — exact
warmup_period()for every indicator. - Source: https://github.com/wickra-lib/wickra