pybroker.optimize module

Hyperparameter declaration and optimization with Optuna.

Hyperparams declare tunable values for indicators and executions. Each hyperparam is registered globally by name via hyperparam() and resolved to a concrete int or float at backtest or optimization time.

Pass hyperparams as keyword arguments to pybroker.indicator.indicator(), or list them on pybroker.strategy.Strategy.add_execution() to read them inside an execution with ctx.hyperparam(name).

class Hyperparam(name: str, default: int | float, low: int | float, high: int | float, step: int | float)[source]

Bases: object

Declares a named hyperparameter with bounds and step size.

Created with hyperparam() and registered globally by name.

name

Unique identifier used in indicator kwargs, execution hyperparam lists, and optimization results.

Type:

str

default

Value for backtests and the baseline during optimization. Should lie within [low, high].

Type:

int | float

low

Minimum candidate value searched during optimize (inclusive).

Type:

int | float

high

Maximum candidate value searched during optimize (inclusive). Candidate values are low, low + step, … up to the largest value not exceeding high.

Type:

int | float

step

Spacing between candidate values. Must be positive. Integer hyperparams use integer steps; float hyperparams use float steps with values rounded to match Optuna stepped suggestions.

Type:

int | float

Examples

Indicator period from 5 to 50 in steps of 5:

period = hyperparam("period", default=14, low=5, high=50, step=5)
class ObjectiveBundle(objective: Callable[[Trial], float], search_space: SearchSpace, score_overrides: Callable[[dict[str, Any]], float])[source]

Bases: object

Return value of make_objective().

objective: Callable[[Trial], float]
score_overrides: Callable[[dict[str, Any]], float]
search_space: SearchSpace
class OptimizeMixin[source]

Bases: object

Mixin implementing hyperparameter optimization.

optimize(score_fn: Callable[[TestResult], float], *, sampler: str | BaseSampler = 'grid', n_trials: int | None = None, direction: str = 'maximize', seed: int | None = None, windows: int | None = None, study: optuna.Study | None = None, pruner: optuna.pruners.BasePruner | None = None, train_size: float = 0.5, lookahead: int = 1, start_date: str | datetime | None = None, end_date: str | datetime | None = None, timeframe: str = '', between_time: tuple[str, str] | None = None, days: Any | None = None, warmup: int | None = None, parallel_indicators: bool = False, adjust: Any | None = None, calc_bootstrap: bool = False, verbose: bool = False) OptimizeResult[source]

Searches pybroker.optimize.hyperparam() values on a training window, then evaluates the best values on the held out test window.

Data supplied by the pybroker.data.DataSource is split into train and test as specified by train_size. Every trial backtests the train window with one combination of hyperparameter values and scores it with score_fn. The winning combination is then replayed on the test window, which score_fn never sees.

Pretrained models (model(..., pretrained=True)) are loaded per train window and reused across that window’s trials. Trainable models are not supported; tune them inside train_fn with a validation split, or use pybroker.strategy.Strategy.walkforward().

