ti-engine
v1.1.4
Published
WASM bindings for RustTI technical indicators for Node and browser
Maintainers
Readme
ti-engine
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
🚀 Quick Start
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.352Browser (CDN - jsdelivr/unpkg)
<script type="module">
// Note: Replace @latest with a specific version (e.g., @1.1.2) for production use
import init, * as wasm from 'https://cdn.jsdelivr.net/npm/ti-engine@latest/dist/web/ti_engine.js';
await init(); // Initialize WASM module
// When using the web target directly, use the flat WASM exports
const prices = [100.2, 100.46, 100.53, 100.38, 100.19];
const rsi = wasm.momentum_single_relativeStrengthIndex(
prices,
wasm.ConstantModelType.SimpleMovingAverage
);
console.log("RSI:", rsi); // 49.2537313432832
// Or use the index.web.js wrapper for the same namespaced API as bundlers
// import init, { momentumIndicators, ConstantModelType } from 'https://cdn.jsdelivr.net/npm/[email protected]/index.web.js';
</script>🧩 What You Get
- 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.
📚 API Overview
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.
🧪 Usage Examples
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.352🔌 Builds and Initialization
This 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.
🧠 Tips & Conventions
- 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]).
📈 Performance
- 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:
🧪 Parity Tests
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.js🤝 Contributing
Contributions, 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.
📰 Release Notes
See Git history and changelog for details. We follow semver where possible for API changes.
📄 License
MIT License. See LICENSE.
