Kurtosis (Excess Kurtosis)

Parameters: period = 5

Overview

Kurtosis measures the presence of extreme price movements and outliers by quantifying how peaked or flat the distribution of returns appears compared to a normal distribution, revealing when markets shift between calm and crisis modes. Positive excess kurtosis indicates fat tails with more extreme moves than expected from normal distributions, signaling increased risk of sudden price spikes or crashes that standard deviation alone cannot capture. When kurtosis rises sharply, it warns traders that the market has entered a regime where extreme events become more likely, requiring wider stops and reduced position sizes to account for tail risk. Negative kurtosis reveals platykurtic distributions where prices cluster tightly around the mean with fewer outliers, indicating stable conditions favorable for mean reversion strategies and tighter risk management. Options traders particularly monitor kurtosis because it directly impacts pricing models, as high kurtosis environments require adjustments to implied volatility smiles to accurately price tail risk protection. The indicator provides crucial intelligence about market regime changes, as shifts from low to high kurtosis often precede volatility expansions, while transitions from high to low kurtosis suggest markets returning to equilibrium after crisis periods.

Implementation Examples

Compute excess kurtosis from slices or candles:

use vectorta::indicators::kurtosis::{kurtosis, KurtosisInput, KurtosisParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};

// From a numeric slice
let prices = vec![100.0, 101.0, 102.0, 99.0, 104.0, 98.0];
let params = KurtosisParams { period: Some(5) }; // Default is 5
let input = KurtosisInput::from_slice(&prices, params);
let out = kurtosis(&input)?;

// From Candles with default source and params (source = "hl2", period=5)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = KurtosisInput::with_default_candles(&candles);
let out = kurtosis(&input)?;

// Access values
for v in out.values { println!("kurtosis: {}", v); }

API Reference

Input Methods
// From price slice
KurtosisInput::from_slice(&[f64], KurtosisParams) -> KurtosisInput

// From candles with custom source
KurtosisInput::from_candles(&Candles, &str, KurtosisParams) -> KurtosisInput

// From candles with default params (source="hl2", period=5)
KurtosisInput::with_default_candles(&Candles) -> KurtosisInput
Parameters Structure
#[derive(Debug, Clone)]
pub struct KurtosisParams {
    pub period: Option<usize>, // Default: 5
}
Output Structure
#[derive(Debug, Clone)]
pub struct KurtosisOutput {
    pub values: Vec<f64>, // Excess kurtosis values (m4/m2^2 - 3)
}
Validation, Warmup & NaNs
  • period > 0 and period ≤ data.len(); otherwise KurtosisError::InvalidPeriod.
  • Requires at least period valid points after the first finite value; otherwise KurtosisError::NotEnoughValidData.
  • Indices before first_valid + period − 1 are NaN (warmup prefix).
  • If any input inside a window is NaN, that window’s output is NaN.
  • If the second central moment m2 is ~0 (no variance), the output is NaN.
  • Streaming: returns None until the first period values are buffered; then emits one value per update.
Error Handling
use vectorta::indicators::kurtosis::{kurtosis, KurtosisError, KurtosisInput, KurtosisParams};

let input = KurtosisInput::from_slice(&prices, KurtosisParams { period: Some(5) });
match kurtosis(&input) {
    Ok(output) => process(output.values),
    Err(KurtosisError::EmptyInputData) => eprintln!("Empty input slice"),
    Err(KurtosisError::AllValuesNaN) => eprintln!("All input values are NaN"),
    Err(KurtosisError::InvalidPeriod { period, data_len }) =>
        eprintln!("Invalid period {} for length {}", period, data_len),
    Err(KurtosisError::NotEnoughValidData { needed, valid }) =>
        eprintln!("Need {} valid points, only {} available", needed, valid),
    Err(KurtosisError::ZeroOrMissingPeriod) =>
        eprintln!("Zero or missing period"),
}

Python Bindings

Basic Usage

Calculate excess kurtosis using NumPy arrays:

import numpy as np
from vectorta import kurtosis

prices = np.array([100.0, 101.0, 102.0, 99.0, 104.0, 98.0], dtype=np.float64)

# period required; optional kernel: "auto", "scalar", "avx2", "avx512" (if available)
values = kurtosis(prices, period=5, kernel="auto")
print(values)
Streaming
from vectorta import KurtosisStream

stream = KurtosisStream(period=5)
for price in price_feed:
    value = stream.update(price)
    if value is not None:
        print("kurtosis:", value)
Batch Parameter Optimization

Evaluate a sweep of period values:

import numpy as np
from vectorta import kurtosis_batch

prices = np.array([...], dtype=np.float64)

# (start, end, step)
res = kurtosis_batch(prices, period_range=(5, 20, 5), kernel="auto")

# Result dict contains a 2D array and tested periods
values_2d = res["values"]     # shape: [rows, len(prices)]
periods = res["periods"]      # tested period values
print(periods, values_2d.shape)
CUDA Acceleration

CUDA support for Kurtosis is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.

# Coming soon: CUDA-accelerated kurtosis calculations
# from vectorta import kurtosis_cuda_batch, kurtosis_cuda_many_series_one_param
# import numpy as np
#
# # Parameter sweep on a single series
# res = kurtosis_cuda_batch(data=prices, period_range=(5, 20, 1), device_id=0)
# # Many series, one parameter set
# out = kurtosis_cuda_many_series_one_param(data_tm=portfolio_tm, period=5, device_id=0)

JavaScript/WASM Bindings

Basic Usage

Calculate Kurtosis in JavaScript/TypeScript:

import { kurtosis_js } from 'vectorta-wasm';

const prices = new Float64Array([100.0, 101.0, 102.0, 99.0, 104.0, 98.0]);
const values = kurtosis_js(prices, 5);
console.log('kurtosis:', values);
Memory-Efficient Operations

Use zero-copy operations for large datasets:

import { kurtosis_alloc, kurtosis_free, kurtosis_into, memory } from 'vectorta-wasm';

const prices = new Float64Array([/* your data */]);
const n = prices.length;

const inPtr = kurtosis_alloc(n);
const outPtr = kurtosis_alloc(n);
new Float64Array(memory.buffer, inPtr, n).set(prices);

// Args: in_ptr, out_ptr, len, period
kurtosis_into(inPtr, outPtr, n, 5);

const out = new Float64Array(memory.buffer, outPtr, n).slice();
kurtosis_free(inPtr, n);
kurtosis_free(outPtr, n);
console.log('kurtosis:', out);
Batch Processing

Unified batch API returns values and combos:

import { kurtosis_batch } from 'vectorta-wasm';

const prices = new Float64Array([/* historical prices */]);
const cfg = { period_range: [5, 20, 5] as [number, number, number] };
const result = kurtosis_batch(prices, cfg);

// result: { values: Float64Array, combos: { period: number | null }[], periods: number[], rows: number, cols: number }
const { values, combos, periods, rows, cols } = result;
console.log('rows x cols =', rows, 'x', cols);
console.log('periods tested:', periods);

Performance Analysis

Comparison:
View:
Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05

Related Indicators