Metadata-Version: 2.5
Name: sophostechne-quant
Version: 1.3.0
Summary: Evolve, test and optimise trading strategies.
Project-URL: Repository, https://github.com/sophostechne/quant
Project-URL: Issues, https://github.com/sophostechne/quant/issues
Author: Sophos Techne
License-Expression: MIT
License-File: LICENSE
Keywords: backtesting,evolutionary,quantitative,strategy,trading
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial :: Investment
Requires-Python: <3.15,>=3.12
Requires-Dist: nautilus-trader>=1.230
Requires-Dist: pandas>=2.0
Description-Content-Type: text/markdown

# quant

Evolve, test and optimise trading strategies.

The engine behind the [Quant Workbench](https://github.com/sophostechne/quant-vsce) extension,
usable on its own from the command line. Everything it reports is JSON on stdout, with
diagnostics on stderr, so it composes with whatever you already run.

## Install

```sh
pip install sophostechne-quant
```

The distribution is `sophostechne-quant`; the import package and the command are both `quant`.
It pulls in [NautilusTrader](https://github.com/nautechsystems/nautilus_trader) and pandas, so
the install is not small.

## The idea

A backtest that reports only a return is a sales pitch. Three questions have to be answered
together, and `evaluate` always answers all three — there is no flag to omit the awkward two:

- **Did it make money?** Net return, drawdown, profit factor, win rate, time in drawdown.
- **Was the drawdown real?** A Monte Carlo resample of the strategy's own trades, so the
  observed drawdown can be placed in the distribution of drawdowns it could have had.
- **Was any of it better than chance?** A noise floor of random strategies on the same bars.
  A strategy that does not beat its noise floor did not find an edge, whatever it returned.

## Use

```sh
quant evaluate --strategy my.strategy --product BTC-USD --timeframe 6h --bars 2000
```

Searching emits NDJSON — one object per generation, then a `done` object carrying the
survivors. Every survivor is scored twice: on the bars it was fitted to, and on a held-out tail
the search never saw. The gap between the two is the entire result.

```sh
quant evolve --population 250 --generations 20 --survivors 5 --holdout 0.3
```

Walk-forward tests the *method* rather than any one strategy. The whole search re-runs in every
training window and its winner is applied, untouched, to the window after.

```sh
quant walkforward --train-bars 1200 --test-bars 400
```

Generate a versioned point-in-time market forecast with separate probabilities for a turning
point, direction and volatility expansion. Forecasts are recorded as append-only JSONL by
default so misses cannot quietly disappear after the outcome is known:

```sh
quant forecast --product BTC-USD --timeframe 1d --bars 1000 --horizon 20
```

This is a transparent deterministic baseline, not a reproduction of any proprietary model.
Its trailing reversal levels and probability heuristics establish what later cycle and pattern
models must beat in purged walk-forward tests. Use `--registry PATH` to choose the record or
`--no-record` for an exploratory run.

The cycle laboratory adds fixed 8.6/4.3/2.15/1.075-year hypotheses and stable data-derived
Fourier, autocorrelation, Lomb–Scargle and localized wavelet candidates. It reports a normalized
timing intensity for each bar in the requested horizon:

```sh
quant forecast --product BTC-USD --timeframe 1d --model cycles --horizon 20
```

Cycle timing estimates whether a turn is near; it does not determine price direction.

The pattern ensemble adds separately trained direction and volatility models, reliability
calibration and normalized historical-neighbour evidence. Ensemble weights come from an
internal validation tail that precedes the live forecast:

```sh
quant forecast --product BTC-USD --timeframe 1d --model patterns \
  --pattern-bars 40 --neighbors 12 --horizon 20
```

The output includes neighbor count, distance, forward-outcome dispersion and the disclosed
parametric/pattern weights. A historical resemblance is evidence with a distribution, not a
promise that one selected chart will repeat.

Cross-market mode synchronizes context markets to the primary market's point-in-time clock and
adds bounded capital-flow proxies. Context observations that are missing or more than three
primary bars stale are disabled and reported:

```sh
quant forecast --product SPY --timeframe 1d --model flows \
  --context EFA,TLT,DXY --horizon 20
```

The output discloses relative strength, rolling betas, correlation breaks, stable lead/lag
relationships, risk-on and international-flow factors, plus the unadjusted pattern probabilities.
Roles for unfamiliar symbols can be supplied with repeated `--role SYMBOL=ROLE` arguments.

Forecasts are resolved only after enough later bars exist to evaluate both the stated horizon
and turning-point confirmation window. Resolution appends to a separate outcome registry; it
never edits the original prediction:

```sh
quant forecast-resolve --product BTC-USD --timeframe 1d
quant forecast-report
quant forecast-audit
```

Reports group Brier scores, log loss and reliability bins by immutable model version. Every
forecast also carries a deterministic explanation assembled only from its structured signals.

Model promotion uses a content-addressed acceptance manifest. The command accepts registry
locations but deliberately provides no flags that can alter the frozen universe, windows or
gates:

```sh
quant forecast-acceptance --manifest config/forecast-acceptance.json
```

Rejected and infrastructure-failed manifests remain under `config/`; results and decisions are
recorded in `docs/forecast-acceptance-log.md`. Historical success cannot bypass the minimum
prospective sample gate.

Advance the prospective cohort after new bars arrive with:

```sh
quant forecast-acceptance-update --manifest config/forecast-acceptance.json
```

The command derives manifest-specific registry paths, records at most one forecast per market
data timestamp, resolves anything mature, and reports progress. Forecasts from ordinary runs or
another manifest cannot count toward the cohort.

Costs are charged on every path: `--fee` (default 0.001) and `--slippage` (default 0.0005).
`--seed` makes a run reproducible, and `--regimes` conditions the search on market regime.

### Where the bars come from

Symbols route by shape. An exchange pair — `BTC-USD`, `ETH-USD`, anything ending in a quote
currency — comes from Coinbase, which serves candles to anyone. A ticker like `AAPL` or `BF-B`
comes from a published bars service:

```sh
quant evolve --product AAPL --timeframe 1d
```

That works with no configuration: `QUANT_BARS_URL` defaults to `https://bars.sophostechne.com`.
Point it at your own service to use different data, or set it empty to refuse equities.

Equities need a service because every real-time equity feed is licensed per subscriber and
cannot be redistributed; a service built from IEX HIST captures can be, so the engine needs no
credentials of its own. With `QUANT_BARS_URL` set empty, a ticker fails with a message saying so
rather than silently doing something else. See
[quant-daemon](https://github.com/sophostechne/quant-daemon) for running one.

A timeframe the service does not publish is built by resampling a finer one, which is exact.
Buckets that no trade fell into stay absent rather than being carried forward — a gap is
information, and filling it puts bars into a backtest that nothing supports.

Everything is cached under `~/.cache/quant`, so a search that re-reads the same window across
folds hits the network once.

## Output

One JSON object per line, always with an `ok` field on terminal results. Failures are reported
as JSON too, so a caller parsing the stream never has to strip a traceback out of it:

```json
{"ok": false, "type": "error", "error": "FileNotFoundError: my.strategy"}
```

## Development

```sh
uv sync
uv run pytest
```

## License

MIT
