ti-engine is a WebAssembly-powered, JS/TS-idiomatic wrapper around RustTI — a high‑performance, pure‑Rust technical indicators library.
- Production‑grade indicators, ported from battle‑tested Rust code
- First‑class TypeScript types and clean, namespaced API
- Works in Node and modern browsers (bundler + web builds)
- Identical results to RustTI (with parity tests for core functions)
Looking for the Rust crate? See: ChironMind/RustTI
Looking for the Python version? See: ChironMind/PyTechnicalIndicators
Install from your package manager (example: local/private package)
# npm
npm install ti-engine
# yarn
yarn add ti-engine
# pnpm
pnpm add ti-engineInitialize and use (Node)
import init, {
momentumIndicators,
ConstantModelType,
} from "ti-engine";
// Node: init() is a no-op, but safe to call
await init();
const prices = [100.2, 100.46, 100.53, 100.38, 100.19];
const rsi = momentumIndicators.single.relativeStrengthIndex(
prices,
ConstantModelType.SimpleMovingAverage
);
console.log("RSI:", rsi); // 49.2537313432832Browser (bundlers)
import init, { movingAverage, MovingAverageType } from "ti-engine";
await init(); // Required to load the WASM module in browsers
const sma = movingAverage.single.movingAverage(
[100.2, 100.46, 100.53, 100.38, 100.19],
MovingAverageType.Simple
);
console.log("SMA:", sma); // 100.352- Same math and deterministic outputs as RustTI
- Two styles for almost every indicator:
- single: full-window, scalar output
- bulk: rolling windows, vector output
- Clean naming and nested namespaces:
- candleIndicators, chartTrends, correlationIndicators, momentumIndicators, movingAverage, otherIndicators, standardIndicators, strengthIndicators, trendIndicators, volatilityIndicators
Fully typed with ambient declarations — enjoy rich editor hints and autocomplete.
All indicator namespaces expose:
- single: functions that compute a single value from the whole input
- bulk: functions that compute rolling outputs (arrays)
Common enums:
- ConstantModelType: SimpleMovingAverage, SmoothedMovingAverage, ExponentialMovingAverage, SimpleMovingMedian, SimpleMovingMode, PersonalisedMovingAverage
- DeviationModel: StandardDeviation, MeanAbsoluteDeviation, MedianAbsoluteDeviation, ModeAbsoluteDeviation, UlcerIndex
- Position: Long, Short (for SAR-like systems)
- MovingAverageType: Simple, Smoothed, Exponential (for generic moving average helpers)
Top namespaces:
- movingAverage: generic MAs and McGinley Dynamic
- momentumIndicators: RSI, Stochastic, MACD variants, PPO, MFI, OBV, CCI, Williams %R, Chaikin, CMO
- strengthIndicators: Accumulation/Distribution, PVI, NVI, RVI
- trendIndicators: Aroon (Up/Down/Oscillator), Parabolic Time Price System, Directional Movement System (+DI, –DI, ADX/ADXR), VPT, TSI
- volatilityIndicators: Ulcer Index, Wilder’s volatility system
- candleIndicators: Bands/Envelopes, Ichimoku, Donchian, Keltner, Supertrend
- correlationIndicators: Asset correlation
- chartTrends: Peaks/Valleys, trend lines, segmentation
- otherIndicators: ROI, True Range / ATR, Internal Bar Strength, Positivity Indicator
See the full set of function signatures via your editor or the included index.d.ts.
Relative Strength Index (RSI)
import init, { momentumIndicators, ConstantModelType } from "ti-engine";
await init();
const prices = [100.2, 100.46, 100.53, 100.38, 100.19, 100.21, 100.32, 100.28];
// Full window (single)
const rsi = momentumIndicators.single.relativeStrengthIndex(
prices.slice(0, 5),
ConstantModelType.SimpleMovingAverage
);
// -> 49.2537313432832
// Rolling (bulk), period = 5
const rsiSeries = momentumIndicators.bulk.relativeStrengthIndex(
prices,
ConstantModelType.SimpleMovingAverage,
5
);
// -> [49.2537..., 20.9302..., 27.6595..., 36.1111...]MACD (EMA/EMA)
import { momentumIndicators, ConstantModelType } from "ti-engine";
const macdLine = momentumIndicators.single.macdLine(
[100.46, 100.53, 100.38, 100.19, 100.21],
3,
ConstantModelType.ExponentialMovingAverage,
ConstantModelType.ExponentialMovingAverage
);
// -> -0.06067027758972188
const signal = momentumIndicators.single.signalLine(
[-0.06067027758972188, -0.022417061611406552, 0.005788761002008869],
ConstantModelType.ExponentialMovingAverage
);
// -> -0.011764193829214216Parabolic Time Price System (SAR)
import { trendIndicators, Position, ConstantModelType } from "ti-engine";
// Long SAR track with rolling outputs
const sars = trendIndicators.bulk.parabolicTimePriceSystem(
[100.64, 102.39, 101.51, 99.48, 96.93], // highs
[95.92, 96.77, 95.84, 91.22, 89.12], // lows
0.02, 0.2, 0.02, // AF start, max, step
Position.Long, // starting side
0.0 // previous SAR (seed)
);
// -> [95.92, 95.92, 102.39, 101.9432, 101.17380800000001]Ulcer Index (volatility)
import { volatilityIndicators } from "ti-engine";
const ui = volatilityIndicators.single.ulcerIndex(
[100.46, 100.53, 100.38, 100.19, 100.21]
);
// -> 0.21816086938686668Moving Average helpers
import { movingAverage, MovingAverageType } from "ti-engine";
const sma = movingAverage.single.movingAverage(
[100.2, 100.46, 100.53, 100.38, 100.19],
MovingAverageType.Simple
);
// -> 100.352This package includes three targets out of the box:
- Node:
dist/node/ti_engine.js(CommonJS require via index.node.js) - Bundler:
dist/bundler/ti_engine.js(ESM, for Vite/Webpack/Rollup) - Web:
dist/web/ti_engine.js(ESM + separate.wasm)
Import surfaces:
- Node:
import init, * as api from "ti-engine/index.node.js";(or defaultimportfrom package root) - Bundler/Web:
import init, * as api from "ti-engine";
Initialization:
- Web/Bundlers: You MUST
await init()before calling indicators (it fetches/instantiates WASM). - Node:
init()is a no‑op, safe to call for parity in shared code paths.
- Input validation mirrors RustTI: many functions panic for empty arrays or mismatched lengths. In JS, this surfaces as a thrown error.
- Use
Float64Arrayornumber[]. Internally, values are copied into WASM memory; consider chunking for very large series. - Bulk functions typically return arrays of length
L - N + 1whereNis the rolling period (or long period for dual-period indicators). - All outputs are plain JS arrays for easy consumption; tuples are represented as small arrays (e.g.,
[lower, middle, upper]).
- All math is executed in highly optimized Rust and compiled to WebAssembly.
- In Node, performance is near-native for numeric workloads.
- In browsers, expect excellent performance; account for WASM boundary crossings (amortize by passing larger slices).
For raw Rust benchmarks and methodology, see:
This repo includes value parity tests that assert equality with RustTI for a selection of indicators across modules. Run them in Node:
npm test
# or
node --test ti-engine/test/*.test.jsContributions, bug reports, and feature requests are welcome!
- Open an issue or discussion
- Submit a PR with tests (value parity preferred)
- Suggestions for new high‑value wrappers and DX improvements are appreciated
Please see CONTRIBUTING.md.
See Git history and changelog for details. We follow semver where possible for API changes.
MIT License. See LICENSE.