Skip to content

TulipRS

High-performance technical analysis in Rust.

TulipRS is a production-ready library implementing 100+ technical indicators and 77+ candlestick patterns, with first-class SIMD acceleration, stateful streaming, and native bindings for C, Python, Node.js, Go, and the browser (WASM).


Why TulipRS?

Most technical analysis libraries are wrappers around the same scalar C code written decades ago. TulipRS is built differently, with several capabilities that compound into meaningfully faster and more practical pipelines:

SIMD acceleration — rather than looping over one asset or one parameter set at a time, TulipRS can process N assets or N option sets simultaneously in a single CPU pass using portable SIMD intrinsics. On AVX2 hardware that is 4× the throughput for the same wall-clock time. See SIMD.

Stateful streaming — built for live systems — every indicator returns an IndicatorState alongside its outputs. Feed it new bars as they arrive and computation resumes from where it left off — no reprocessing of historical data, no O(n) cost per tick. State is fully serialisable to JSON and other Serde formats for persistence across restarts. See State Management.

Optional outputs at no extra cost — many indicators compute intermediate series (sub-EMAs, TR, AD line, etc.) as a natural part of their calculation. TulipRS can return those alongside the primary output in the same pass. C Tulip and TA-Lib require a separate function call — and a full extra data scan — for each one. TulipRS is 1.3× – 8.7× faster when you need those intermediate values. See Indicator API.


Browser-native via WebAssembly — the full indicator library compiles to a WebAssembly module via wasm-pack, bringing the same computation to any modern browser with zero server round-trips and zero native dependencies. Pair it with tulip-rs-lwc for drop-in TradingView Lightweight Charts overlays and oscillators, or use tulip-rs-wasm directly for headless browser-side computation. See Live Demo.


Performance

TulipRS isn't just SIMD-accelerated in theory — it's measurably faster in practice, benchmarked against C Tulip, TA-Lib, pure-Rust libraries (kand, RustTa), pandas-based Python libraries, pure-Go libraries, and popular Node.js TA packages:

  • ~22× faster than Python's ta library, up to 20,802× on select indicators
  • ~46× faster than Node's technicalindicators, up to 403× on select indicators
  • ~2,283× faster than Go's cinar/indicator, up to 7,491× on select indicators
  • Up to 11.93× faster than TA-Lib, the industry-standard C library
  • Beats every pure-Rust TA-Lib-inspired competitor on 100% of compared indicators — up to 36.10× faster than kand (mfi) and up to 6.78× faster than RustTa (ef)
  • Up to 3.85× additional throughput from SIMD batch processing

📊 Full benchmark methodology and results


Features at a Glance

Capability Detail
Indicators 100+ (moving averages, oscillators, trend, volatility, volume, price/statistical)
Candlestick Patterns 60+ patterns with bullish/bearish forecasting
SIMD — by assets Same options applied to N assets in one CPU pass (indicator_by_assets::<N>)
SIMD — by options N option sets applied to one asset in one CPU pass (indicator_by_options::<N>)
State management Every indicator returns a serialisable IndicatorState for streaming / incremental use
Browser / WASM Full indicator set compiled to WebAssembly — runs in any modern browser, no server needed (tulip-rs-wasm)
Languages Rust (native), C (tulip_rs_ffi — hand-rolled extern "C" FFI), Python (tulip_rs_python via PyO3), Node.js (tulip-rs-node via napi-rs), Go (tulip_rs_go via cgo), Browser (WASM)

Quick Example

use tulip_rs::indicators::sma::{Sma, Indicator};

let close = vec![81.59, 81.06, 82.87, 83.00, 83.61,
                 83.15, 82.84, 83.99, 84.55, 84.36_f64];

let (outputs, state) = Sma::indicator(&[close.as_slice()], &[5.0], None).unwrap();

println!("{:?}", outputs[0]); // SMA(5) values
import "github.com/me60732/tulip_rs_go/indicators"

close := []float64{81.59, 81.06, 82.87, 83.00, 83.61,
                   83.15, 82.84, 83.99, 84.55, 84.36}

res, st, _ := indicators.Sma.Indicator(close, []float64{5.0}, nil)
defer res.Close()
defer st.Close()

fmt.Println(res.Rows[0]) // SMA(5) values — zero-copy views
import org.tuliprs.*;
import org.tuliprs.indicators.Sma;

double[] close = {81.59, 81.06, 82.87, 83.00, 83.61,
                  83.15, 82.84, 83.99, 84.55, 84.36};

Outcome oc = Sma.indicator(new double[][] {close}, new double[] {5.0});
try (Result res = oc.result(); State st = oc.state()) {
    System.out.println(java.util.Arrays.toString(res.toDoubleArray(0))); // SMA(5) values — zero-copy views
}
import numpy as np
import tulip_rs

close = np.array([81.59, 81.06, 82.87, 83.00, 83.61,
                  83.15, 82.84, 83.99, 84.55, 84.36], dtype=np.float64)

outputs, state = tulip_rs.indicators.sma.indicator([close], [5.0])

print(outputs[0])  # SMA(5) values
import * as ti from 'tulip-rs-node';

const close = Float64Array.from([81.59, 81.06, 82.87, 83.00, 83.61,
                                 83.15, 82.84, 83.99, 84.55, 84.36]);

const [outputs, state] = ti.sma.indicator([close], [5]);

console.log(outputs[0]); // SMA(5) values
import { init } from 'tulip-rs-wasm';
import * as ti from 'tulip-rs-wasm';

await init(); // bundler resolves the WASM asset automatically

const close = [81.59, 81.06, 82.87, 83.00, 83.61,
               83.15, 82.84, 83.99, 84.55, 84.36];

const [outputs, state] = ti.sma.indicator([close], [5]);

console.log(outputs[0]); // SMA(5) values

Documentation Pages

Page Description
Getting Started Installation, feature flags, calling convention, and first examples
Indicators — Overview Full indicator index with inputs, options, and output counts
Moving Averages SMA, EMA, WMA, DEMA, TEMA, TRIMA, HMA, ZLEMA, KAMA, VIDYA, VWMA, Wilders
Oscillators RSI, MACD, Stoch, StochRSI, Williams %R, CCI, CMO, UltOsc, AO, Fisher, FOSC, MSW
Trend PPO, APO, ADX, ADXR, DM, DI, DX, Aroon, AroonOsc, PSAR
Volatility BBands, ATR, NATR, TR, StdDev, Volatility, VHF, CVI
Volume AD, ADOSC, OBV, MFI, NVI, PVI, VOSC, KVO, EMV, WAD
Price & Statistical AvgPrice, MedPrice, TypPrice, WCPrice, Max, Min, MOM, ROC, ROCR, BOP, LinReg, TSF, TRIX, DPO, Mass, MD, MarketFi, QStick, PivotPoint
Candlestick Patterns 60+ patterns, forecast types, Rust, C, Python, and Node.js usage
SIMD Conceptual overview: by-assets and by-options modes, lane counts, when to use each
State Management Streaming computation, chunked processing, JSON serialisation
Language Bindings Per-binding subpages: C FFI, Python (PyO3/maturin), Node.js (napi-rs), Go (cgo), Browser (WASM)
Benchmarks Comparison against Tulip Indicators (C) and TA-Lib, methodology, how to run

Language Support

Language Status Package
Rust ✅ Native tulip_rs (this crate)
C ✅ Supported tulip_rs_ffi — hand-rolled extern "C" FFI, usable from C, C++/any C ABI
Go ✅ Supported tulip_rs_go — cgo bindings over the extern "C" FFI, zero-copy outputs
Java ✅ Supported tulip-rs-java — JDK 22+ Foreign Function API
Python ✅ Supported tulip_rs_python
Node.js ✅ Supported tulip-rs-node
Browser (WASM) ✅ Supported tulip-rs-wasm · tulip-rs-lwc