Introducing Open Backtest Format (.obtf)
Open Backtest Format: A Strategy Is More Than One Backtest OBTF is a versioned, framework/engineagnostic, studiesfirst ondisk format for storing a strategy's b
mduyn
September 7, 2026
Open Backtest Format: A Strategy Is More Than One Backtest
OBTF is a versioned, framework/engine-agnostic, studies-first on-disk format for storing a strategy's backtest evidence in one self-contained file. It can hold studies, universes, metrics, trades, orders, portfolio snapshots, execution assumptions, and Monte Carlo test results.
The organizing principle is simple: one .obtf file per strategy, containing the studies and runs used to evaluate it.
The Problem: Results Without Their Research Context
Many backtesting workflows save results one backtest at a time. That is convenient while running experiments, but awkward when evaluating a strategy as a whole.
Current systems scatter the evidence for the performance of algorithms accross a wide variety of files. For example, a notebook holds the equity curve, a CSV holds the trades, and a separate configuration holds the fees. A proprietary dashboard may bring them together, but only inside the platform that produced them.
That fragmentation creates three practical problems:
- Portability: sharing or archiving results often requires custom exports and engine-specific parsing. The evidence should be usable beyond its original dashboard.
- Comparison: two headline returns can hide different universes, time windows, and execution assumptions. Researchers need access to that context before treating results as comparable.
- Lineage: disconnected reports make it difficult to follow related experiments or identify which strategy variant produced a result. Also, its difficult to see how a strategy performs accross studies.
Together, these make a straightforward question surprisingly difficult to answer:
Does this strategy hold up across different conditions, or am I looking at its best run?
The missing piece is a shared structure that keeps results connected to their research context. The goal here is to have in a single opienenated overview the evidence how a strategy performs on different assets, time-windows, parameters and if it overfits.
OBTF does not replace the experiments. It provides a common structure for preserving their outputs together. You end up with a file containing all the evidence how your strategy performns in different scenarions.
From Individual Runs to Studies
The most important design choice is that OBTF is studies-first. A study contains the execution context of its backtests and exactly one universe, shared by all its runs.
Illustrative view: one universe per study, with runs across multiple windows.
A run is one execution over a particular time window and universe of assets. A study groups related evaluations of a strategy idea, with context such as its validation role and execution assumptions. Within each study, engine slots separate results produced by different engine classes.
For example, a bundle could contain an exploratory study using a vectorized engine and a separate out-of-sample validation study using an event-driven engine. Each can contain multiple runs across different periods on its single universe. Testing a different universe belongs in a separate study.
Illustrative organization. Optional content depends on what the producer records.
Notice where the assumptions sit: on the study. A zero-cost exploration and a realistic-cost validation can coexist without implying that they used the same execution model.
In the Python reference implementation, Study.execution_config is an ExecutionConfig dataclass serving two roles: input, for configuring backtest costs, and output, for capturing what the blotter actually used. blotter_type records class identity only; the optional slippage, commission, and fill dictionaries record model type and params. Per-symbol trading_costs override the default entry with symbol=None, while metadata holds extras such as runtime flags.
The implementation builds runtime snapshots with ExecutionConfig.from_runtime(blotter=..., trading_costs=..., metadata=...). Cost entries can be TradingCost instances or their to_dict() form; get_trading_costs() returns instances, and is_empty() supports introspection. These are Python helpers, not requirements imposed on every OBTF reader. The snapshot supports auditing execution assumptions; it does not replace the code and data needed to reproduce a backtest.
Bundles also carry an algorithm identifier and can record parameters and an anchor_algorithm_id linking a variant to its source algorithm. This supports tracing related experiments across bundles. Those identifiers are producer-defined, however: the format does not require a code hash or independently prove that two strategies contain identical code.
Making Robustness Easier to Inspect
Consider a hypothetical trend-following strategy. Its initial backtest looks promising. Before taking it seriously, you want to examine several additional questions:
| Evidence to inspect | Research question |
|---|---|
| Runs across different periods | Does performance depend on one favorable market? |
| Separate studies for different universes | Does the result depend on a particular asset selection? |
| A study with realistic costs | Do commission and slippage erase the apparent edge? |
| Held-out validation runs | Does the idea survive beyond the data used to develop it? |
| Monte Carlo test results | How unusual is the observed result under the chosen null model? |
OBTF gives these outputs places within the same bundle. Engine slots can also hold pooled summaries across their runs, all evaluated on the study's universe.
An analysis tool could present a window-by-window view, a metrics table, equity curves, and trading activity from the same underlying runs. These become different views of shared evidence, rather than separate reports to reconcile by hand. Stored summaries are caches that readers may recompute, not independent guarantees of correctness.
For comparisons across strategies, a tool can align runs from separate bundles by universe, window, and assumptions. A common format makes fair comparison easier to construct; it does not make every comparison fair automatically.
The format does not perform these tests or guarantee a robust strategy. It preserves the evidence a producer supplies. Missing experiments remain missing, and a bundle can still contain selectively chosen results.
One File, Built From Established Technologies
The file begins with an OBTF identifier and a format-version number. Its body uses MessagePack for structured data and Zstandard for compression. Larger supported time-series fields can be stored as embedded Parquet blobs.
Those pieces travel together in a single file. Versioning provides a compatibility boundary: readers must reject newer versions they do not support.
Because the specification is open, a compatible notebook, dashboard, or ranking tool can read the bundle without being the tool that produced it. The results need not remain tied to one platform's presentation.
Portable Does Not Mean Identical
Engine-agnostic storage does not make different engines behave identically. A vectorized simulation and an event-driven simulation can make different execution assumptions; OBTF keeps their results separate within a shared structure.
There are other important boundaries:
- Metric calculations remain producer-defined. Two stored Sharpe ratios are not automatically comparable without checking their definitions.
- Detailed row schemas are not yet universal. Trades, orders, and several other record types remain producer-defined in the current design, so some cross-framework analysis still needs producer-specific knowledge.
- A self-contained results file is not a complete reproduction environment. OBTF does not package strategy source code or raw market data. It can carry data-source references, but reproducing a run requires those external inputs and the relevant software.
The promise is a shared container and research structure, not automatic equivalence between every backtesting system.
Available Today, Still Evolving
OBTF is now officially supported in investing-algorithm-framework (QuantOS), which hosts the reference Python implementation.
The specification is currently v0.1.0-draft. It is not yet stable, parts of the specification remain unfinished, and adoption beyond the reference implementation has not yet been established.
The ambition is to make a strategy's evaluation portable as a coherent body of evidence, rather than a collection of engine-specific exports. Broader adoption would let engine authors focus on simulation and analysis-tool authors build against a shared results structure.
A backtest answers, "What happened in this run?" OBTF is designed to help preserve the evidence for the bigger question: "What have we learned about this strategy?"
1
0 Comments
Table of Contents
Open Backtest Format: A Strategy Is More Than One Backtest
The Problem: Results Without Their Research Context
From Individual Runs to Studies
Making Robustness Easier to Inspect
One File, Built From Established Technologies
Portable Does Not Mean Identical
Available Today, Still Evolving