cfad — Characteristic Function Anomaly Detector
cfad is research software for studying distributional change in financial return series with empirical characteristic functions (ECFs). It turns rolling ECF discrepancies into shape-sensitive anomaly scores, supports sequential Page-CUSUM monitoring, and includes model-comparison, goodness-of-fit, backtesting, bootstrap, sensitivity, notebook, dashboard, and benchmark workflows for reproducible experimentation.
The project is aimed at methodological research and validation rather than turnkey production trading signals. Its benchmarks explicitly preserve negative results and document where the current ECF score does, and does not, outperform simpler distributional summaries.
For each rolling window, CFAD compares the empirical characteristic function with the Gaussian characteristic function fitted to that window's sample mean and variance. The normalized real-frequency discrepancy is the anomaly score:
$$ D_t = \left[ \frac{1}{\xi_{\max}-\xi_{\min}} \int_{\xi_{\min}}^{\xi_{\max}} \left| \widehat\varphi_t(\xi)
\varphi_{\mathcal N(\widehat\mu_t,\widehat\sigma_t^2)}(\xi) \right|^2 ,d\xi \right]^{1/2}. $$
Because location and scale are fitted within each window, the score is aimed at higher-order shape changes such as tail and skewness changes. A two-sided Page-CUSUM then converts the score sequence into sequential alarms.
Scientific scope. The finite-sample ECF $\widehat\varphi_n(z)=n^{-1}\sum_j e^{izx_j}$ is a finite sum of entire functions and is itself entire. Therefore its exact closed-contour integral is zero. CFAD does not infer population-CF branch cuts or poles from an empirical contour residue. Complex contour integration remains available as a diagnostic helper for parametric characteristic functions evaluated at complex arguments, but it is not the empirical anomaly statistic.
Status
The repository is currently a research/development project. Version 0.2.2
is the first verified public release available both as a GitHub Release and on
PyPI. PyPI publication uses GitHub Actions OpenID Connect (OIDC) trusted
publishing rather than a long-lived API token.
Current validation boundary
Two frozen validation programmes have now tested the corrected method rather than the retired contour-residue interpretation.
The v2 sequential benchmark showed that Monte Carlo calibration can control the Gaussian-null false-alarm rate, but the Gaussian-reference score was not robust to a stable Student-t in-control law and had weak first-alarm power once false alarms were controlled. The v3 score-level ablation then removed CUSUM and separated frequency scaling from reference-law choice. Standardizing each window corrected the legacy score's sensitivity to pure variance changes, and a frozen empirical in-control ECF produced strong null-law stability. However, the empirical-reference score achieved AUC 0.646 for a Gaussian-to-Student-t shape change and 0.783 for a Gaussian-to-skew change, for an average of 0.715 versus 0.738 for a simple kurtosis-distance comparator.
Accordingly, the current evidence does not establish that CFAD is a validated
sequential detector or that its ECF score outperforms simpler moment summaries.
The negative v2 and v3 results are retained as reproducible evidence in
benchmarks/ and are treated as design constraints rather than tuned away.
Installation
From PyPI:
python -m pip install cfad
For development from the default branch:
git clone https://github.com/DiogoRibeiro7/cfad
cd cfad
git switch main
python -m pip install -e ".[dev]" --no-build-isolation
The package includes optional Cython acceleration for rolling ECF evaluation and CUSUM updates. The statistical score itself is implemented once in NumPy, so installing the extensions changes performance rather than the definition of the statistic.
Quick start
import numpy as np
from cfad import detect
rng = np.random.default_rng(42)
returns = np.concatenate(
[
rng.normal(0.0, 0.01, 300),
rng.standard_t(df=3.0, size=150) * 0.01 / np.sqrt(3.0),
]
)
report = detect(
returns,
window=60,
xi_range=(-10.0, 10.0),
step=1,
calibration_frac=0.4,
k=0.5,
h=5.0,
)
print(report.summary())
For market data, fetch the series explicitly with the provider of your choice,
then pass returns to detect. Keeping data acquisition outside the core example
makes the detector reproducible without relying on network access.
Detection pipeline
returns
│
├─ rolling ECF on a real-frequency grid
│
├─ fitted Gaussian CF in each window
│
├─ normalized ECF L2 shape distance D_t
│
├─ calibration of score mean/std on an in-control prefix
│
└─ two-sided Page-CUSUM → alarms
Parametric CF models
CFAD also implements characteristic-function models for descriptive model comparison and goodness-of-fit work:
| Model | Main use |
|---|---|
GaussianCF |
location/scale baseline |
NIGCF |
semi-heavy tails and skewness |
CGMYCF |
jump/tail-shape modelling |
LevyStableCF |
power-law tail modelling |
compare_models() compares fitted models by real-frequency ECF discrepancy and
AIC. A better-fitting non-Gaussian model is evidence of distributional fit, not
a direct empirical test for complex singularities.
Utilities
The repository includes:
rolling_gof,cf_distance, andepps_pulley_testfor ECF goodness of fit;WalkForwardBacktestfor temporal evaluation;- bootstrap and score-stability diagnostics;
window_sensitivity,frequency_sensitivity, and threshold sensitivity;- multivariate and market-oriented helpers;
- a Streamlit dashboard under
apps/; - reproducible notebooks and benchmark scripts.
Reproducibility
The main scientific validation target is not "does an alarm fire on one famous market event?" but how the detector behaves under controlled null and alternative data-generating processes. The benchmark layer reports false-positive behaviour, power/discrimination under prespecified shape changes, specificity to location/scale changes, and comparison against simpler baselines.
Frozen failed experiments are part of the evidence record. In particular,
benchmarks/v2_failed_calibration_record.json records the failed sequential
screen and benchmarks/v3_failed_score_validation_record.json records the failed
score-level screen. Those failures are not retroactively reclassified after
parameter or method changes.
Documentation and paper
- Published documentation: https://diogoribeiro7.github.io/cfad/
- MkDocs sources:
docs/ - Draft software paper:
paper/paper.md - Reproducible notebooks:
notebooks/ - Benchmarks:
benchmarks/
The manuscript is a draft companion to the software. Citation metadata should only advertise a journal DOI after an actual accepted/published record exists.
Author
Diogo Ribeiro
Faculty of Media Arts and Design, Technical University of Porto
ORCID: 0009-0001-2022-7072
License
MIT
Metadata
Release files for cfad 0.2.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cfad-0.2.3.tar.gz | 224.6 kB | Details |
Built distributions (wheels)
Total release size: 3.4 MB
Release files / cfad-0.2.3.tar.gz
| Download URL | cfad-0.2.3.tar.gz |
|---|---|
| Size | 224.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dfb765e5bc4c19f2329ad7320f0d5777f733dbece872802d0be5fc1fa6494156
|
|
BLAKE2b-256 checksum How to use checksums |
950f0a292e4cd7bcf4ed45b6806046fb6f8a17d9ed5f4e7608e1f3da99b41ba4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / cfad-0.2.3-cp312-cp312-win_amd64.whl
| Download URL | cfad-0.2.3-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 279.7 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
4eea88a087a507a16db63aa3721e61bdec13cc306511965d6c682d22d55b089b
|
|
BLAKE2b-256 checksum How to use checksums |
706a7f03158745330db7a79d7c9748ff88e495f976fd1dcc1db6f4ae80da0f2e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / cfad-0.2.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | cfad-0.2.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 541.9 kB |
| Tags | CPython 3.12 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
bf0404527ca454a12c42872adfde96eaed11e226c4aab8da7afa0304e2a67b6f
|
|
BLAKE2b-256 checksum How to use checksums |
4aa4aa0a5121073bbab3c944721fedf1734686c63e3f9cad483141d0a8f2f531
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / cfad-0.2.3-cp312-cp312-macosx_11_0_arm64.whl
| Download URL | cfad-0.2.3-cp312-cp312-macosx_11_0_arm64.whl |
|---|---|
| Size | 279.4 kB |
| Tags | CPython 3.12 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
69271c7816724d9ed8cfb39cf9cce272e554cb18c332ed92b8a4e6c255b79b01
|
|
BLAKE2b-256 checksum How to use checksums |
0d81c141f72dfc59908283bb00a89dde72862d4424fe21123930e59eda4685ca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / cfad-0.2.3-cp311-cp311-win_amd64.whl
| Download URL | cfad-0.2.3-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 276.7 kB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
fd609f201e5c1eb03e77453cff07a946c23b186cf52d7fb2334eff863c6d5522
|
|
BLAKE2b-256 checksum How to use checksums |
d23c8004d69d90dfdebf642b48a2974129bcedd04b2c41f7f0cc1af47c1c633e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / cfad-0.2.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | cfad-0.2.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 505.2 kB |
| Tags | CPython 3.11 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
1b6d64ae97f2639236c11c7e7c2b3cdfd04e8c7788c586cdd3be03289362db64
|
|
BLAKE2b-256 checksum How to use checksums |
f72d4ebc49c2225309b2953b36e48516732dcab79a8a91267bdf06665d00eea0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / cfad-0.2.3-cp311-cp311-macosx_11_0_arm64.whl
| Download URL | cfad-0.2.3-cp311-cp311-macosx_11_0_arm64.whl |
|---|---|
| Size | 276.7 kB |
| Tags | CPython 3.11 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
0cc7ae12cb9b204ed5583cbbe9ba98e569f674a3b7744c32f43fcecc9ff50b1e
|
|
BLAKE2b-256 checksum How to use checksums |
63203284e199c06bf52b329ed9139222a187dfe632dbc88ae5b62decee555a78
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / cfad-0.2.3-cp310-cp310-win_amd64.whl
| Download URL | cfad-0.2.3-cp310-cp310-win_amd64.whl |
|---|---|
| Size | 277.7 kB |
| Tags | CPython 3.10 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
ec170d9cae519f8779131346b4aee5dd92afa8a8bd30f2fbba525fa9a292893c
|
|
BLAKE2b-256 checksum How to use checksums |
c17ed27a16a167629d47fad4aa58a353f26fb719de943dd58d6b546175880783
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / cfad-0.2.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | cfad-0.2.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 499.9 kB |
| Tags | CPython 3.10 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
d46b0ba631497141cd533bc7542df8ccd7eada8b7ac8ca94e47e68e4ed24df94
|
|
BLAKE2b-256 checksum How to use checksums |
edef8ee7809a2104f194eb8903cdf19d845afd28c5514541889151f72a04fe52
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / cfad-0.2.3-cp310-cp310-macosx_11_0_arm64.whl
| Download URL | cfad-0.2.3-cp310-cp310-macosx_11_0_arm64.whl |
|---|---|
| Size | 278.1 kB |
| Tags | CPython 3.10 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
49ccbed221def626c9246e94b69d6aca1059838ef41c9fe304df51e6e92a1935
|
|
BLAKE2b-256 checksum How to use checksums |
1729b48c86a67d3c3233f1e2b6f0207f7f0dd0177f40747602299dcb7e4c448a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency log