Metadata-Version: 2.4
Name: pairscan-rmr
Version: 0.1.0
Summary: Ratio mean-reversion testing for asset pairs. Hurst, ADF, walk-forward backtest.
Project-URL: Homepage, https://pairscan.io
Project-URL: Repository, https://github.com/pairscan/ratio-mean-reversion
Project-URL: Documentation, https://pairscan.io/methodology
Project-URL: Issues, https://github.com/pairscan/ratio-mean-reversion/issues
Project-URL: Changelog, https://github.com/pairscan/ratio-mean-reversion/blob/main/CHANGELOG.md
Author-email: Pairscan <hello@pairscan.io>
License: MIT License
        
        Copyright (c) 2026 Pairscan
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: adf-test,backtest,cryptocurrency,hurst-exponent,mean-reversion,pairs-trading,quantitative-finance,statistical-arbitrage,tokenized-equities
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Mathematics
Requires-Python: >=3.10
Requires-Dist: numpy>=1.24
Requires-Dist: statsmodels>=0.14
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Provides-Extra: examples
Requires-Dist: ccxt>=4.0; extra == 'examples'
Requires-Dist: jupyter>=1.0; extra == 'examples'
Requires-Dist: matplotlib>=3.5; extra == 'examples'
Requires-Dist: pandas>=2.0; extra == 'examples'
Description-Content-Type: text/markdown

# pairscan-rmr

[![PyPI](https://img.shields.io/pypi/v/pairscan-rmr)](https://pypi.org/project/pairscan-rmr/)
[![Tests](https://github.com/pairscan/ratio-mean-reversion/actions/workflows/tests.yml/badge.svg)](https://github.com/pairscan/ratio-mean-reversion/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)

**Ratio mean-reversion testing for asset pairs.** Hurst exponent + ADF + range filters + walk-forward backtest. No lookahead. MIT license.

This is the open-source utility behind [pairscan.io](https://pairscan.io) — a screener for pair trading on crypto and tokenized US equities. It does **one thing**: takes two price series, tells you whether their log-ratio shows mean-reversion, and if so, what a walk-forward backtest would have looked like.

## What this does (and doesn't do)

✅ **Does:**
- Compute Hurst exponent via R/S analysis
- Run Augmented Dickey-Fuller test for stationarity
- Test range width and alternating boundary touches
- Combine all four into a single `is_mean_reverting()` predicate
- Walk-forward backtest one pair (rolling P5/P95, no lookahead)

❌ **Doesn't:**
- Fetch data from exchanges (use `ccxt`, `yfinance`, or your own pipeline)
- Screen multiple pairs (this is a single-pair tool)
- Validate tokenized asset pegs against oracles
- Run scheduled, multi-source data fallback
- Send alerts

If you need those, [pairscan.io](https://pairscan.io) does them as a hosted product — that's our commercial offering. This package is the math, free and open.

## Install

```bash
pip install pairscan-rmr
```

## Quick start

```python
import numpy as np
from pairscan_rmr import is_mean_reverting, walk_forward_backtest

# Your price series — daily closes for two assets
price_a = np.array([...])  # e.g. ETH daily closes
price_b = np.array([...])  # e.g. BTC daily closes

# Step 1: Does this pair mean-revert?
result = is_mean_reverting(price_a, price_b)
print(result)
# MeanReversionResult(passed=True, hurst=0.42, adf_pvalue=0.31,
#                      range_width=0.53, low_touches=3, high_touches=2)

# Step 2: If yes, run a walk-forward backtest
if result.passed:
    backtest = walk_forward_backtest(
        price_a, price_b,
        lookback_days=540,
        entry_low=0.2,
        entry_high=0.8,
        fee_pct=0.001,
    )
    print(f"Final A qty: {backtest.final_a_qty:.2f}")
    print(f"Final B qty: {backtest.final_b_qty:.2f}")
    print(f"Trades:      {backtest.n_trades}")
    print(f"Max drawdown: {backtest.max_drawdown:.1%}")
```

## Why we open-sourced this

Because the math has been public since 1951. Hurst (1951), Dickey-Fuller (1979), Lo-MacKinlay (1988) — none of this is proprietary. Anyone can reimplement it in an afternoon.

What's not in this repo is what makes [pairscan.io](https://pairscan.io) worth $19/mo: 5-source data fallback, oracle peg-check on tokenized assets, 170-pair screening every 6 hours, cross-sector matching, Telegram alerts. That's operational engineering, and that's what we sell.

The math should be free. The pipeline costs money to run.

## Methodology

Brief intro below. Full walkthrough with derivations and academic references at [pairscan.io/methodology](https://pairscan.io/methodology).

### Hurst exponent (R/S analysis)

Measures long-term memory of a time series:
- `H < 0.5` — anti-persistent / mean-reverting (we want this)
- `H = 0.5` — random walk
- `H > 0.5` — persistent / trending

We compute it on the **log-ratio**, not raw prices.

### ADF test

Augmented Dickey-Fuller checks for unit root. Low p-value → stationarity → mean to revert to. We use a **loose threshold (p < 0.7)** combined with other filters — strict p < 0.05 throws out genuinely mean-reverting crypto pairs because crypto data is noisier than equities.

### Range width and alternating touches

Operational filters: range must span ≥ 40% (so swap fees don't kill returns) and the series must touch both boundaries multiple times alternately (so it's genuinely oscillating, not just visiting an extreme once).

### Walk-forward backtest

At each decision point t, only data **up to t** is used to set entry/exit thresholds. The percentile bounds are recomputed every day on a trailing 540-day window. This is the only way to honestly simulate "what would have happened if I'd been running this in real time".

## Verification: how to know there's no lookahead bias

`tests/test_no_lookahead.py` runs the same backtest twice — once with clean data, once with all data after a midpoint replaced with garbage — and asserts the two trade lists are byte-identical up to the midpoint. If a future-dependent statistic ever leaks in, the test fails immediately. Look at it before trusting the backtest output.

## Examples

See [`examples/`](./examples) for runnable scripts:

1. **01_quick_start.py** — 5 minutes, synthetic data
2. **02_synthetic_series.py** — Ornstein-Uhlenbeck (mean-reverting) and GBM (trending) as ground truth — check that filters classify them correctly
3. **03_real_crypto_pair.py** — ETH/BTC via `ccxt`, full pipeline
4. **04_walk_forward_explained.py** — visual comparison with naive in-sample backtest

## Limitations

We're explicit about where this fails. See full discussion at [pairscan.io/methodology](https://pairscan.io/methodology):

- Hurst R/S has variance — sensitive to `max_lag` choice
- ADF assumes stationary residuals — structural breaks mislead it
- Tests are **descriptive**, not predictive
- Sample size matters: < 200 days = noise, < 540 days = use with caution
- Real execution adds slippage, taxes, exchange downtime — none modeled

## Contributing

PRs welcome, especially:
- Performance improvements (vectorization, Numba)
- Additional tests (edge cases, numerical stability)
- Examples on different asset classes (FX, commodities, equities)

See [CONTRIBUTING.md](./CONTRIBUTING.md).

## License

MIT — do whatever you want, attribution appreciated.

## Citation

If you use this in research:

```bibtex
@software{pairscan_rmr,
  author = {Pairscan},
  title  = {pairscan-rmr: Ratio mean-reversion testing for asset pairs},
  url    = {https://github.com/pairscan/ratio-mean-reversion},
  year   = {2026}
}
```

## Acknowledgments

- Hurst, H.E. (1951). *Long-term storage capacity of reservoirs*. Transactions of the American Society of Civil Engineers, 116, 770–799.
- Dickey, D.A. & Fuller, W.A. (1979). *Distribution of the Estimators for Autoregressive Time Series with a Unit Root*. JASA, 74, 427–431.
- Gatev, E., Goetzmann, W.N. & Rouwenhorst, K.G. (2006). *Pairs Trading: Performance of a Relative-Value Arbitrage Rule*. Review of Financial Studies, 19(3), 797–827.
