# API Reference

This document provides a comprehensive reference for all public APIs in the `anofox-forecast` crate. The crate provides 35+ forecasting models, 76+ time series features, and extensive utilities for time series analysis.

## Table of Contents

- [Core Types](#core-types)
  - [TimeSeries](#timeseries)
  - [TimeSeriesBuilder](#timeseriesbuilder)
  - [Forecast](#forecast)
  - [ForecastError](#forecasterror)
- [Missing Value Imputation](#missing-value-imputation)
  - [MissingValuePolicy](#missingvaluepolicy)
  - [Imputation Methods](#imputation-methods)
  - [Metadata Helpers](#metadata-helpers)
- [Forecaster Trait](#forecaster-trait)
- [Baseline Models](#baseline-models)
  - [Naive](#naive)
  - [SeasonalNaive](#seasonalnaive)
  - [RandomWalkWithDrift](#randomwalkwithdrift)
  - [HistoricAverage](#historicaverage)
  - [WindowAverage](#windowaverage)
  - [SeasonalWindowAverage](#seasonalwindowaverage)
- [Exponential Smoothing](#exponential-smoothing)
  - [SimpleExponentialSmoothing](#simpleexponentialsmoothing)
  - [Holt](#holt)
  - [HoltWinters](#holtwinters)
  - [ETS](#ets)
  - [AutoETS](#autoets)
  - [SeasonalES](#seasonales)
- [ARIMA Models](#arima-models)
  - [ARIMA](#arima)
  - [SARIMA](#sarima)
  - [AutoARIMA](#autoarima)
- [Theta Models](#theta-models)
  - [Theta](#theta)
  - [OptimizedTheta](#optimizedtheta)
  - [DynamicTheta](#dynamictheta)
  - [DynamicOptimizedTheta](#dynamicoptimizedtheta)
  - [AutoTheta](#autotheta)
- [Intermittent Demand Models](#intermittent-demand-models)
  - [Croston](#croston)
  - [TSB](#tsb)
  - [ADIDA](#adida)
  - [IMAPA](#imapa)
- [Advanced Models](#advanced-models)
  - [MFLES](#mfles)
  - [MSTLForecaster](#mstlforecaster)
  - [TBATS](#tbats)
  - [AutoTBATS](#autotbats)
  - [GARCH](#garch)
- [Ensemble](#ensemble)
- [Decomposition](#decomposition)
  - [STL](#stl)
  - [MSTL](#mstl)
- [Spectral Analysis](#spectral-analysis)
  - [Welch Periodogram](#welch-periodogram)
- [Feature Extraction](#feature-extraction)
- [Transformations](#transformations)
- [Validation](#validation)
- [Changepoint Detection](#changepoint-detection)
- [Utilities](#utilities)
- [Probabilistic Postprocessing](#probabilistic-postprocessing)
  - [PointForecasts](#pointforecasts)
  - [QuantileForecasts](#quantileforecasts)
  - [PredictionIntervals](#predictionintervals)
  - [ConformalPredictor](#conformalpredictor)
  - [HistoricalSimulator](#historicalsimulator)
  - [NormalPredictor](#normalpredictor)
  - [IDRPredictor](#idrpredictor)
  - [QRAPredictor](#qrapredictor)
  - [PostProcessor](#postprocessor)
  - [Backtesting](#backtesting)
  - [Conformalize](#conformalize)

---

## Core Types

### TimeSeries

Container for time series data with timestamps and multivariate values.

```rust
pub struct TimeSeries {
    // Fields are private, use methods to access
}
```

#### Constructor Methods

| Method | Description |
|--------|-------------|
| `TimeSeries::new(timestamps, values, labels)` | Create with full configuration |
| `TimeSeries::univariate(values)` | Create simple single-dimension series |

#### Key Methods

| Method | Returns | Description |
|--------|---------|-------------|
| `len()` | `usize` | Number of observations |
| `dimensions()` | `usize` | Number of dimensions |
| `is_empty()` | `bool` | Check if series is empty |
| `is_multivariate()` | `bool` | Check if multi-dimensional |
| `timestamps()` | `&[DateTime<Utc>]` | Get timestamps |
| `values(dimension)` | `Result<&[f64]>` | Get values for dimension |
| `primary_values()` | `&[f64]` | Get first dimension values |
| `slice(start, end)` | `Result<TimeSeries>` | Extract subsequence |
| `has_missing_values()` | `bool` | Check for NaN/Inf |
| `missing_mask()` | `Vec<bool>` | Boolean mask: true where NaN/Inf (primary dimension) |
| `missing_count()` | `Vec<usize>` | Count of missing values per dimension |
| `interpolated(fill_edges)` | `TimeSeries` | Linear interpolation for NaN values |
| `sanitized(policy)` | `Result<TimeSeries>` | Apply missing value policy |
| `imputed_forward_backward()` | `TimeSeries` | Forward-fill then backward-fill |
| `imputed_moving_average(window)` | `Result<TimeSeries>` | Centered moving average imputation |
| `imputed_seasonal(period)` | `Result<TimeSeries>` | Seasonal median imputation |
| `with_imputed_regressors(policy)` | `Result<TimeSeries>` | Impute NaN in regressor vectors |

[Back to top](#api-reference)

---

### TimeSeriesBuilder

Builder pattern for constructing TimeSeries.

```rust
let ts = TimeSeriesBuilder::new()
    .timestamps(timestamps)
    .values(values)
    .frequency(Duration::days(1))
    .build()?;
```

| Method | Description |
|--------|-------------|
| `new()` | Create new builder |
| `timestamps(Vec<DateTime<Utc>>)` | Set timestamps |
| `values(Vec<f64>)` | Set univariate values |
| `multivariate_values(Vec<Vec<f64>>, ValueLayout)` | Set multivariate values |
| `labels(Vec<String>)` | Set dimension labels |
| `frequency(Duration)` | Set time frequency |
| `build()` | Build the TimeSeries |

[Back to top](#api-reference)

---

### Forecast

Prediction output containing point forecasts and optional confidence intervals.

```rust
pub struct Forecast {
    // Fields are private, use methods to access
}
```

#### Constructor Methods

| Method | Description |
|--------|-------------|
| `Forecast::new()` | Create empty forecast |
| `Forecast::from_values(values)` | Create from point forecasts |
| `Forecast::from_values_with_intervals(values, lower, upper)` | Create with intervals |

#### Key Methods

| Method | Returns | Description |
|--------|---------|-------------|
| `horizon()` | `usize` | Number of forecast steps |
| `primary()` | `&[f64]` | Get point forecasts |
| `lower()` | `Option<&[Vec<f64>]>` | Get lower bounds |
| `upper()` | `Option<&[Vec<f64>]>` | Get upper bounds |
| `has_lower()` | `bool` | Check if lower bounds exist |
| `has_upper()` | `bool` | Check if upper bounds exist |

[Back to top](#api-reference)

---

### ForecastError

Error types for forecasting operations.

```rust
pub enum ForecastError {
    EmptyData,
    InsufficientData { needed: usize, got: usize, hint: Option<String> },
    InvalidParameter(String),
    DimensionMismatch { expected: usize, got: usize },
    FitRequired,
    MissingValues,
    ComputationError(String),
    // ... other variants
}
```

| Variant | Description |
|---------|-------------|
| `EmptyData` | Input data is empty |
| `InsufficientData` | Not enough data points |
| `InvalidParameter` | Invalid parameter value |
| `DimensionMismatch` | Dimension mismatch in data |
| `FitRequired` | Model not fitted before prediction |
| `MissingValues` | Missing values detected |
| `ComputationError` | Numerical computation error |

[Back to top](#api-reference)

---

## Missing Value Imputation

Tools for handling NaN/Inf values before model fitting. All models reject missing values at `fit()` time, so imputation must be applied beforehand.

### MissingValuePolicy

```rust
pub enum MissingValuePolicy {
    Drop,           // Remove observations with NaN/Inf
    Fill(f64),      // Replace with specific value
    ForwardFill,    // Carry last valid value forward
    BackwardFill,   // Carry next valid value backward
    FillMean,       // Replace with mean of finite values
    FillMedian,     // Replace with median of finite values
    Interpolate,    // Linear interpolation (edges filled)
    Error,          // Return error if any missing
}
```

**Usage:**
```rust
use anofox_forecast::core::{TimeSeries, MissingValuePolicy};

// Apply policy via sanitized()
let clean = ts.sanitized(MissingValuePolicy::FillMean)?;
let clean = ts.sanitized(MissingValuePolicy::BackwardFill)?;
let clean = ts.sanitized(MissingValuePolicy::Interpolate)?;
```

### Imputation Methods

| Method | Description |
|--------|-------------|
| `sanitized(policy)` | Apply any `MissingValuePolicy` variant |
| `imputed_forward_backward()` | Forward-fill then backward-fill — handles both leading and trailing NaN |
| `imputed_moving_average(window)` | Centered window mean with multi-pass for adjacent gaps. Window must be odd. Remaining NaN filled with global mean. |
| `imputed_seasonal(period)` | Fill NaN with median of same seasonal position across cycles. Requires at least 1 full cycle. Errors if >50% missing in any bucket. |
| `with_imputed_regressors(policy)` | Apply fill policy to each regressor vector independently. Supports `Fill`, `ForwardFill`, `BackwardFill`, `FillMean`, `FillMedian`, `Interpolate`. |

### Metadata Helpers

| Method | Returns | Description |
|--------|---------|-------------|
| `has_missing_values()` | `bool` | True if any NaN/Inf in any dimension |
| `missing_mask()` | `Vec<bool>` | Per-observation mask for primary dimension |
| `missing_count()` | `Vec<usize>` | Count of NaN/Inf per dimension |

**Example — seasonal imputation:**
```rust
// Weekly data with gaps
let clean = ts.imputed_seasonal(7)?;  // Fill using same-weekday median
```

**Example — regressor imputation:**
```rust
let clean = ts.with_imputed_regressors(MissingValuePolicy::FillMean)?;
```

[Back to top](#api-reference)

---

## Forecaster Trait

Main trait interface that all forecasting models implement.

```rust
pub trait Forecaster {
    fn fit(&mut self, series: &TimeSeries) -> Result<()>;
    fn predict(&self, horizon: usize) -> Result<Forecast>;
    fn predict_with_intervals(&self, horizon: usize, level: f64) -> Result<Forecast>;
    fn fitted_values(&self) -> Option<&[f64]>;
    fn residuals(&self) -> Option<&[f64]>;
    fn name(&self) -> &str;
    fn is_fitted(&self) -> bool;
}
```

| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| `fit` | `series: &TimeSeries` | `Result<()>` | Fit model to data |
| `predict` | `horizon: usize` | `Result<Forecast>` | Generate point forecasts |
| `predict_with_intervals` | `horizon: usize, level: f64` | `Result<Forecast>` | Forecasts with confidence intervals |
| `fitted_values` | - | `Option<&[f64]>` | Get in-sample fitted values |
| `residuals` | - | `Option<&[f64]>` | Get residuals (actual - fitted) |
| `name` | - | `&str` | Model name |
| `is_fitted` | - | `bool` | Check if model is fitted |

[Back to top](#api-reference)

---

## Baseline Models

### Naive

Repeats the last observed value for all forecast horizons.

```rust
pub struct Naive;

impl Naive {
    pub fn new() -> Self;
}
```

**Example:**
```rust
let mut model = Naive::new();
model.fit(&ts)?;
let forecast = model.predict(12)?;
```

[Back to top](#api-reference)

---

### SeasonalNaive

Repeats values from the same season in the previous cycle.

```rust
pub struct SeasonalNaive {
    period: usize,
}

impl SeasonalNaive {
    pub fn new(period: usize) -> Self;
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `period` | `usize` | Seasonal period (e.g., 12 for monthly data) |

[Back to top](#api-reference)

---

### RandomWalkWithDrift

Random walk model with trend drift component.

```rust
pub struct RandomWalkWithDrift;

impl RandomWalkWithDrift {
    pub fn new() -> Self;
}
```

The drift is estimated as the average change between consecutive observations.

[Back to top](#api-reference)

---

### HistoricAverage

Forecasts the mean of all historical observations.

```rust
pub struct HistoricAverage;

impl HistoricAverage {
    pub fn new() -> Self;
}
```

[Back to top](#api-reference)

---

### WindowAverage

Moving window average forecaster.

```rust
pub struct WindowAverage {
    window: usize,
}

impl WindowAverage {
    pub fn new(window: usize) -> Self;
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `window` | `usize` | Number of observations to average |

[Back to top](#api-reference)

---

### SeasonalWindowAverage

Seasonal window-based averaging.

```rust
pub struct SeasonalWindowAverage {
    period: usize,
    window: usize,
}

impl SeasonalWindowAverage {
    pub fn new(period: usize, window: usize) -> Self;
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `period` | `usize` | Seasonal period |
| `window` | `usize` | Number of seasonal cycles to average |

[Back to top](#api-reference)

---

## Exponential Smoothing

### SimpleExponentialSmoothing

Simple exponential smoothing for non-seasonal, non-trending data.

```rust
pub struct SimpleExponentialSmoothing {
    alpha: Option<f64>,
}

impl SimpleExponentialSmoothing {
    pub fn new(alpha: f64) -> Self;
    pub fn auto() -> Self;
    pub fn alpha(&self) -> Option<f64>;
    pub fn level(&self) -> Option<f64>;
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `alpha` | `f64` | Smoothing parameter (0 < alpha < 1) |

| Method | Returns | Description |
|--------|---------|-------------|
| `auto()` | `Self` | Create with auto-optimized alpha |
| `alpha()` | `Option<f64>` | Get fitted alpha value |
| `level()` | `Option<f64>` | Get final level |

[Back to top](#api-reference)

---

### Holt

Holt's linear trend method (double exponential smoothing).

```rust
pub struct Holt {
    alpha: Option<f64>,
    beta: Option<f64>,
}

impl Holt {
    pub fn new(alpha: f64, beta: f64) -> Self;
    pub fn auto() -> Self;
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `alpha` | `f64` | Level smoothing (0 < alpha < 1) |
| `beta` | `f64` | Trend smoothing (0 < beta < 1) |

[Back to top](#api-reference)

---

### HoltWinters

Holt-Winters seasonal exponential smoothing.

```rust
pub struct HoltWinters {
    period: usize,
    seasonal_type: SeasonalType,
    alpha: Option<f64>,
    beta: Option<f64>,
    gamma: Option<f64>,
}

impl HoltWinters {
    pub fn new(period: usize, seasonal_type: SeasonalType) -> Self;
    pub fn with_params(period: usize, seasonal_type: SeasonalType,
                       alpha: f64, beta: f64, gamma: f64) -> Self;
    pub fn auto(period: usize, seasonal_type: SeasonalType) -> Self;
}

pub enum SeasonalType {
    Additive,
    Multiplicative,
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `period` | `usize` | Seasonal period |
| `seasonal_type` | `SeasonalType` | Additive or Multiplicative |
| `alpha` | `f64` | Level smoothing |
| `beta` | `f64` | Trend smoothing |
| `gamma` | `f64` | Seasonal smoothing |

[Back to top](#api-reference)

---

### ETS

Error-Trend-Seasonal state-space model following the [FPP3 taxonomy](https://otexts.com/fpp3/taxonomy.html).

```rust
pub struct ETS {
    spec: ETSSpec,
}

impl ETS {
    pub fn new(spec: ETSSpec, period: usize) -> Self;
}

pub struct ETSSpec {
    pub error: ErrorType,
    pub trend: TrendType,
    pub seasonal: SeasonalType,
}

pub enum ErrorType { Additive, Multiplicative }
pub enum TrendType { None, Additive, AdditiveDamped }
pub enum SeasonalType { None, Additive, Multiplicative }
```

#### ETS Model Taxonomy

This implementation follows the ETS taxonomy from [Forecasting: Principles and Practice (FPP3)](https://otexts.com/fpp3/taxonomy.html).

**Valid ETS Specifications (16 of 18 combinations):**

| Code | Name | Constructor |
|------|------|-------------|
| ANN | Simple exponential smoothing | `ETSSpec::ann()` |
| AAN | Holt's linear method | `ETSSpec::aan()` |
| AAdN | Additive damped trend | `ETSSpec::aadn()` |
| ANA | Seasonal (no trend, additive) | `ETSSpec::ana()` |
| ANM | Seasonal (no trend, multiplicative) | `ETSSpec::anm()` |
| AAA | Holt-Winters additive | `ETSSpec::aaa()` |
| AAM | Holt-Winters multiplicative seasonal | `ETSSpec::aam()` |
| AAdA | Damped Holt-Winters additive | `ETSSpec::aada()` |
| AAdM | Damped Holt-Winters multiplicative | `ETSSpec::aadm()` |
| MNN | Multiplicative error simple smoothing | `ETSSpec::mnn()` |
| MAN | Multiplicative error with trend | `ETSSpec::man()` |
| MAdN | Multiplicative error damped trend | `ETSSpec::madn()` |
| MNM | Multiplicative error and seasonal | `ETSSpec::mnm()` |
| MAM | Multiplicative Holt-Winters | `ETSSpec::mam()` |
| MAdM | Damped multiplicative Holt-Winters | `ETSSpec::madm()` |

**Invalid/Unstable (rejected):**

| Code | Reason |
|------|--------|
| MAA | Multiplicative error + additive trend + additive seasonal |
| MAdA | Multiplicative error + damped trend + additive seasonal |

#### Parsing ETS Notation

```rust
impl ETSSpec {
    /// Parse from notation string like "AAA", "MAM", "AAdM"
    pub fn from_notation(notation: &str) -> Result<Self>;

    /// Check if this combination is valid
    pub fn is_valid(&self) -> bool;
}
```

**Example:**
```rust
use anofox_forecast::models::exponential::ETSSpec;

// Parse notation
let spec = ETSSpec::from_notation("AAA")?;  // Holt-Winters additive
let spec = ETSSpec::from_notation("MAdM")?; // Damped multiplicative

// Invalid combinations return error
assert!(ETSSpec::from_notation("MAA").is_err());
```

[Back to top](#api-reference)

---

### AutoETS

Automatic ETS model selection using information criteria.

```rust
pub struct AutoETS {
    config: AutoETSConfig,
}

impl AutoETS {
    pub fn new() -> Self;
    pub fn with_config(config: AutoETSConfig) -> Self;
    pub fn with_period(period: usize) -> Self;
}

pub struct AutoETSConfig {
    pub criterion: SelectionCriterion,
    pub seasonal_period: Option<usize>,
    pub allow_multiplicative: bool,
}

pub enum SelectionCriterion { AIC, BIC, AICc }
```

[Back to top](#api-reference)

---

### SeasonalES

Multiplicative seasonal exponential smoothing.

```rust
pub struct SeasonalES {
    period: usize,
}

impl SeasonalES {
    pub fn new(period: usize) -> Self;
}
```

[Back to top](#api-reference)

---

## ARIMA Models

### ARIMA

Non-seasonal ARIMA(p,d,q) model.

```rust
pub struct ARIMA {
    spec: ARIMASpec,
}

impl ARIMA {
    pub fn new(p: usize, d: usize, q: usize) -> Self;
    pub fn spec(&self) -> &ARIMASpec;
    pub fn ar_coefficients(&self) -> &[f64];
    pub fn ma_coefficients(&self) -> &[f64];
    pub fn intercept(&self) -> f64;
    pub fn aic(&self) -> Option<f64>;
    pub fn bic(&self) -> Option<f64>;
}

pub struct ARIMASpec {
    pub p: usize,  // AR order
    pub d: usize,  // Differencing order
    pub q: usize,  // MA order
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `p` | `usize` | Autoregressive order |
| `d` | `usize` | Differencing order |
| `q` | `usize` | Moving average order |

[Back to top](#api-reference)

---

### SARIMA

Seasonal ARIMA(p,d,q)(P,D,Q)\[s\] model.

```rust
pub struct SARIMA {
    spec: SARIMASpec,
}

impl SARIMA {
    pub fn new(p: usize, d: usize, q: usize,
               cap_p: usize, cap_d: usize, cap_q: usize, s: usize) -> Self;
}

pub struct SARIMASpec {
    pub p: usize, pub d: usize, pub q: usize,       // Non-seasonal
    pub cap_p: usize, pub cap_d: usize, pub cap_q: usize,  // Seasonal
    pub s: usize,  // Seasonal period
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `p, d, q` | `usize` | Non-seasonal orders |
| `P, D, Q` | `usize` | Seasonal orders |
| `s` | `usize` | Seasonal period |

[Back to top](#api-reference)

---

### AutoARIMA

Automatic ARIMA order selection.

```rust
pub struct AutoARIMA {
    config: AutoARIMAConfig,
}

impl AutoARIMA {
    pub fn new() -> Self;
    pub fn with_config(config: AutoARIMAConfig) -> Self;
}

pub struct AutoARIMAConfig {
    pub max_p: usize,
    pub max_d: usize,
    pub max_q: usize,
    pub seasonal_period: Option<usize>,
    pub criterion: SelectionCriterion,
    pub stepwise: bool,
    pub true_stepwise: bool,  // Neighbor-based hill climbing
}

impl AutoARIMAConfig {
    pub fn with_true_stepwise(self, enabled: bool) -> Self;
    pub fn exhaustive(self) -> Self;
}
```

| Parameter | Description |
|-----------|-------------|
| `stepwise` | Use stepwise search (faster, fewer models) |
| `true_stepwise` | Use neighbor-based hill climbing (60-70% fewer evaluations) |

**Parallel Execution:**

Enable with `--features parallel` for 4-8x speedup on multi-core systems:
```toml
[dependencies]
anofox-forecast = { version = "0.3", features = ["parallel"] }
```

[Back to top](#api-reference)

---

## Theta Models

### Theta

Standard Theta Model (STM) for forecasting.

```rust
pub struct Theta {
    theta: f64,
    seasonal_period: usize,
    decomposition: DecompositionType,
}

impl Theta {
    pub fn new() -> Self;
    pub fn with_theta(theta: f64) -> Self;
    pub fn seasonal(period: usize) -> Self;
    pub fn seasonal_with_type(period: usize, decomposition: DecompositionType) -> Self;
}

pub enum DecompositionType {
    Additive,
    Multiplicative,
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `theta` | `f64` | Theta parameter (default: 2.0) |
| `period` | `usize` | Seasonal period (0 for non-seasonal) |
| `decomposition` | `DecompositionType` | Seasonal decomposition type |

[Back to top](#api-reference)

---

### OptimizedTheta

Theta model with optimized alpha and theta parameters.

```rust
pub struct OptimizedTheta;

impl OptimizedTheta {
    pub fn new() -> Self;
}
```

Parameters are optimized using Nelder-Mead minimization of MSE.

[Back to top](#api-reference)

---

### DynamicTheta

Theta with dynamic linear coefficient updates.

```rust
pub struct DynamicTheta {
    period: Option<usize>,
}

impl DynamicTheta {
    pub fn new(period: Option<usize>) -> Self;
}
```

[Back to top](#api-reference)

---

### DynamicOptimizedTheta

Combines dynamic updates with parameter optimization.

```rust
pub struct DynamicOptimizedTheta {
    period: Option<usize>,
}

impl DynamicOptimizedTheta {
    pub fn new(period: Option<usize>) -> Self;
}
```

[Back to top](#api-reference)

---

### AutoTheta

Automatic Theta model selection.

```rust
pub struct AutoTheta;

impl AutoTheta {
    pub fn new() -> Self;
}
```

Selects the best Theta variant based on cross-validation performance.

[Back to top](#api-reference)

---

## Intermittent Demand Models

### Croston

Croston's method for intermittent demand forecasting.

```rust
pub struct Croston {
    variant: CrostonVariant,
    alpha: f64,
}

impl Croston {
    pub fn new() -> Self;           // Classic variant
    pub fn classic() -> Self;
    pub fn sba() -> Self;           // Syntetos-Babai adjusted
    pub fn with_alpha(alpha: f64) -> Self;
}

pub enum CrostonVariant {
    Classic,
    SBA,  // Syntetos-Babai Approximation
}
```

| Variant | Description |
|---------|-------------|
| `Classic` | Original Croston method |
| `SBA` | Bias-corrected Syntetos-Babai variant |

[Back to top](#api-reference)

---

### TSB

Teunter-Syntetos-Babai method for intermittent demand.

```rust
pub struct TSB {
    alpha: f64,
    beta: f64,
}

impl TSB {
    pub fn new() -> Self;
    pub fn with_params(alpha: f64, beta: f64) -> Self;
}
```

[Back to top](#api-reference)

---

### ADIDA

Aggregate-Disaggregate Intermittent Demand Approach.

```rust
pub struct ADIDA {
    aggregation_level: usize,
}

impl ADIDA {
    pub fn new() -> Self;
    pub fn with_aggregation(level: usize) -> Self;
}
```

[Back to top](#api-reference)

---

### IMAPA

Intermittent Multiple Aggregation Prediction Algorithm.

```rust
pub struct IMAPA;

impl IMAPA {
    pub fn new() -> Self;
}
```

Combines forecasts from multiple aggregation levels.

[Back to top](#api-reference)

---

## Advanced Models

### MFLES

Multiple Fourier Linear Exponential Smoothing - gradient boosted decomposition.

```rust
pub struct MFLES {
    seasonal_periods: Vec<usize>,
}

impl MFLES {
    pub fn new(seasonal_periods: Vec<usize>) -> Self;
    pub fn with_max_rounds(rounds: usize) -> Self;
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `seasonal_periods` | `Vec<usize>` | Seasonal periods to model |
| `max_rounds` | `usize` | Maximum boosting iterations |

[Back to top](#api-reference)

---

### MSTLForecaster

MSTL decomposition-based forecaster for multiple seasonalities.

```rust
pub struct MSTLForecaster {
    seasonal_periods: Vec<usize>,
}

impl MSTLForecaster {
    pub fn new(seasonal_periods: Vec<usize>) -> Self;
}
```

[Back to top](#api-reference)

---

### TBATS

Trigonometric seasonality, Box-Cox transformation, ARMA errors, Trend, Seasonal components.

```rust
pub struct TBATS {
    seasonal_periods: Vec<usize>,
}

impl TBATS {
    pub fn new(seasonal_periods: Vec<usize>) -> Self;
}
```

Handles complex seasonal patterns with trigonometric representation.

[Back to top](#api-reference)

---

### AutoTBATS

Automatic TBATS configuration selection.

```rust
pub struct AutoTBATS;

impl AutoTBATS {
    pub fn new(seasonal_periods: Vec<usize>) -> Self;
}
```

[Back to top](#api-reference)

---

### GARCH

Generalized Autoregressive Conditional Heteroskedasticity for volatility modeling.

```rust
pub struct GARCH {
    p: usize,
    q: usize,
}

impl GARCH {
    pub fn new(p: usize, q: usize) -> Self;
}
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `p` | `usize` | GARCH order (variance lags) |
| `q` | `usize` | ARCH order (squared residual lags) |

[Back to top](#api-reference)

---

## Ensemble

Combines multiple forecasting models.

```rust
pub struct Ensemble {
    models: Vec<Box<dyn Forecaster>>,
    method: CombinationMethod,
}

impl Ensemble {
    pub fn new(models: Vec<Box<dyn Forecaster>>) -> Self;
    pub fn with_method(method: CombinationMethod) -> Self;
    pub fn with_weights(weights: Vec<f64>) -> Self;
}

pub enum CombinationMethod {
    Mean,
    Median,
    WeightedMSE,
    Custom,
}
```

| Method | Description |
|--------|-------------|
| `Mean` | Simple average of forecasts |
| `Median` | Median of forecasts |
| `WeightedMSE` | Inverse MSE weighting |
| `Custom` | User-provided weights |

[Back to top](#api-reference)

---

## Decomposition

### STL

Seasonal-Trend decomposition using LOESS.

```rust
pub struct STL {
    period: usize,
}

impl STL {
    pub fn new(period: usize) -> Self;
    pub fn decompose(&self, series: &[f64]) -> Result<STLResult>;
}

pub struct STLResult {
    pub seasonal: Vec<f64>,
    pub trend: Vec<f64>,
    pub remainder: Vec<f64>,
}
```

[Back to top](#api-reference)

---

### MSTL

Multiple Seasonal-Trend decomposition using LOESS.

```rust
pub struct MSTL {
    periods: Vec<usize>,
}

impl MSTL {
    pub fn new(periods: Vec<usize>) -> Self;
    pub fn decompose(&self, series: &[f64]) -> Result<MSTLResult>;
}

pub struct MSTLResult {
    pub seasonal_components: Vec<Vec<f64>>,
    pub trend: Vec<f64>,
    pub remainder: Vec<f64>,
}
```

[Back to top](#api-reference)

---

## Spectral Analysis

### Welch Periodogram

Welch's method for reduced variance spectral estimation using overlapping windowed segments.

```rust
/// Welch's periodogram for reduced variance spectral estimation
pub fn welch_periodogram(
    signal: &[f64],
    window_size: usize,  // Segment size (power of 2 recommended)
    overlap: f64,        // Overlap ratio (0.0-0.9, typically 0.5)
) -> Vec<(usize, f64)>;
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `signal` | `&[f64]` | Input time series |
| `window_size` | `usize` | Segment size (power of 2 for efficiency) |
| `overlap` | `f64` | Overlap ratio between segments (0.0-0.9) |

**Returns:** Vector of `(period, power)` tuples sorted by period (largest first).

**Example:**
```rust
use anofox_forecast::detection::welch_periodogram;

let signal: Vec<f64> = (0..256)
    .map(|i| (2.0 * std::f64::consts::PI * i as f64 / 12.0).sin())
    .collect();

let psd = welch_periodogram(&signal, 64, 0.5);
if let Some((period, _)) = psd.iter().max_by(|a, b| a.1.partial_cmp(&b.1).unwrap()) {
    println!("Dominant period: {}", period);
}
```

> **Note:** For comprehensive periodicity detection (ACF, FFT, Autoperiod, CFD-Autoperiod, SAZED),
> see the [fdars](https://crates.io/crates/fdars-core) crate.

[Back to top](#api-reference)

---

## Feature Extraction

The crate provides 76+ time series features organized by category.

### Basic Features

```rust
pub fn mean(series: &[f64]) -> f64;
pub fn median(series: &[f64]) -> f64;
pub fn variance(series: &[f64]) -> f64;
pub fn standard_deviation(series: &[f64]) -> f64;
pub fn minimum(series: &[f64]) -> f64;
pub fn maximum(series: &[f64]) -> f64;
pub fn sum_values(series: &[f64]) -> f64;
pub fn abs_energy(series: &[f64]) -> f64;
pub fn mean_abs_change(series: &[f64]) -> f64;
pub fn mean_change(series: &[f64]) -> f64;
```

### Distribution Features

```rust
pub fn skewness(series: &[f64]) -> f64;
pub fn kurtosis(series: &[f64]) -> f64;
pub fn quantile(series: &[f64], q: f64) -> f64;
pub fn variation_coefficient(series: &[f64]) -> f64;
```

### Autocorrelation Features

```rust
pub fn autocorrelation(series: &[f64], lag: usize) -> f64;
pub fn partial_autocorrelation(series: &[f64], lag: usize) -> f64;
```

### Entropy Features

```rust
pub fn approximate_entropy(series: &[f64], m: usize, r: f64) -> f64;
pub fn sample_entropy(series: &[f64], m: usize, r: f64) -> f64;
pub fn permutation_entropy(series: &[f64], order: usize) -> f64;
```

### Complexity Features

```rust
pub fn cid_ce(series: &[f64], normalize: bool) -> f64;
pub fn lempel_ziv_complexity(series: &[f64], threshold: Option<f64>) -> f64;
```

### Trend Features

```rust
pub fn linear_trend(series: &[f64]) -> LinearTrendResult;
pub fn ar_coefficient(series: &[f64], k: usize) -> f64;
```

[Back to top](#api-reference)

---

## Transformations

### Box-Cox

```rust
pub fn boxcox(series: &[f64], lambda: f64) -> Result<BoxCoxResult>;
pub fn boxcox_auto(series: &[f64]) -> Result<BoxCoxResult>;
pub fn inv_boxcox(transformed: &[f64], lambda: f64) -> Result<Vec<f64>>;
pub fn boxcox_lambda(series: &[f64]) -> Result<f64>;

pub struct BoxCoxResult {
    pub transformed: Vec<f64>,
    pub lambda: f64,
}
```

### Scaling

```rust
pub fn standardize(series: &[f64]) -> ScaleResult;
pub fn normalize(series: &[f64]) -> ScaleResult;
pub fn robust_scale(series: &[f64]) -> ScaleResult;

pub struct ScaleResult {
    pub scaled: Vec<f64>,
    pub mean: f64,
    pub std: f64,
}
```

### Window Functions

```rust
pub fn rolling_mean(series: &[f64], window: usize, center: bool) -> Vec<f64>;
pub fn rolling_std(series: &[f64], window: usize, center: bool) -> Vec<f64>;
pub fn rolling_min(series: &[f64], window: usize, center: bool) -> Vec<f64>;
pub fn rolling_max(series: &[f64], window: usize, center: bool) -> Vec<f64>;
pub fn expanding_mean(series: &[f64]) -> Vec<f64>;
pub fn ewm_mean(series: &[f64], span: f64) -> Vec<f64>;
```

[Back to top](#api-reference)

---

## Validation

### Residual Tests

```rust
pub fn ljung_box(residuals: &[f64], nlags: Option<usize>, seasonal: usize) -> LjungBoxResult;
pub fn box_pierce(residuals: &[f64], nlags: Option<usize>, seasonal: usize) -> LjungBoxResult;
pub fn durbin_watson(residuals: &[f64]) -> DurbinWatsonResult;

pub struct LjungBoxResult {
    pub statistic: f64,
    pub p_value: f64,
    pub degrees_of_freedom: usize,
}

pub struct DurbinWatsonResult {
    pub statistic: f64,  // Values near 2 indicate no autocorrelation
}
```

### Stationarity Tests

```rust
pub fn adf_test(series: &[f64], nlags: Option<usize>) -> StationarityResult;
pub fn kpss_test(series: &[f64], nlags: Option<usize>) -> StationarityResult;

pub struct StationarityResult {
    pub test_statistic: f64,
    pub p_value: f64,
    pub is_stationary: bool,
}
```

[Back to top](#api-reference)

---

## Changepoint Detection

PELT (Pruned Exact Linear Time) algorithm for changepoint detection.

```rust
pub fn pelt_detect(series: &[f64], config: &PeltConfig) -> PeltResult;

pub struct PeltConfig {
    pub penalty: f64,
    pub min_segment_length: usize,
    pub cost_fn: CostFunction,
}

impl PeltConfig {
    pub fn default() -> Self;
    pub fn penalty(penalty: f64) -> Self;
    pub fn with_bic_penalty(n: usize) -> Self;
}

pub enum CostFunction {
    L2,           // Squared cost (default)
    L1,           // Absolute cost, robust to outliers
    Normal,       // Normal likelihood
    Poisson,      // Poisson likelihood for count data
    LinearTrend,  // Detects slope/trend changes
    MeanVariance, // Joint mean and variance changes
    Cusum,        // Sustained mean shifts
}

pub struct PeltResult {
    pub changepoints: Vec<usize>,
    pub n_changepoints: usize,
}
```

[Back to top](#api-reference)

---

## Utilities

### Accuracy Metrics

```rust
pub fn calculate_metrics(actual: &[f64], predicted: &[f64],
                         seasonal_period: Option<usize>) -> Result<AccuracyMetrics>;

pub struct AccuracyMetrics {
    pub mae: f64,      // Mean Absolute Error
    pub mse: f64,      // Mean Squared Error
    pub rmse: f64,     // Root Mean Squared Error
    pub mape: f64,     // Mean Absolute Percentage Error
    pub smape: f64,    // Symmetric MAPE
    pub mase: f64,     // Mean Absolute Scaled Error
    pub r_squared: f64,
}
```

### Cross-Validation

```rust
pub fn cross_validate<F>(config: &CVConfig, series: &TimeSeries,
                         model_factory: F) -> Result<CVResults>;

pub struct CVConfig {
    pub horizon: usize,
    pub initial_window: usize,
    pub step_size: usize,
    pub strategy: CVStrategy,
}

pub enum CVStrategy {
    Rolling,    // Fixed window slides forward
    Expanding,  // Window grows over time
}

pub struct CVResults {
    pub n_folds: usize,
    pub aggregated: AggregatedMetrics,
    pub fold_metrics: Vec<AccuracyMetrics>,
}
```

### Optimization

```rust
pub fn nelder_mead(objective: fn(&[f64]) -> f64, initial: Vec<f64>,
                   config: &NelderMeadConfig) -> Result<NelderMeadResult>;

pub struct NelderMeadConfig {
    pub max_iter: usize,
    pub tolerance: f64,
}

pub struct NelderMeadResult {
    pub parameters: Vec<f64>,
    pub value: f64,
    pub iterations: usize,
}
```

[Back to top](#api-reference)

---

### Bootstrap Intervals

Bootstrap methods for empirical confidence intervals.

```rust
pub struct BootstrapConfig {
    pub n_samples: usize,      // Number of bootstrap samples (default: 1000)
    pub block_size: Option<usize>,  // Block size for block bootstrap
    pub seed: Option<u64>,     // Random seed for reproducibility
}

impl BootstrapConfig {
    pub fn new(n_samples: usize) -> Self;
    pub fn with_block_size(self, block_size: usize) -> Self;
    pub fn with_seed(self, seed: u64) -> Self;
}

pub struct BootstrapResult {
    pub lower: Vec<f64>,       // Lower bounds per horizon step
    pub upper: Vec<f64>,       // Upper bounds per horizon step
    pub level: f64,            // Confidence level used
    pub n_samples: usize,      // Number of samples used
}

/// Generate bootstrap confidence intervals
pub fn bootstrap_intervals<M: Forecaster + Clone>(
    model: &M,
    series: &TimeSeries,
    horizon: usize,
    level: f64,
    config: &BootstrapConfig,
) -> Result<BootstrapResult>;

/// Generate forecast with bootstrap intervals
pub fn bootstrap_forecast<M: Forecaster + Clone>(
    model: &M,
    series: &TimeSeries,
    horizon: usize,
    level: f64,
    config: &BootstrapConfig,
) -> Result<Forecast>;
```

| Method | Description |
|--------|-------------|
| Residual Bootstrap | Resamples fitted residuals with replacement |
| Block Bootstrap | Preserves autocorrelation structure |

**Example:**
```rust
use anofox_forecast::utils::bootstrap::{bootstrap_forecast, BootstrapConfig};

let config = BootstrapConfig::new(500).with_seed(42);
let forecast = bootstrap_forecast(&model, &ts, 12, 0.95, &config)?;
```

[Back to top](#api-reference)

---

## Probabilistic Postprocessing

The postprocessing module provides methods to convert point forecasts into calibrated
predictive distributions with coverage guarantees. It follows the approach of
[PostForecasts.jl](https://github.com/lipiecki/PostForecasts.jl).

### Core Types

#### PointForecasts

Point forecasts with optional timestamps and metadata.

```rust
pub struct PointForecasts {
    timestamps: Vec<DateTime<Utc>>,
    values: Vec<f64>,
    model_name: Option<String>,
}

impl PointForecasts {
    pub fn new(timestamps: Vec<DateTime<Utc>>, values: Vec<f64>) -> Result<Self>;
    pub fn from_values(values: Vec<f64>) -> Self;
    pub fn empty() -> Self;
    pub fn with_model_name(self, name: impl Into<String>) -> Self;
    pub fn len(&self) -> usize;
    pub fn values(&self) -> &[f64];
    pub fn timestamps(&self) -> &[DateTime<Utc>];
}
```

#### QuantileForecasts

Multi-quantile forecasts representing a discrete predictive distribution.

```rust
pub struct QuantileForecasts {
    timestamps: Vec<DateTime<Utc>>,
    quantiles: Vec<f64>,
    values: Vec<Vec<f64>>,  // values[time][quantile]
}

impl QuantileForecasts {
    pub fn new(timestamps: Vec<DateTime<Utc>>, quantiles: Vec<f64>, values: Vec<Vec<f64>>) -> Result<Self>;
    pub fn from_values(quantiles: Vec<f64>, values: Vec<Vec<f64>>) -> Result<Self>;
    pub fn n_times(&self) -> usize;
    pub fn n_quantiles(&self) -> usize;
    pub fn quantiles(&self) -> &[f64];
    pub fn at_time(&self, idx: usize) -> Option<&[f64]>;
    pub fn at_quantile(&self, idx: usize) -> Option<Vec<f64>>;
    pub fn median(&self) -> Option<Vec<f64>>;
    pub fn to_prediction_intervals(&self, coverage: f64) -> Option<PredictionIntervals>;
}
```

#### PredictionIntervals

Lower and upper bounds with coverage level.

```rust
pub struct PredictionIntervals {
    timestamps: Vec<DateTime<Utc>>,
    lower: Vec<f64>,
    upper: Vec<f64>,
    coverage: f64,
}

impl PredictionIntervals {
    pub fn new(timestamps: Vec<DateTime<Utc>>, lower: Vec<f64>, upper: Vec<f64>, coverage: f64) -> Result<Self>;
    pub fn from_bounds(lower: Vec<f64>, upper: Vec<f64>, coverage: f64) -> Result<Self>;
    pub fn lower(&self) -> &[f64];
    pub fn upper(&self) -> &[f64];
    pub fn coverage(&self) -> f64;
    pub fn widths(&self) -> Vec<f64>;
    pub fn midpoints(&self) -> Vec<f64>;
    pub fn contains(&self, values: &[f64]) -> Vec<bool>;
    pub fn empirical_coverage(&self, actuals: &[f64]) -> Option<f64>;
}
```

[Back to top](#api-reference)

---

### ConformalPredictor

Distribution-free prediction intervals with coverage guarantees.

```rust
pub struct ConformalPredictor {
    coverage: f64,
    method: ConformalMethod,
}

pub enum ConformalMethod {
    Split { cal_fraction: f64 },
    CrossVal { n_folds: usize },
    JackknifePlus,
}

impl ConformalPredictor {
    pub fn new(coverage: f64, method: ConformalMethod) -> Self;
    pub fn split(coverage: f64) -> Self;
    pub fn cross_val(coverage: f64, n_folds: usize) -> Self;
    pub fn jackknife_plus(coverage: f64) -> Self;
    pub fn fit(&self, forecasts: &[f64], actuals: &[f64]) -> Result<ConformalResult>;
    pub fn predict(&self, result: &ConformalResult, forecasts: &PointForecasts) -> PredictionIntervals;
    pub fn predict_values(&self, result: &ConformalResult, values: &[f64]) -> PredictionIntervals;
}

pub struct ConformalResult {
    pub fn scores(&self) -> &[f64];
    pub fn quantile_value(&self) -> f64;
    pub fn coverage(&self) -> f64;
    pub fn method(&self) -> &ConformalMethod;
}
```

| Method | Description |
|--------|-------------|
| `Split` | Fast method using a holdout calibration set |
| `CrossVal` | Uses all data via k-fold cross-validation |
| `JackknifePlus` | Leave-one-out with finite sample validity |

**Example:**
```rust
use anofox_forecast::postprocess::{ConformalPredictor, ConformalMethod, PointForecasts};

let predictor = ConformalPredictor::split(0.90);
let result = predictor.fit(&historical_forecasts, &historical_actuals)?;

let new_forecasts = PointForecasts::from_values(vec![20.0, 21.0, 22.0]);
let intervals = predictor.predict(&result, &new_forecasts);
```

[Back to top](#api-reference)

---

### HistoricalSimulator

Non-parametric empirical error distribution for uncertainty quantification.

```rust
pub struct HistoricalSimulator {
    quantiles: Vec<f64>,
    window_size: Option<usize>,
}

impl HistoricalSimulator {
    pub fn new(quantiles: Vec<f64>) -> Self;
    pub fn with_window(quantiles: Vec<f64>, window_size: usize) -> Self;
    pub fn fit(&self, forecasts: &[f64], actuals: &[f64]) -> Result<HistoricalSimResult>;
    pub fn predict_values(&self, result: &HistoricalSimResult, values: &[f64]) -> Result<QuantileForecasts>;
}
```

[Back to top](#api-reference)

---

### NormalPredictor

Gaussian error assumption baseline for uncertainty quantification.

```rust
pub struct NormalPredictor {
    quantiles: Vec<f64>,
}

impl NormalPredictor {
    pub fn new(quantiles: Vec<f64>) -> Self;
    pub fn fit(&self, forecasts: &[f64], actuals: &[f64]) -> Result<NormalResult>;
    pub fn predict_values(&self, result: &NormalResult, values: &[f64]) -> Result<QuantileForecasts>;
}
```

[Back to top](#api-reference)

---

### IDRPredictor

Isotonic Distributional Regression for state-of-the-art calibration.

```rust
pub struct IDRPredictor {
    quantiles: Vec<f64>,
}

impl IDRPredictor {
    pub fn new(quantiles: Vec<f64>) -> Self;
    pub fn fit(&self, forecasts: &[f64], actuals: &[f64]) -> Result<IDRResult>;
    pub fn predict_values(&self, result: &IDRResult, values: &[f64]) -> Result<QuantileForecasts>;
}
```

[Back to top](#api-reference)

---

### QRAPredictor

Quantile Regression Averaging for ensemble combining.

```rust
pub struct QRAPredictor {
    quantiles: Vec<f64>,
    regularization: QRARegularization,
}

pub enum QRARegularization {
    None,
    L1(f64),
    L2(f64),
}

impl QRAPredictor {
    pub fn new(quantiles: Vec<f64>) -> Self;
    pub fn with_regularization(quantiles: Vec<f64>, reg: QRARegularization) -> Self;
}
```

[Back to top](#api-reference)

---

### PostProcessor

Unified interface for all postprocessing methods.

```rust
pub struct PostProcessor {
    model: PostModel,
}

pub enum PostModel {
    Conformal { coverage: f64, method: ConformalMethod },
    HistoricalSim { quantiles: Vec<f64>, window_size: Option<usize> },
    Normal { quantiles: Vec<f64> },
    IDR { quantiles: Vec<f64> },
}

impl PostProcessor {
    pub fn new(model: PostModel) -> Self;
    pub fn conformal(coverage: f64) -> Self;
    pub fn historical_sim(quantiles: Vec<f64>) -> Self;
    pub fn normal(quantiles: Vec<f64>) -> Self;
    pub fn idr(quantiles: Vec<f64>) -> Self;
    pub fn train(&self, forecasts: &PointForecasts, actuals: &[f64]) -> Result<TrainedModel>;
    pub fn predict_intervals(&self, trained: &TrainedModel, forecasts: &PointForecasts) -> Result<PredictionIntervals>;
    pub fn predict_quantiles(&self, trained: &TrainedModel, forecasts: &PointForecasts) -> Result<QuantileForecasts>;
    pub fn point_to_quantiles(&self, train_forecasts: &PointForecasts, train_actuals: &[f64], predict_forecasts: &PointForecasts) -> Result<QuantileForecasts>;
}

pub enum TrainedModel {
    Conformal(ConformalResult),
    HistoricalSim(HistoricalSimResult),
    Normal(NormalResult),
    IDR(IDRResult),
}
```

**Example:**
```rust
use anofox_forecast::postprocess::{PostProcessor, PointForecasts};

// Create a conformal processor with 90% coverage
let processor = PostProcessor::conformal(0.90);

// Train on historical data
let train_forecasts = PointForecasts::from_values(historical_f);
let trained = processor.train(&train_forecasts, &historical_actuals)?;

// Generate prediction intervals
let new_forecasts = PointForecasts::from_values(new_f);
let intervals = processor.predict_intervals(&trained, &new_forecasts)?;
```

[Back to top](#api-reference)

---

### Backtesting

Rolling/expanding window backtesting with horizon-aware calibration.

```rust
pub struct BacktestConfig {
    pub initial_window: usize,
    pub step: usize,
    pub horizon: usize,
    pub expanding: bool,
    pub horizon_aware: bool,
}

impl BacktestConfig {
    pub fn new() -> Self;
    pub fn initial_window(self, size: usize) -> Self;
    pub fn step(self, step: usize) -> Self;
    pub fn horizon(self, horizon: usize) -> Self;
    pub fn expanding(self, expanding: bool) -> Self;
    pub fn horizon_aware(self, aware: bool) -> Self;
}

pub struct BacktestResult {
    pub fn n_folds(&self) -> usize;
    pub fn config(&self) -> &BacktestConfig;
    pub fn folds(&self) -> impl Iterator<Item = &BacktestFold>;
    pub fn coverage(&self) -> f64;
    pub fn calibration_error(&self, target_coverage: f64) -> f64;
    pub fn interval_widths(&self) -> f64;
    pub fn coverage_by_horizon(&self) -> &HashMap<usize, f64>;
    pub fn calibrated_model(&self, processor: &PostProcessor) -> Result<TrainedModel>;
    pub fn calibrated_model_by_horizon(&self, processor: &PostProcessor) -> Result<CalibratedModelByHorizon>;
}

pub struct BacktestFold {
    pub fold_idx: usize,
    pub train_start: usize,
    pub train_end: usize,
    pub test_start: usize,
    pub test_end: usize,
    pub intervals: PredictionIntervals,
    pub actuals: Vec<f64>,
    pub coverage: f64,
    pub avg_width: f64,
}
```

**Example:**
```rust
use anofox_forecast::postprocess::{PostProcessor, BacktestConfig, PointForecasts};

let processor = PostProcessor::conformal(0.90);

let config = BacktestConfig::new()
    .initial_window(100)
    .step(10)
    .horizon(7)
    .horizon_aware(true);

let forecasts = PointForecasts::from_values(all_forecasts);
let results = processor.backtest(&forecasts, &all_actuals, config)?;

println!("Coverage: {:.1}%", results.coverage() * 100.0);
println!("Calibration error: {:.3}", results.calibration_error(0.90));
```

[Back to top](#api-reference)

---

### Conformalize

Recalibrate quantile forecasts using conformal prediction.

```rust
pub fn conformalize(
    forecasts: &QuantileForecasts,
    calib_forecasts: &QuantileForecasts,
    calib_actuals: &[f64],
) -> Result<ConformalizeResult>;

pub fn conformalize_with_config(
    forecasts: &QuantileForecasts,
    calib_forecasts: &QuantileForecasts,
    calib_actuals: &[f64],
    config: ConformalizeConfig,
) -> Result<ConformalizeResult>;

pub struct ConformalizeConfig {
    method: ConformalMethod,
    symmetric: bool,
}

impl ConformalizeConfig {
    pub fn new() -> Self;
    pub fn method(self, method: ConformalMethod) -> Self;
    pub fn symmetric(self, symmetric: bool) -> Self;
}

pub struct ConformalizeResult {
    pub fn forecasts(&self) -> &QuantileForecasts;
    pub fn into_forecasts(self) -> QuantileForecasts;
    pub fn adjustments(&self) -> &[f64];
    pub fn original_coverage(&self) -> &[f64];
}
```

**Example:**
```rust
use anofox_forecast::postprocess::{conformalize, QuantileForecasts};

// Calibrate quantile forecasts
let calibrated = conformalize(&test_forecasts, &calib_forecasts, &calib_actuals)?;

// Get the recalibrated forecasts
let improved = calibrated.into_forecasts();
```

[Back to top](#api-reference)

---

## Prelude

Convenience re-exports for common usage:

```rust
pub use crate::core::{Forecast, TimeSeries};
pub use crate::error::{ForecastError, Result};
pub use crate::models::Forecaster;
pub use crate::utils::{calculate_metrics, AccuracyMetrics};
```

**Usage:**
```rust
use anofox_forecast::prelude::*;
```

[Back to top](#api-reference)