Parameters:
  • score_fnCallable[[TestResult], float] that scores one trial’s train window backtest. Maximized by default; see direction.

  • sampler – How candidate values are chosen. "grid" (the default) exhaustively enumerates every combination, "tpe" uses optuna.samplers.TPESampler, "random" uses optuna.samplers.RandomSampler. An optuna.samplers.BaseSampler instance is also accepted; it is deep-copied and re-seeded per window, and a multi-window run ships copies to worker processes, so it must be picklable. Grid and random samplers evaluate trials in parallel on the configured workers. Any other sampler — "tpe", or an instance that is not a GridSampler or RandomSampler — is adaptive, and evaluating its trials in batches would change the values it proposes and tie results to the worker count; its trials therefore run sequentially, and an info-level log message notes that parallelism was disabled.

  • n_trials – Number of trials to run. Required for every sampler except "grid", where it defaults to the full grid size and a smaller value samples that many combinations at random.

  • direction"maximize" (default) or "minimize" score_fn.

  • seed – Random seed for the sampler and for bootstrap metrics. Defaults to None, which does not reproduce.

  • windows – When greater than 1, hyperparameters are optimized separately in each of windows walkforward windows and the test windows are stitched into one continuous result. Defaults to None, a single train/test split.

  • study – Existing optuna.study.Study to record trials in, for example one backed by persistent storage. The study’s own sampler and pruner are used, and its direction must match direction. Not supported when windows is greater than 1.

  • pruneroptuna.pruners.BasePruner attached to the created study. Each trial is one complete backtest with no intermediate values to report, so pruning never actually triggers.

  • train_size – Fraction of each window used for training, exclusive of 0 and 1. Defaults to 0.5.

  • lookahead – Number of bars in the future of the target prediction. Held out between train and test to prevent training data from leaking across the boundary, in the bars of the timeframe each model is fitted on: a model bound to an interval with pybroker.model.ModelSource.intervals() holds out lookahead bars of that interval, not of the base timeframe. Defaults to 1.

  • start_date – Starting date of the optimization (inclusive). Must be within the range passed to the pybroker.strategy.Strategy constructor.

  • end_date – Ending date of the optimization (inclusive). Must be within the range passed to the pybroker.strategy.Strategy constructor.

  • timeframe – Formatted string specifying the timeframe resolution of the data, as in pybroker.strategy.Strategy.walkforward().

  • between_timetuple[str, str] of times of day e.g. ('9:30', '16:00') used to filter the data (inclusive).

  • days – Days (e.g. "mon", "tues") used to filter the data.

  • warmup – Number of bars that need to pass before running the executions. Must be greater than 0 when set.

  • parallel_indicators – If True, pybroker.indicator.Indicator data is computed in parallel using multiple processes. Defaults to False.

  • adjust – The type of adjustment to make to the pybroker.data.DataSource.

  • calc_bootstrap – Whether to compute randomized bootstrap evaluation metrics for the test result. Defaults to False.

  • verbose – Whether to log every trial’s backtest – indicator computation, test split progress bars, and Optuna’s own trial logging. Defaults to False, which logs the optimization summary and the final test window evaluation only.

Returns:

OptimizeResult with the winning hyperparameter values, the train window score they earned, and the test window pybroker.strategy.TestResult they produced. When windows is greater than 1, best_params, best_score, and study describe the last window while result is stitched across all of them; see OptimizeResult.windows for the per-window results.

Raises:

ValueError – If no executions were added, if any model source is trainable, if train_size is not between 0 and 1 exclusive, if warmup is not greater than 0, if windows is not greater than 0, if study is combined with windows greater than 1 or has a conflicting direction, or if the dates fall outside the range passed to the pybroker.strategy.Strategy constructor.

class OptimizeResult(best_params: dict[str, Any], best_score: float, result: TestResult, study: optuna.Study, windows: tuple[WindowOptimizeResult, ...] | None = None)[source]

Bases: object

Result of Strategy.optimize().

best_params

Winning hyperparameter values, including the ones that were fixed rather than searched. When windows is set, these are the last window’s values, since each window is tuned separately.

Type:

dict[str, Any]

best_score

score_fn value that best_params earned on the train window. When windows is set, this is the last window’s score.

Type:

float

result

pybroker.strategy.TestResult for the test window. When windows is set, this is a single continuous result stitched from every window’s test data, with positions and cash carried across window boundaries.

Type:

TestResult

study

optuna.study.Study holding the trials. When windows is set, this is the last window’s study; see windows for the rest.

Type:

optuna.Study

windows

Per-window tuning results, or None for a single train/test split.

Type:

Optional[tuple[WindowOptimizeResult, …]]

to_json(*, include: frozenset[str] | None = None, max_rows: int | None = 100, symbols: frozenset[str] | None = None) dict[str, Any][source]

Returns JSON-serializable optimization results.

to_json_str(*, include: frozenset[str] | None = None, max_rows: int | None = 100, symbols: frozenset[str] | None = None) str[source]

Returns strict JSON text from to_json().

class SearchSpace(hyperparams: frozenset[str], specs: Mapping[str, Hyperparam])[source]

