- OpenBacktesting
- Saved parameter experiments
Saved parameter experiments¶
Use runtime.optimize to save a complete Portfolio for every parameter combination to a local SQLite file. Reopen that file to rank, filter, or inspect reports without rerunning strategies. Use Backtest.optimize if you only need the best run and a score grid.
Values · Range · ExecutionIdentity · open_result · ExperimentResult · OptimizationError · plan · Plan · execute
Run and query an experiment¶
Save this complete example as experiment.py, then run python experiment.py. The temporary directory gives each invocation a new result file; replace it with a new persistent path to retain the experiment.
import hashlib
import tempfile
from pathlib import Path
from openbacktesting import Strategy, backtest, inputs, runtime, DataContext, Timeframe
from openbacktesting.broker import InstrumentSpec
from openbacktesting.optimizer import ExecutionIdentity, Range, open_result
from openbacktesting.test import GOOG
@backtest()
class Experiment(Strategy):
quantity = inputs.int(1, title="Quantity", minval=1)
def init(self):
pass
def next(self):
if self.bar_index == 0:
self.buy(qty=self.quantity)
elif self.bar_index == 10:
self.position.close()
if __name__ == "__main__":
data = GOOG.iloc[:30].copy()
data.index = data.index.tz_localize("UTC")
identity = ExecutionIdentity(
strategy_sha256=hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
dependencies_sha256=hashlib.sha256(b"no local dependencies").hexdigest(),
)
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / "experiment.db"
saved = runtime.optimize(
globals(), {"Quantity": Range(1, 3, 1)}, path=path, identity=identity,
data=data, context=DataContext(Timeframe.days(1), "UTC"),
instrument=InstrumentSpec(symbol="GOOG"),
)
reopened = open_result(path)
ranking = reopened.query(order_by=["summary.all.totalReturn.value"])
print(ranking)
trial = ranking["rows"][0]
report = reopened.load_portfolio(trial["trial_id"])
print(report["summary"]["all"]["totalReturn"])
Choose search domains¶
Search keys are unique input titles, not Python attribute names. Values([10, 20, 40]) supplies explicit choices. Range(5, 25, 5) supplies an integer grid, including the stop only if it lies on the grid. Use decimal strings for exact float ranges, e.g. Range("0.1", "0.3", "0.1"). Empty domains, duplicates, and invalid candidates are rejected.
Parameters not in search use the current request (from inputs.request_for) or declaration defaults. Every candidate starts a fresh account. This interface retains Portfolios but disables plot/log history; it does not automatically choose or rerun a winner.
Execution arguments¶
| Argument | Meaning |
|---|---|
namespace, data, context, instrument |
Same loaded strategy and chart arguments as runtime.run. |
path |
New local database path. Use resume for an existing experiment. |
identity |
ExecutionIdentity with SHA256 digests of the strategy source and its local dependencies. Include all code that affects the strategy. |
request, settings |
Current input request and sparse backtest setting overrides. |
constraint |
Optional predicate receiving complete serialized input values and returning bool. Requires a stable constraint_id. False records a skipped candidate. |
cancel |
Optional zero-argument callable; returning True stops dispatch after the in-flight candidate completes. |
on_progress |
Called after a candidate commits. Its event includes trial_id; committed reports are already readable. |
The library checks data/settings/environment identity on resume. Call runtime.resume_optimization(namespace, path=path, experiment_id=saved.experiment_id, identity=identity, data=data, context=context, instrument=instrument, ...) with the same current inputs/settings/constraint. Changed material requires a new experiment. Successful, failed, and skipped candidates are not automatically rerun; interrupted or undispatched work can continue.
Inspect results¶
| Method | Result and arguments |
|---|---|
info() |
Experiment metadata and counts. |
trials(limit=100, offset=0) |
Visited candidate records with trial_id, state, and any error, including failures. |
fields() |
Queryable scalar paths, units, and suggested sort direction. |
query(order_by=..., filters=..., fields=..., limit=100, cursor=None) |
A page of ranked/filtered candidates. Limit is 1..1000. |
load_portfolio(trial_id) |
One successful candidate's complete report. |
backup(destination) |
Safe database copy, including committed work while a run is active. |
For explicit sorting, use order_by=[("summary.all.totalReturn.value", "desc")]. Filters are (path, operator, value) tuples; operators include eq, ne, lt, le, gt, ge, and status. fields selects scalars to return. Null values sort last. Use the returned cursor for the next page; restart without it to include newer commits.
Values¶
Finite candidate values; plan validates against the corresponding input declaration.
| Attribute | Type | Meaning |
|---|---|---|
values |
tuple \| list |
Explicit candidate values. |
Range¶
Ascending grid range; int uses integers, float/price uses decimal strings or integers.
| Attribute | Type | Meaning |
|---|---|---|
start |
int \| str |
First grid value. |
stop |
int \| str |
Inclusive upper bound when it falls exactly on the grid. |
step |
int \| str |
Positive grid increment. |
ExecutionIdentity¶
Host declaration of SHA256 digests for loaded source and local dependencies; no files are loaded or executed.
| Attribute | Type | Meaning |
|---|---|---|
strategy_sha256 |
str |
SHA256 digest of the executed strategy source. |
dependencies_sha256 |
str |
SHA256 digest identifying its local code dependencies. |
open_result¶
Open an experiment result database read-only, without strategy or market-data dependencies.
ExperimentResult¶
Reopenable read-only result handle; each access uses an independent connection without live strategy references.
| Attribute | Type | Meaning |
|---|---|---|
path |
str |
Local experiment database path. |
experiment_id |
str |
Identifier of the experiment in that database. |
ExperimentResult.backup¶
Create a consistent backup in a new local file; reject overwriting existing files.
ExperimentResult.fields¶
Return scalar paths, types, units, statuses, methods, and suggested sort directions.
ExperimentResult.info¶
Return experiment status, category counts, and an immutable plan copy.
ExperimentResult.load_portfolio¶
Validate and load one complete report; explicitly reject failures and corruption.
ExperimentResult.query¶
Query scalar values and parameters for successful trials; cursors freeze the commit range, and new queries refresh it.
ExperimentResult.trials¶
Browse live statuses of all visited trials by page, without complete Portfolios.
OptimizationError¶
Experiment infrastructure error preserving result location, identity, and last known committed count.
An OptimizationError identifies the path, experiment, and last known committed count. A failed strategy is recorded as a failed candidate; a storage failure stops the experiment. Already committed results remain available for inspection.
Advanced: supply your own executor¶
Most users should call runtime.optimize. If integrating a separate executor, plan(strategy_class, search, base_inputs=..., execution=..., constraint_id=...) validates and freezes the search. execution supplies the execution identity mapping; base_inputs is the title-based input request. A Plan exposes .total and .snapshot().
execute(plan_value, executor, path, ...) calls your executor for each input request; it must return the complete Portfolio report. Supply experiment_id to resume the matching plan. Cancellation, progress, and constraints have the same role as above. See the complete runtime example for the supported default path.
plan¶
Freeze complete current configuration and selected dimensions; the host must explicitly supply execution identity.
Plan¶
Immutable canonical text; snapshot returns an independent copy, and combinations are generated incrementally at runtime.
Attributes¶
| Attribute | Meaning |
|---|---|
total |
Raw Cartesian-product count, without deducting constraints not yet checked. |
Plan.snapshot¶
Return an independent JSON copy of the complete plan.
execute¶
optimizer.execute(
plan_value,
executor,
path,
*,
experiment_id=None,
constraint=None,
cancel=None,
on_progress=None,
)
Execute or resume a plan; executor receives title-based requests and returns complete Portfolio dictionaries.