Performance claims without measurement: just marketing. QuanTAlib benchmarks against established libraries: TA-Lib and Tulip (industry-standard C libraries accessed via P/Invoke), Skender.Stock.Indicators and Ooples.FinancialIndicators (popular .NET implementations).
## Test Environment
| Component | Specification |
| :-------- | :------------ |
| Data Size | 500,000 bars |
| Period | 220 (sufficient to expose algorithmic inefficiencies) |
These results represent what current-generation CPUs achieve in production. Your mileage varies with older hardware, but relative performance ratios hold.
## SIMD and FMA: The Speed Multipliers
The library auto-detects and exploits the highest available instruction set. Processing multiple data points per clock cycle changes everything:
**Fused Multiply-Add (FMA)** performs `a * b + c` in a single cycle with one rounding step. Two advantages compound:
1.**Throughput**: Double the floating-point operations per cycle versus separate multiply/add
2.**Precision**: Cumulative rounding errors shrink in iterative calculations
In convolution-heavy algorithms (WMA, LinReg, Correlation), SIMD + FMA explains most of the observed speedup. The CPU stops being the bottleneck; memory bandwidth takes over.
## Benchmark Results
### Simple Moving Average (SMA)
QuanTAlib Span mode: 500,000 SMA values in 328 microseconds. Zero allocations. That works out to **0.66 nanoseconds per value**. For perspective: a single L1 cache access takes approximately 1 nanosecond. Moving averages calculating faster than cache fetch.
| Library | Mean Time | Allocations | Relative Speed |
Skender and Ooples allocate 42-151 MB for what should be a stateless calculation. Garbage collector wakes up, stretches, and ruins everyone's day.
### Exponential Moving Average (EMA)
QuanTAlib at 421 microseconds outperforms both C libraries: Tulip at 709 μs, TA-Lib at 709 μs. Beating heavily optimized C with managed code sounds improbable. The secret: **FMA instructions** on the hot path. Those C libraries predate AVX-512 optimizations by a decade.
| Library | Mean Time | Allocations | Relative Speed |
The 1.7× speedup over C libraries represents what happens when old code meets new silicon. Modern instruction sets exist; using them helps.
### Weighted Moving Average (WMA)
QuanTAlib WMA: 302 microseconds. Tulip: 378 μs. TA-Lib: 368 μs. Not a measurement error. Pure C# with proper SIMD vectorization beating C code that predates AVX-512 optimizations.
| Library | Mean Time | Allocations | Relative Speed |
A 251× improvement over standard .NET implementations. Compound calculations expose implementation quality: inefficiencies multiply with each nested operation.
### Chaikin Oscillator (ADOSC)
Multi-input indicator using high, low, close, and volume. Tests OHLCV data handling efficiency.
| Library | Mean Time | Allocations | Relative Speed |
Even QuanTAlib's slowest mode (Eventing with complete event infrastructure, 16.8 MB allocations) processes 500,000 EMA values in 3.5 milliseconds. Still faster than Ooples at 14.5 ms and Skender at 26.6 ms for identical calculation. The "slow" path here beats other libraries' only path.
The same indicators benchmarked in C# are also available through Python via NativeAOT shared library + ctypes FFI. This comparison measures the real-world cost of calling QuanTAlib from Python versus using pandas-ta (the most popular pure-Python technical analysis library).
SMA and WMA expose the largest gaps. pandas-ta implements SMA as a rolling window in pure Python/numpy, while quantalib calls the same SIMD-optimized C# code (via NativeAOT) that beats TA-Lib in the C# benchmarks above. WMA at 68× faster reflects the dot-product advantage: eight FMA operations per cycle versus Python's element-at-a-time loop.
### quantalib vs pandas builtins
pandas itself provides optimized C implementations for common rolling operations. Fair comparison:
Even against pandas' C-optimized rolling operations, quantalib NativeAOT wins 2-5× on simple indicators. WMA is the extreme case: pandas lacks a native WMA implementation, falling back to `rolling().apply()` with a Python lambda — 561× slower.
### FFI Overhead
The ctypes foreign function interface adds approximately 5-15 microseconds per invocation. At 500,000 bars, this overhead disappears into noise. Below ~100 bars, FFI marshaling dominates and pandas-ta's pure-Python approach wins on latency. Above ~1,000 bars, NativeAOT SIMD takes over decisively.
Adjust `--bars` and `--period` to match your use case. The script degrades gracefully — if pandas-ta or quantalib is unavailable, it benchmarks whatever is installed.
Results vary by CPU generation, but relative ratios (QuanTAlib vs competitors) remain consistent across hardware. The architectures that make something fast stay fast; the ones that allocate memory keep allocating.