Bases: object

Searchable hyperparameters collected from a strategy.

Only includes hyperparams with low < high that are passed to Optuna during Strategy.optimize().

hyperparams

Names of hyperparams searched during optimize.

Type:

frozenset[str]

specs

Mapping of hyperparam name to Hyperparam spec.

Type:

Mapping[str, pybroker.optimize.Hyperparam]

grid_size() int[source]

Total number of grid combinations.

class WindowOptimizeResult(params: dict[str, Any], study: Study, train_score: float, train_start_date: datetime | None = None, train_end_date: datetime | None = None, test_start_date: datetime | None = None, test_end_date: datetime | None = None, execution_symbols: dict[int, frozenset[str]] | None = None)[source]

Bases: object

Per-window walk-forward optimization result.

Holds the values a window was tuned to, not a backtest of its own: the single out-of-sample pybroker.strategy.TestResult lives on OptimizeResult.result, stitched across every window.

params

Winning hyperparameter values for this window, including the ones that were fixed rather than searched.

Type:

dict[str, Any]

study

optuna.study.Study holding this window’s trials.

Type:

optuna.study.study.Study

train_score

score_fn value that params earned on this window’s train data.

Type:

float

train_start_date

First date of the window’s train data, or None when the train split is empty.

Type:

datetime.datetime | None

train_end_date

Last date of the window’s train data, or None when the train split is empty.

Type:

datetime.datetime | None

test_start_date

First date of the window’s test data – the span its tuned params trade in the stitched OptimizeResult.result – or None when the test split is empty.

Type:

datetime.datetime | None

test_end_date

Last date of the window’s test data, or None when the test split is empty.

Type:

datetime.datetime | None

execution_symbols

Symbols each execution id resolved to for this window when a pybroker.common.SymbolSelector chose them, or None when no execution uses a selector.

Type:

dict[int, frozenset[str]] | None

to_json() dict[str, Any][source]

Returns JSON-serializable walk-forward optimization window results.

to_json_str() str[source]

Returns strict JSON text from to_json().

build_run_hyperparams(specs: Mapping[str, Hyperparam], overrides: dict[str, Any] | None = None) dict[str, Any][source]

Builds the hyperparam dict for a single backtest or trial run.

Parameters:
  • specs – All hyperparams reachable from the strategy.

  • overrides – Trial or user-supplied values to merge over defaults.

Returns:

Dict of name -> value for every hyperparam in specs.

collect_hyperparams(strategy: _ExecutionsHost) dict[str, Hyperparam][source]

Collects all hyperparams reachable from strategy.

collect_search_space(strategy: _ExecutionsHost) SearchSpace[source]

Collects searchable hyperparams reachable from strategy.

hyperparam(name: str, *, default: int | float, low: int | float, high: int | float, step: int | float) Hyperparam[source]

Creates and registers a Hyperparam.

Parameters:
  • name – Unique identifier for the hyperparam. Referenced in indicator kwargs, add_execution(..., hyperparams=[...]), and ctx.hyperparam(name).

  • default – Value used for backtests.

  • low – Minimum candidate value searched during optimize (inclusive).

  • high – Maximum candidate value searched during optimize (inclusive).

  • step – Spacing between candidate values. Must be positive.

Returns:

The registered Hyperparam instance.

make_objective(strategy: _OptimizeTrialHost, score_fn: Callable[[TestResult], float], *, train_rows: np.ndarray, df: pd.DataFrame, hyperparams: Mapping[str, Hyperparam], search_space: SearchSpace, invariant_indicator_data: dict[IndicatorSymbol, pd.Series], window_executions: set[Execution], master_store: Any, interval_data: Any, parallel_indicators: bool, warmup: int | None, pretrained_models: Mapping[ModelSymbol, TrainedModel], exit_dates: Mapping[str, np.datetime64], verbose: bool = False) ObjectiveBundle[source]

Builds an Optuna objective for train-window scoring.

When verbose is False (the default), each trial’s backtest runs with logging suppressed so that per-trial progress bars do not repeat for every combination searched.