Rust-implemented time-series utilities exposed to Python via PyO3.
Project description
rust_timeseries — Python bindings for duration models and tests
rust_timeseries is a Python-first package for
- modelling event-time durations with ACD-type models,
- calling a Rust-implemented maximum-likelihood optimizer,
- extracting fitted parameters and optimizer diagnostics, and
- running the Escanciano–Lobato heteroskedasticity proxy test.
All heavy computation runs in Rust (see lib.rs, duration, and statistical_tests),
but the public surface is a small, typed Python API defined by the compiled
_rust_timeseries extension and the stub files
duration_models.pyistatistical_tests.pyi.
This document describes only what is actually exposed through those bindings.
1. Installation
From source, using maturin (development workflow):
maturin develop --release
Once the wheel is installed into your environment you can import:
import rust_timeseries as rts
and typically:
from rust_timeseries import duration_models, statistical_tests
A future PyPI release will allow installation via
pip install rust_timeseries
without changing the Python API.
2. Python modules
The Python-visible layout mirrors the bindings defined in lib.rs:
rust_timeseries/
duration_models.py # ACD models and optimization results
statistical_tests.py # Escanciano–Lobato test
_rust_timeseries.* # compiled extension (internal)
Rust-only modules such as duration, inference, optimization, and utils
are implementation details and are not part of the public Python API.
Users should import only from
rust_timeseries.duration_modelsrust_timeseries.statistical_tests.
3. Duration models (rust_timeseries.duration_models)
The duration_models module is the main entry point for ACD(p, q)-type duration
processes. The public classes implemented in lib.rs and described in
duration_models.pyi are:
ACD– duration model used from Python,ACDOptimOutcome– optimization diagnostics,ACDFittedParams– fitted model-space parameters.
3.1 Constructing an ACD model
ACD instances are configured once and reused across fits. The constructor
exposes the same arguments that the PyO3 wrapper forwards into Rust:
from rust_timeseries.duration_models import ACD
acd = ACD(
data_length=len(durations), # in-sample length
p=1, # AR order of ψ_t (optional)
q=1, # MA order of durations (optional)
init=None,
init_fixed=None,
init_psi_lags=None,
init_durations_lags=None,
tol_grad=None,
tol_cost=None,
max_iter=None,
line_searcher=None,
lbfgs_mem=None,
psi_guards=None,
)
Key arguments (see duration_models.pyi for full details):
data_length: int
Length of the in-sample duration series. This determines internal buffer sizes and is checked whenever you callfit,forecast, orstandard_errors.p: int | None,q: int | None
Model orders. At least one of them must be positive.init,init_fixed,init_psi_lags,init_durations_lags
Initialization policy and associated values, forwarded unchanged to Rust-side initialization logic.tol_grad,tol_cost,max_iter,line_searcher,lbfgs_mem
Optimizer tolerances and configuration.psi_guards: tuple[float, float] | None
Optional lower/upper bounds on the conditional mean process ψ_t, mapped into Rust asPsiGuards.
The default constructor uses an exponential innovation distribution. Two alternative constructors are available:
ACD.wacd(...)– Weibull-innovation ACD(p, q) with shape parameterk.ACD.gacd(...)– generalized-gamma-innovation ACD(p, q) with shape parametersp_shapeandd_shape.
Both wacd and gacd accept the same configuration arguments as ACD
(including data_length, p, q, and optimizer settings), plus their
respective shape parameters.
3.2 Fitting a model (ACD.fit)
Model fitting is performed by calling fit on an ACD instance. The method
is backed by the Rust function ACDModel::fit and stores results on the
Python object; it does not return the fitted parameters directly.
Minimal example:
import numpy as np
from rust_timeseries.duration_models import ACD
durations = np.asarray(durations, dtype=float)
acd = ACD(data_length=len(durations), p=1, q=1)
# Initial parameter guess in the unconstrained parameterization.
theta0 = np.asarray(theta0, dtype=float)
acd.fit(
durations=durations,
theta0=theta0,
unit="seconds", # or other supported unit strings
t0=None, # optional index offset
diurnal_adjusted=False # whether durations are already adjusted
)
Signature (from the bindings):
def fit(
self,
durations,
theta0,
unit: str | None = "seconds",
t0: int | None = None,
diurnal_adjusted: bool | None = False,
) -> None: ...
On success, the fitted model state is cached inside the Rust ACDModel.
You can then access:
acd.results– anACDOptimOutcomeinstance with optimizer diagnostics,acd.fitted_params– anACDFittedParamsinstance with model parameters.
Both are defined as @property-style getters in lib.rs.
If you call results or fitted_params before any successful fit, the
bindings raise a Python exception originating from the Rust
ACDError::ModelNotFitted variant.
3.3 Forecasting (ACD.forecast and ACD.forecast_result)
Forecasts are produced via ACD.forecast, which delegates to the Rust
ACDModel::forecast and stores the forecast path internally:
horizon = 20
psi_h = acd.forecast(
durations=durations,
horizon=horizon,
unit="seconds",
t0=None,
diurnal_adjusted=False,
)
Signature:
def forecast(
self,
durations,
horizon: int,
unit: str | None = "seconds",
t0: int | None = None,
diurnal_adjusted: bool | None = False,
) -> float: ...
The return value is the final forecasted ψ at the requested horizon, while the full path is cached and exposed through
acd.forecast_result– a 1-D list offloatcorresponding to the most recent forecast call.
If forecast has not yet been called, forecast_result returns an empty list.
3.4 Standard errors (ACD.standard_errors)
The standard_errors method computes model parameter standard errors for a
given duration series, optionally using HAC corrections. It forwards
options directly into the Rust-side HAC implementation via extract_hac_options
and ACDModel::standard_errors.
Example:
se = acd.standard_errors(
durations=durations,
unit="seconds",
t0=None,
diurnal_adjusted=False,
robust=True,
kernel="bartlett",
bandwidth=None,
center=False,
small_sample_correction=True,
)
Signature:
def standard_errors(
self,
durations,
unit: str | None = "seconds",
t0: int | None = None,
diurnal_adjusted: bool | None = False,
robust: bool | None = False,
kernel: str | None = "bartlett",
bandwidth: int | None = None,
center: bool | None = False,
small_sample_correction: bool | None = True,
) -> list[float]: ...
Return value:
- A Python
list[float]with standard errors corresponding to the fitted parameter vector. Whenrobust=False, these are based on the model-based information matrix; whenrobust=True, a HAC estimator is used.
3.5 Optimization diagnostics (ACDOptimOutcome)
The ACD.results property returns an ACDOptimOutcome object, which is a
thin wrapper around the Rust OptimOutcome type. The PyO3 bindings defined
in lib.rs expose the following attributes:
theta_hat: list[float]
Final parameter vector in the unconstrained parameterization.value: float
Objective value at the solution (e.g. maximized log-likelihood or its negation, depending on configuration).converged: bool
Whether the optimizer terminated with a successful status.status: str
Human-readable termination reason.iterations: int
Number of iterations taken.grad_norm: float | None
Norm of the gradient at the solution, when available.fn_evals: list[tuple[str, int]]
Evaluation counters keyed by function name.
A typical access pattern:
outcome = acd.results
print("Converged:", outcome.converged, "-", outcome.status)
print("Objective value:", outcome.value)
print("Iterations:", outcome.iterations)
print("Gradient norm:", outcome.grad_norm)
print("Function evals:", outcome.fn_evals)
3.6 Fitted parameters (ACDFittedParams)
The ACD.fitted_params property returns an ACDFittedParams instance that
wraps the Rust ACDParams struct. The bindings in lib.rs expose the
following read-only properties:
omega: float
Baseline level parameter.slack: float
Positive slack term used to enforce strict stationarity.alpha: list[float]
Vector of ARCH-type coefficients (sizep).beta: list[float]
Vector of GARCH-type coefficients (sizeq).psi_lags: list[float]
Initialization lags for ψ_t used at the start of the sample.
Example:
params = acd.fitted_params
print("omega:", params.omega)
print("slack:", params.slack)
print("alpha:", params.alpha)
print("beta:", params.beta)
print("psi_lags:", params.psi_lags)
These values are guaranteed (by the Rust-side constructors) to satisfy the
model invariants documented in ACDParams (positivity, stationarity, shape
constraints).
4. Escanciano–Lobato test (rust_timeseries.statistical_tests)
The statistical_tests module currently exposes a single class,
EscancianoLobato, which implements the Escanciano–Lobato heteroskedasticity
proxy test from the Rust type ELOutcome.
4.1 Constructing EscancianoLobato
The constructor validates inputs, converts them into a contiguous float64
slice, runs the test in Rust, and stores the result:
import numpy as np
from rust_timeseries.statistical_tests import EscancianoLobato
residuals = np.asarray(residuals, dtype=float)
el = EscancianoLobato(
residuals, # 1-D array-like of float64, no NaNs, length >= 1
q=2.4, # positive float proxy order (optional)
d=None, # positive integer max lag; default floor(n**0.2)
)
Signature (from statistical_tests.pyi and lib.rs):
class EscancianoLobato:
def __init__(
self,
data,
q: float | None = 2.4,
d: int | None = None,
) -> None: ...
Validation rules enforced in the bindings:
datamust be non-empty and contain no NaNs,qmust be positive when provided,dmust be positive when provided.
If any of these fail, a ValueError is raised from the PyO3 binding.
4.2 Accessing test results
EscancianoLobato wraps a Rust ELOutcome and exposes three read-only
properties:
statistic: float
The test statistic.pvalue: float
Asymptotic p-value under the null.p_tilde: int
Data-driven lag choice that maximizes the penalized statistic.
Example:
print("EL statistic:", el.statistic)
print("EL p-value:", el.pvalue)
print("Selected lag p~:", el.p_tilde)
5. Design notes
-
Python-first
The core of the codebase lives in Rust, but the bindings are designed so that quantitative researchers can stay in Python. Inputs are standard array-like objects (numpy.ndarray,pandas.Series, Python lists), and outputs are plain Python scalars and lists. -
Tight coupling to Rust invariants
The PyO3 layer performs only shape checks, basic validation, and error mapping. All model invariants (positivity, stationarity, etc.) are enforced in the Rust types (ACDModel,ACDParams,ELOutcome). -
Explicit error reporting
Whenever a Rust error is raised (for example via theACDErrortype), it is surfaced as a Python exception with a clear string message. Fitted-state- dependent getters (results,fitted_params) fail loudly if you call them beforefit. -
Minimal, inspectable objects
The Python wrappers (ACD,ACDOptimOutcome,ACDFittedParams,EscancianoLobato) are intentionally small and read-only. They are easy to log, serialize, or convert to dictionaries for downstream analysis.
6. Status and extension points
The current Python API is intentionally narrow and corresponds exactly to the
bindings implemented in lib.rs and documented in duration_models.pyi and
statistical_tests.pyi. Natural extensions, to be added in Rust and then
surfaced through the same pattern, include:
- additional duration families that reuse the same
ACDinterface, - further goodness-of-fit and residual tests under
statistical_tests, - higher-level helpers for multi-asset or panel duration data.
When extending the library, keep the following principles:
- add functionality first in the Rust core,
- expose it through a PyO3 wrapper (
#[pyclass]or#[pymethods]), - update the
.pyistubs to match, - and only then document it here.
This keeps the README, the stubs, and the compiled extension in sync.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rust_timeseries-1.0.0.tar.gz.
File metadata
- Download URL: rust_timeseries-1.0.0.tar.gz
- Upload date:
- Size: 1.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f8b10152d50a49fcd7c281a8db58b416ec293d73eecc0279a46cc6184f7271d
|
|
| MD5 |
e55d2e800d534a04efe769e51aa95d3a
|
|
| BLAKE2b-256 |
1226c8ea529bb25963d25679cf4b733f0e039e87f22d9e660643074294bbec8b
|
File details
Details for the file rust_timeseries-1.0.0-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: rust_timeseries-1.0.0-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 431.2 kB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
534742a81ad452f7ee2a48ea950f4988bbc38826a2781d2b3a011b774784e921
|
|
| MD5 |
0c185edf22ec3bfd3661127cb2f2cbcb
|
|
| BLAKE2b-256 |
e67afa5bed65eeebc9723c61cfc2bed59c16d49708618df4c324d792fe931d7a
|
File details
Details for the file rust_timeseries-1.0.0-cp313-cp313-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: rust_timeseries-1.0.0-cp313-cp313-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 605.5 kB
- Tags: CPython 3.13, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66db7d693fba6c231ea10805d103313798f131372881e2e004f0a44b4ece463c
|
|
| MD5 |
091341d82296966228e7adf8042b6d00
|
|
| BLAKE2b-256 |
c520710daaff58c84a189caed153f945e6edf293f35c2bf93b54a0180a7c0079
|
File details
Details for the file rust_timeseries-1.0.0-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: rust_timeseries-1.0.0-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 522.6 kB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
326cb1e627f282b58345dcdc59e30c9b01fa859d5efdfd0ffe577b06bd76a60f
|
|
| MD5 |
83cecbe5536a2deb812be57bb3ee7816
|
|
| BLAKE2b-256 |
e51832bf91a09d99b0ef0c0a55f7b48c6310bc8d47488c837d27fd1934b9d3d8
|
File details
Details for the file rust_timeseries-1.0.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: rust_timeseries-1.0.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 431.6 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
618b9750967661fcdd2b4d8622d99d043a047731c39b24487266eee2cf5555d2
|
|
| MD5 |
493264565879401537b17d72f9f199f1
|
|
| BLAKE2b-256 |
566ef5a99bb045b5768623e889e7c50176869131444dcf72c56af2357c67dc32
|
File details
Details for the file rust_timeseries-1.0.0-cp312-cp312-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: rust_timeseries-1.0.0-cp312-cp312-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 606.1 kB
- Tags: CPython 3.12, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6486b54c2638707a50104b4eb3611c340e2d7ecfb133b5e9be85916885ff23ba
|
|
| MD5 |
2960acfce5d94a8fcd1c423fe759ec89
|
|
| BLAKE2b-256 |
3a2f6a912b880b33d76bb4d56a7d6e22635ab6c0bf735e2eab65ffd6055a6059
|
File details
Details for the file rust_timeseries-1.0.0-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: rust_timeseries-1.0.0-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 522.8 kB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36076501f7240ff289d5442dedb16ce8b094421796af84a41fb44ff3940ddcec
|
|
| MD5 |
407f1c902689b3c43de89b9b5978de9a
|
|
| BLAKE2b-256 |
161ffae76990d5870c5f5252d517533920ea05a3b3cab1ece8519ddc828e98e1
|
File details
Details for the file rust_timeseries-1.0.0-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: rust_timeseries-1.0.0-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 427.3 kB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b74a896d9aaec942cfec9f48ab6514be019bc19a638926dd7062f9cf34956bbd
|
|
| MD5 |
f5ec87ca2e4637b7c01597efc9ead086
|
|
| BLAKE2b-256 |
4df72ff962f1ae9898983f24322a679fb380692bec621bd07b103b7d351b7b10
|
File details
Details for the file rust_timeseries-1.0.0-cp311-cp311-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: rust_timeseries-1.0.0-cp311-cp311-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 603.4 kB
- Tags: CPython 3.11, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0935b24b76d21ad403b8839cb7179a111d3a8d94855b0b851bc2776d63f3bffb
|
|
| MD5 |
ad30b6f9c077eea570a6bcb87c1b9101
|
|
| BLAKE2b-256 |
29d89ee12ed5cfbe1ed845fc71de08edbdcc042c6b10127ade1d82109ab734b9
|
File details
Details for the file rust_timeseries-1.0.0-cp311-cp311-macosx_11_0_arm64.whl.
File metadata
- Download URL: rust_timeseries-1.0.0-cp311-cp311-macosx_11_0_arm64.whl
- Upload date:
- Size: 526.6 kB
- Tags: CPython 3.11, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2abfc1194bac6cc913d318a5e6157fe75dc6838b1b90d1dc6140dae6a133010
|
|
| MD5 |
6cfea140df1a3ef44e967fc2287ddc04
|
|
| BLAKE2b-256 |
39f19368b421169320cf2093986e5f1ae90ea2218098453cf4b475bce0e0c925
|