Skip to content

Quickstart: WASM ​

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 WASM binding. The same Rust core that powers the Python, Node.js, and Rust APIs is compiled to WebAssembly with wasm-bindgen, so indicators run entirely client-side — in a browser tab, a bundler build, or Node — with no server round-trips.

Install ​

The published package is wickra-wasm on npm:

bash
npm install wickra-wasm

The npm package is built for the bundler target, so it works directly with Webpack, Vite, Rollup, and similar toolchains.

Build from source ​

To build the binding yourself you need wasm-pack and the wasm32-unknown-unknown target:

bash
rustup target add wasm32-unknown-unknown
cargo install wasm-pack

# Browser ES-module build (import directly from a <script type="module">):
wasm-pack build bindings/wasm --target web --release --features panic-hook

# Bundler build (Webpack / Vite / Rollup):
wasm-pack build bindings/wasm --target bundler --release --features panic-hook

wasm-pack writes the generated module, the .wasm binary, and TypeScript definitions into bindings/wasm/pkg/. The panic-hook feature routes Rust panics to console.error for readable stack traces during development.

A first run (browser) ​

With a --target web build, import the generated module directly:

html
<script type="module">
  import init, { version, SMA } from "./pkg/wickra_wasm.js";

  await init();                       // load and instantiate the .wasm binary
  console.log("wickra-wasm", version());

  const sma = new SMA(3);
  console.log(sma.batch([2, 4, 6, 8, 10]));
  // -> Float64Array [ NaN, NaN, 4, 6, 8 ]
</script>

init() must be awaited once before any indicator is constructed — it fetches and instantiates the WebAssembly binary. After that the API mirrors the other bindings.

Streaming ​

javascript
import init, { RSI } from "wickra-wasm";

await init();

const rsi = new RSI(14);
for (const price of liveFeed) {
  const value = rsi.update(price);    // number, or null/undefined during warmup
  if (value != null && value > 70) {
    console.log("overbought");
  }
}

Every indicator is an incremental state machine: update advances the indicator by exactly one input, so a browser charting app pays no cost for recomputing history on each tick.

Multi-output indicators ​

Several indicators return a structured object from update (or null during warmup). The full list and their field names:

Indicatorupdate return shape
MACD{ macd, signal, histogram }
BollingerBands{ upper, middle, lower, stddev }
Stochastic{ k, d }
ADX{ plusDi, minusDi, adx }
Keltner{ upper, middle, lower }
Donchian{ upper, middle, lower }
Aroon{ up, down }
SuperTrend{ value, direction }
javascript
import init, { MACD } from "wickra-wasm";

await init();

const macd = new MACD(12, 26, 9);
let last = null;
for (let i = 0; i < 40; i++) {
  last = macd.update(100 + i * 0.5);  // null during warmup, else { macd, signal, histogram }
}
console.log(last);

batch returns a flat Float64Array; multi-output indicators interleave their fields per row (e.g. MACD: [macd0, signal0, hist0, macd1, ...]). The exact layout is documented in the generated pkg/wickra_wasm.d.ts.

Since [email protected], every candle-input indicator (ATR, ADX, WilliamsR, CCI, MFI, PSAR, Keltner, Donchian, VWAP, RollingVWAP, AwesomeOscillator, Aroon, Stochastic, OBV, and the rest of the volume / volatility / trailing-stop / price-statistics families) exposes the same streaming API as MACD here — update, batch, reset, isReady and warmupPeriod. Earlier releases only shipped batch for twelve of these classes; browser code no longer needs to replay batch on every tick.

The opt-in fast batch ​

The single-output indicators — plus MACD, MACDFIX, Bollinger Bands, ATR, the Chaikin oscillator and Pearson correlation — add batchFast and the caller-buffer batchInto / batchFastInto next to batch:

js
const out = new Float64Array(prices.length);
const fast = new EMA(20).batchFast(prices);   // Float64Array, NaN during warmup
new SMA(20).batchInto(prices, out);           // exact, into a reused buffer
new EMA(20).batchFastInto(prices, out);

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.

Errors ​

Unlike the Node binding (whose constructors clamp pathological values), the WASM binding's constructors throw a JavaScript error for invalid parameters:

javascript
try {
  new MACD(0, 0, 0);
} catch (e) {
  console.error("invalid MACD parameters:", e);
}

A complete example ​

examples/wasm/index.html is a self-contained browser demo: it streams a synthetic price series through six indicators and draws a live chart on a <canvas>. Open it after a --target web build:

bash
wasm-pack build bindings/wasm --target web --release --features panic-hook
# then serve the repository root and open examples/wasm/index.html

See also ​