Files
QuanTAlib/docs/benchmarks.md
T
Miha Kralj b5358091ae feat: Add Absolute Price Oscillator (APO) implementation and documentation
feat: Implement ADL (Accumulation/Distribution Line) indicator
2025-12-18 21:32:01 -08:00

4.8 KiB

Benchmarks

Performance claims require measurement. We benchmark QuanTAlib 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

  • Framework: .NET 10.0 with AOT compilation
  • Hardware: Modern CPU supporting AVX-512 instructions
  • Data: 500,000 bars
  • Parameters: Period 220 (sufficient scale to expose algorithmic inefficiencies)

These results represent what current-generation server CPUs achieve in production.

Benchmark Results

Simple Moving Average (SMA)

QuanTAlib's Span mode calculates 500,000 SMA values in 318 microseconds with zero memory allocations. That's 0.64 nanoseconds per value. For context, a single L1 cache access takes approximately 1 nanosecond on modern CPUs — we're calculating moving averages faster than fetching data from the nearest cache level.

Library Mean Time Allocations Relative Speed
QuanTAlib (Span) 318.3 μs 0 B 1.00x (baseline)
TA-Lib 356.4 μs 34 B 1.12x slower
Tulip 359.3 μs 0 B 1.13x slower
Skender 71,277 μs 50.8 MB 224x slower
Ooples 500,793 μs 151 MB 1,573x slower

Exponential Moving Average (EMA)

QuanTAlib matches C library performance at 711 microseconds — within measurement error of Tulip's 708μs and TA-Lib's 713μs. Pure C# matching heavily optimized C code demonstrates what modern .NET achieves when you align memory layouts with hardware capabilities.

Library Mean Time Allocations Relative Speed
QuanTAlib (Span) 711.0 μs 0 B 1.00x
TA-Lib 712.9 μs 36 B 1.00x slower
Tulip 708.1 μs 0 B 1.00x faster
Skender 31,393 μs 50.8 MB 44x slower
Ooples 18,860 μs 79.3 MB 27x slower

Weighted Moving Average (WMA)

QuanTAlib's WMA beats both C libraries — 296 microseconds versus Tulip's 372μs and TA-Lib's 360μs. This isn't a measurement error. Pure C# with proper SIMD vectorization outperforms C code that predates AVX-512 optimizations.

Library Mean Time Allocations Relative Speed
QuanTAlib (Span) 296.0 μs 0 B 1.00x (baseline)
TA-Lib 360.0 μs 34 B 1.22x slower
Tulip 372.1 μs 0 B 1.26x slower
Skender 103,254 μs 50.8 MB 349x slower
Ooples 73,983 μs 70.9 MB 250x slower

Hull Moving Average (HMA)

HMA requires multiple moving average calculations — traditionally expensive. QuanTAlib processes 500,000 bars in 1,008 microseconds. Tulip takes 2,266 microseconds. Skender requires 251,694 microseconds. (TALib doesn't include HMA calculation) That's a 2.25x improvement over optimized C and a 250x improvement over standard .NET implementations.

Library Mean Time Allocations Relative Speed
QuanTAlib (Span) 1,007.8 μs 0 B 1.00x (baseline)
TA-Lib -- -- --
Tulip 2,266.0 μs 152 B 2.25x slower
Skender 251,694 μs 235.9 MB 250x slower
Ooples 123,234 μs 108.7 MB 122x slower

Multi-mode Comparison

The benchmarks above show Span mode. Here's how all four modes compare using EMA as representative:

QuanTAlib Mode Mean Time Allocations Use Case
Span 711.0 μs 0 B Maximum speed, batch processing
Streaming 721.9 μs 44 B Real-time updates, minimal overhead
Batch (TSeries) 1,311.7 μs 8.0 MB Time-aligned series with metadata
Eventing 2,928.4 μs 16.8 MB Reactive architectures with event infrastructure

Even QuanTAlib's slowest mode (Eventing with complete event infrastructure and 16MB of allocations) processes 500,000 EMA values in 3 milliseconds — faster than Ooples' 19 milliseconds and Skender's 31 milliseconds for the same calculation.

Methodology

We use BenchmarkDotNet for all performance testing. This ensures:

  • Warmup iterations to stabilize JIT compilation
  • Statistical analysis of results (mean, standard deviation)
  • Memory allocation tracking
  • Environment isolation

How to Run Benchmarks Yourself

You can run the benchmarks on your own hardware to verify these results.

  1. Clone the repository:

    git clone https://github.com/mihakralj/QuanTAlib.git
    cd QuanTAlib
    
  2. Navigate to the performance project:

    cd perf
    
  3. Run the benchmarks:

    dotnet run -c Release
    

    Note: Benchmarks must be run in Release configuration to enable optimizations.