Skip to main content

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 ... and tick_backtest.api.*(...)

Documentation is hosted here: Documentation Site. Release process details are documented in docs/releasing.md.


Quickstart

  1. Install prerequisites

    python3.12 -m venv .venv
    source .venv/bin/activate
    pip install tick-backtest
    
  2. Write a starter config

    tick-backtest example-config --output ./demo --include-demo-data
    
  3. Run the bundled demo project

    tick-backtest run ./demo/backtest.yaml
    
  4. Generate report artefacts for a single trade file

    tick-backtest report ./demo/output/<RUN_ID>/output/EURUSD/trades.parquet
    
  5. 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, and strategy.yaml
  • demo_data/ with bundled EURUSD and GBPUSD parquet shards
  • output/ as the run destination declared in the emitted config

Config surfaces are intentionally split:

  • src/tick_backtest/config/templates/ and src/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 by TickValidator.
  • src/tick_backtest/backtest/BacktestCoordinator orchestrates per-pair runs; Backtest executes 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

  1. Configs are parsed with forbid-by-default schemas (config_validation/*).
  2. Tick feeds stream from Parquet; invalid ticks are skipped but logged.
  3. Per-pair runs are isolated; errors are captured without aborting the batch.
  4. 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.0
  • pandas >= 1.5, < 2.3
  • pyarrow >= 10.0, < 16.0
  • matplotlib >= 3.7, < 3.9
  • pyyaml >= 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 in metrics/config_registry.py, implement runtime logic. Validation blocks duplicates.
  • Add a signal engine – add a class in signals/entries, register it in ENTRY_ENGINE_REGISTRY, and expose parameters in strategy YAML.
  • Support new data layouts – extend tick_backtest.data_feed for 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

  1. Generate a starter config with tick-backtest example-config.
  2. Point it at your own Parquet tick data.
  3. Run tick-backtest run and inspect the generated manifest and pair-level artefacts.
  4. Explore the documentation for advanced configuration and internals.

Author: Edward Clewer
License: Apache License 2.0
Docs: Docs

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tick_backtest-0.1.1.tar.gz (7.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tick_backtest-0.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (11.5 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

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

Hashes for tick_backtest-0.1.1.tar.gz
Algorithm Hash digest
SHA256 82c996b14b9152418300b89bd444aeca6a8ce67cd5630be52015aa1398d9c918
MD5 3add3bddc47ecc8be1559d97cd27ae91
BLAKE2b-256 db584179e32e655abcab224aef23ae2dbe4d3f1396c04267e88a089f0151b65a

See more details on using hashes here.

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

File hashes

Hashes for tick_backtest-0.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 49db0e00a5d4ec2b034ee52e508d0ed6c7d35ec1e919953bb7e56ac3111c2d65
MD5 daedf3a9ce73d7ea060e02d886d3cce0
BLAKE2b-256 e330ac86b5e7b16674328a44dd8daa4a8cd88b5bc19a192b228443894a4dbc7f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page