Local backtesting toolkit with Cython-accelerated primitives.
Project description
Tick Backtest
Deterministic tick-level FX backtesting for reproducible research.
Tick Backtest is a configuration-first Python 3.12 toolkit for reproducible FX strategy research. You provide Parquet ticks and YAML configs; the stack validates every setting, executes deterministic backtests, and writes manifests, logs, reports, and analysis artefacts to disk.
Highlights
- Performance: ~8 million ticks/minute/core on AMD 5950X (Parquet → metrics → signals → trades)
- Deterministic runs: Deterministic runs: config, git hash, dependency snapshot, and shard hashes captured per run
- Resilient pipelines: Resilient pipelines: per-pair failure isolation, tick validation, and structured telemetry
- Declarative research: Declarative research: swap YAML configs instead of editing code
- Report ready: Report ready: trade tables, Markdown summaries, metric stratification CSV/PNG artefacts
- CLI + API parity: Every supported command is exposed both as
tick-backtest ...andtick_backtest.api.*(...)
Documentation is hosted here: Documentation Site. Release process details are documented in docs/releasing.md.
Quickstart
-
Install prerequisites
python3.12 -m venv .venv source .venv/bin/activate pip install tick-backtest
-
Write a starter config
tick-backtest example-config --output ./demo --include-demo-data
-
Run the bundled demo project
tick-backtest run ./demo/backtest.yaml
-
Generate report artefacts for a single trade file
tick-backtest report ./demo/output/<RUN_ID>/output/EURUSD/trades.parquet
-
Run multivariate trade analysis
tick-backtest analyze ./demo/output/<RUN_ID>/output/EURUSD/trades.parquet
The same surface is available from Python:
from tick_backtest import api
api.example_config("./demo", include_demo_data=True)
api.run("./demo/backtest.yaml")
api.report("./demo/output/<RUN_ID>/output/EURUSD/trades.parquet")
api.analyze("./demo/output/<RUN_ID>/output/EURUSD/trades.parquet")
The generated demo project includes:
backtest.yaml,metrics.yaml, andstrategy.yamldemo_data/with bundled EURUSD and GBPUSD parquet shardsoutput/as the run destination declared in the emitted config
Config surfaces are intentionally split:
src/tick_backtest/config/templates/andsrc/tick_backtest/demo_data/are the public packaged assets used by installed users.config/at the repository root is for checkout-only development, smoke tests, and CI golden runs.
For your own data instead of the bundled demo, emit the generic starter templates:
tick-backtest example-config --output ./tick-backtest-config
Then edit the generated YAML files:
# tick-backtest-config/backtest.yaml
data_base_path: "/abs/path/to/your/parquet/shards"
output_base_path: "/abs/path/to/backtest/output"
metrics_config_path: "./metrics.yaml"
strategy_config_path: "./strategy.yaml"
Inspect outputs under the configured output_base_path:
| Path | Purpose |
|---|---|
manifest.json |
Immutable run snapshot (configs, git hash, shard hashes, status). |
output/logs/<RUN_ID>.log |
Structured NDJSON log with validation summaries and errors. |
output/<PAIR>/trades.parquet |
Trade-level dataset including metrics and PnL. |
output/<PAIR>/analysis/report.md |
Markdown analysis summary with equity plots. |
configs/*.yaml |
Copies of backtest/metrics/strategy configs with SHA256 digests. |
Public Commands
| Command | Input | Output location |
|---|---|---|
tick-backtest run <backtest.yaml> |
Backtest config | Writes a run directory under output_base_path/<RUN_ID>/ |
tick-backtest report <trades.parquet> |
Trade database | Writes trade report artefacts and metric stratification beside the parquet file |
tick-backtest analyze <trades.parquet> |
Trade database | Writes multivariate_analysis/ beside the parquet file |
tick-backtest example-config [--output DIR] [--include-demo-data] |
Optional destination dir | Prints starter YAML or writes a template set or runnable demo project |
Configuration Cheat Sheet
Tick Backtest is driven by three YAML files that are validated against strict schemas (unknown keys and duplicates are rejected).
Backtest YAML
schema_version: "1.0"
pairs: [EURUSD, GBPUSD]
start: 2012-02
end: 2013-02
pip_size: 0.0001
warmup_seconds: 1800
data_base_path: "/data/dukascopy/"
output_base_path: "/results/backtests/"
metrics_config_path: "config/metrics/default_metrics.yaml"
strategy_config_path: "config/strategy/default_strategy.yaml"
Key fields: pair list, inclusive year-month span, data/output roots, warmup length, and the metric/strategy config locations.
Metrics YAML
metrics:
- name: z30m
type: zscore
enabled: true
params:
lookback_seconds: 1800
- name: ewma_vol_5m
type: ewma_vol
params:
tau_seconds: 300
percentile_horizon_seconds: 300
bins: 256
base_vol: 0.0001
stddev_cap: 5.0
Entries wire directly into registries; unknown types or duplicate names raise immediately.
Strategy YAML
strategy:
name: threshold_reversion_strategy
entry:
engine: threshold_reversion
params:
threshold_pips: 10
tp_pips: 10
sl_pips: 20
trade_timeout_seconds: 7200
predicates:
- metric: tick_rate_30s.tick_rate_per_min
operator: "<"
value: 200
exit:
name: default_exit
predicates: []
Entry engines and predicates gate trade opens; exit predicates can force closures.
Need full schemas or extension guidance? See the Configuration Guide.
Python API
| Function | Purpose |
|---|---|
tick_backtest.api.run(config_path, *, output_root=None) |
Run the backtest engine and write run artefacts only |
tick_backtest.api.report(trades_path) |
Generate trade report artefacts and metric stratification outputs |
tick_backtest.api.analyze(trades_path) |
Generate multivariate regression-style analysis outputs |
tick_backtest.api.example_config(dest=None, *, template="minimal", include_demo_data=False) |
Print or write starter YAML templates, optionally with bundled demo data |
The API is intentionally filesystem-oriented. It writes artefacts to disk and does not aim to return in-memory result objects.
Repository Development
If you are working from a checkout rather than an installed package:
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -e .
pytest
Legacy repo scripts under scripts/ still exist for internal development and CI coverage, but installed usage should go through tick-backtest or tick_backtest.api.
Release Posture
The project is versioned for public releases starting at 0.1.0. Tagged releases publish via GitHub Actions using staged TestPyPI then PyPI trusted publishing. See docs/releasing.md and CHANGELOG.md.
Architecture Snapshot
config/– versioned YAML templates validated before runtime.src/tick_backtest/config_parsers/– schema validation → immutable dataclasses.src/tick_backtest/data_feed/– compiled tick loader with Python fallback; wrapped byTickValidator.src/tick_backtest/backtest/–BacktestCoordinatororchestrates per-pair runs;Backtestexecutes signals and positions.src/tick_backtest/metrics/– registries and indicator implementations (compiled with Python fallbacks).src/tick_backtest/signals/– predicate-aware entry/exit engines.src/tick_backtest/analysis/– reporting, stratification, and plotting utilities.tests/– unit, integration, and regression coverage across parsers, primitives, and pipeline stages.
Data & validation flow
- Configs are parsed with forbid-by-default schemas (
config_validation/*). - Tick feeds stream from Parquet; invalid ticks are skipped but logged.
- Per-pair runs are isolated; errors are captured without aborting the batch.
- Outputs, manifests, and environment snapshots land under
output/backtests/<RUN_ID>/.
Design Choice: sequential execution avoids lookahead; scale comes from multi-pair orchestration and sweep automation.
Dive deeper in the Developer Notes.
Troubleshooting Essentials
| Symptom | Likely Cause | Fix |
|---|---|---|
ConfigError: unknown field ... |
Extra keys in YAML | Remove or rename; see Configuration Guide. |
pyarrow import error |
Wheel missing | Install pinned version from requirements.txt and rerun. |
| Run finishes but no trades | Warmup consumed data or predicates blocked | Check output/logs/<RUN_ID>.log and entry predicates. |
Manifest shows missing_file |
data_base_path doesn’t match shard layout |
Adjust path or supply expected Parquet shards. |
Percentile metrics return NaN |
Histogram warming up | Feed more ticks; expected during first few minutes. |
Compatibility & Dependencies
- Python 3.12
numpy >= 1.26, < 3.0pandas >= 1.5, < 2.3pyarrow >= 10.0, < 16.0matplotlib >= 3.7, < 3.9pyyaml >= 6.0, < 6.1
Running offline? Pre-install these wheels in your environment. Backtests abort if pip freeze fails (dependency snapshot is required).
Testing & CI
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -e .
pytest
Coverage highlights:
tests/config_parsers– YAML schema governance & regression checks.tests/data_feed– tick validation and resilience.tests/metrics– primitives plus indicator mathematics with reference helpers.tests/integration/test_backtest_run.py– end-to-end pipeline regression.
GitHub Actions builds wheels, runs tests, validates distribution metadata, and publishes docs via .github/workflows/mkdocs.yml.
Extending the Stack
- Add a metric – create a dataclass under
metrics/dataclasses, register it inmetrics/config_registry.py, implement runtime logic. Validation blocks duplicates. - Add a signal engine – add a class in
signals/entries, register it inENTRY_ENGINE_REGISTRY, and expose parameters in strategy YAML. - Support new data layouts – extend
tick_backtest.data_feedfor alternative Parquet conventions; the validator enforces monotonic timestamps and finite spreads.
See the Developer Notes for dependency maps, testing expectations, and release checklists.
Next Steps
- Generate a starter config with
tick-backtest example-config. - Point it at your own Parquet tick data.
- Run
tick-backtest runand inspect the generated manifest and pair-level artefacts. - Explore the documentation for advanced configuration and internals.
Author: Edward Clewer
License: Apache License 2.0
Docs: Docs
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 Distribution
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 tick_backtest-0.1.1.tar.gz.
File metadata
- Download URL: tick_backtest-0.1.1.tar.gz
- Upload date:
- Size: 7.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82c996b14b9152418300b89bd444aeca6a8ce67cd5630be52015aa1398d9c918
|
|
| MD5 |
3add3bddc47ecc8be1559d97cd27ae91
|
|
| BLAKE2b-256 |
db584179e32e655abcab224aef23ae2dbe4d3f1396c04267e88a089f0151b65a
|
File details
Details for the file tick_backtest-0.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: tick_backtest-0.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 11.5 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49db0e00a5d4ec2b034ee52e508d0ed6c7d35ec1e919953bb7e56ac3111c2d65
|
|
| MD5 |
daedf3a9ce73d7ea060e02d886d3cce0
|
|
| BLAKE2b-256 |
e330ac86b5e7b16674328a44dd8daa4a8cd88b5bc19a192b228443894a4dbc7f
|