Skip to content

Spearman Rank Correlation

Rolling Spearman rank correlation between two synchronised series. Captures monotonic rather than linear association — values in each channel are replaced by their ranks (mid-ranks for ties), and the Pearson correlation of those ranks is reported. Robust to nonlinearities that defeat Pearson.

Quick reference

ItemValue
FamilyPrice Statistics
Input type(f64, f64)(x, y) pair per update
Output typef64
Output range[-1, +1]
Default parametersperiod required
Warmup periodperiod
InterpretationStrength of monotonic relationship (linear or nonlinear)

Formula

rx = rank(x_i)  with mid-rank tie handling
ry = rank(y_i)  with mid-rank tie handling
Spearman = Pearson(rx, ry)

Mid-rank tie handling assigns the average rank to tied values (matches scipy's default). See crates/wickra-core/src/indicators/spearman_correlation.rs.

Parameters

NameTypeDefaultConstraintDescription
periodusizenone> 1Rolling window.

Inputs / Outputs

Indicator<Input = (f64, f64), Output = f64>. Standard binding shapes.

Warmup

warmup_period() == period.

Edge cases

  • All-tied input. Variance of ranks zero → output 0.0.
  • Monotone but nonlinear relationship. Pearson may show low correlation; Spearman shows ±1.
  • Cost. Each update is O(period · log period) due to sort.
  • Reset. Clears the rolling window.

Examples

Rust

rust
use wickra::{Indicator, SpearmanCorrelation};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut s = SpearmanCorrelation::new(50)?;
    for i in 0..100 {
        let x = f64::from(i);
        let y = x.powi(2);  // monotone nonlinear
        let _ = s.update((x, y));
    }
    Ok(())
}

Python

python
import numpy as np
import wickra as ta

x = np.arange(100, dtype=float)
y = x ** 2
s = ta.SpearmanCorrelation(50)
print(s.batch(x, y)[-1])  # +1.0 (perfectly monotone)

Node

javascript
const wickra = require('wickra');
const s = new wickra.SpearmanCorrelation(50);
// feed x, y

Streaming

rust
use wickra::{Indicator, SpearmanCorrelation};

let mut s = SpearmanCorrelation::new(252).unwrap();
let price_stream: Vec<(f64, f64)> = Vec::new(); // your paired (a, b) feed
for (asset_a, asset_b) in price_stream {
    if let Some(v) = s.update((asset_a, asset_b)) {
        // v is rolling rank correlation — robust to nonlinearity
    }
}

Interpretation

  • Spearman ≈ +1. Perfect monotone increasing relationship (linear OR nonlinear).
  • Spearman ≈ -1. Perfect monotone decreasing.
  • Vs Pearson. Pearson detects only linear; Spearman detects any monotone relationship. For two series related by y = x² (positive x): Pearson ≈ 0.97; Spearman = 1.0.
  • Outlier robustness. Ranks bound outliers — Spearman is more robust than Pearson to extreme values.

Common pitfalls

  • Slower than Pearson. O(n log n) per update vs O(1).
  • Tie handling. Series with many tied values produce ambiguous ranks; mid-rank handling is standard but other conventions exist.
  • Confusing with Kendall's tau. Kendall's tau is another rank correlation; computationally more expensive, slightly different formula. Wickra implements Spearman.

References

  • Charles Spearman, The Proof and Measurement of Association between Two Things, American Journal of Psychology, 1904.

See also