Skip to content
GeneratedGenerated from the built extension by scripts/generate_python_api_reference.py; CI fails if it is stale.

openquant.research

Pure Python. Signatures are as written in the source; descriptions are the docstrings. All Python modules.

Classes

ResearchDataset

class ResearchDataset

Inputs for one research-flywheel run, as parallel per-bar lists.

Built by make_synthetic_futures_dataset and consumed by run_flywheel_iteration and run_flywheel_grid, which pass the fields to openquant.pipeline.run_mid_frequency_pipeline_frames.

Attributes

timestamps : list[str]

Bar timestamps as "%Y-%m-%d %H:%M:%S" strings.

close : list[float]

Close price of the primary traded instrument per bar.

model_probabilities : list[float]

Model probability per bar.

model_sides : list[float]

Model side per bar (+1.0 or -1.0).

asset_prices : list[list[float]]

One row per bar, one column per asset, in asset_names order.

asset_names : list[str]

Asset names; the first is the primary instrument.

periods_per_year : float or None, default None

Bars a year, used to annualise Sharpe ratios and volatility. None derives it from the spacing of timestamps (openquant.pipeline.infer_periods_per_year). make_synthetic_futures_dataset sets it to 98,280 (one-minute bars, 390 a session, 252 sessions a year).

Functions

make_synthetic_futures_dataset

make_synthetic_futures_dataset(
    n_bars: int = 192,
    seed: int = 7,
    asset_names: list[str] | None = None,
) -> ResearchDataset

Build a deterministic synthetic multi-asset futures dataset.

The first asset is treated as the primary traded instrument (e.g., crude oil), while the other assets provide cross-asset context for allocation/risk.

The bars are **one minute** apart, starting 2024-01-01 09:30:00, so the dataset's periods_per_year is openquant.pipeline.MINUTE_BARS_PER_YEAR (98,280 = 390 bars a 6.5-hour session times 252 sessions); every annualised figure the research loop reports on it uses that factor, not the daily 252.

research_run_manifest

research_run_manifest(
    config: dict[str, Any],
    dataset_meta: dict[str, Any] | None = None,
) -> dict[str, Any]

Build deterministic run metadata for notebook/script parity.

run_flywheel_grid

run_flywheel_grid(
    dataset: ResearchDataset,
    configs: list[dict[str, Any]],
    *,
    run_names: list[str] | None = None,
) -> dict[str, Any]

Execute multiple flywheel configs and return a ranked leaderboard.

run_flywheel_iteration

run_flywheel_iteration(
    dataset: ResearchDataset,
    *,
    config: dict[str, Any] | None = None,
) -> dict[str, Any]

Run the mid-frequency pipeline once and add cost estimates and promotion checks.

Runs openquant.pipeline.run_mid_frequency_pipeline_frames on dataset, then estimates trading costs from the backtest frame and evaluates promotion gates. These cost and Sharpe figures are heuristics for comparing configurations, not a cost model:

  • turnover is the sum of absolute position changes between bars.
  • periods_per_year is config["periods_per_year"] if given, else dataset.periods_per_year, else derived from dataset.timestamps (openquant.pipeline.infer_periods_per_year). It is passed to the pipeline, so it also annualises risk["realized_sharpe"] and the portfolio stage.
  • bar_vol is the sample standard deviation of the per-bar strategy returns, and realized_vol is bar_vol * sqrt(periods_per_year).
  • cost_per_turn is (commission_bps + spread_bps) * 1e-4 + slippage_vol_mult * bar_vol * sqrt(252) * 1e-3, and the estimated total cost is turnover * cost_per_turn. The slippage term scales with the per-bar volatility and does not depend on periods_per_year: it is the formula the loop has always used (on daily bars it equals slippage_vol_mult * realized_vol * 1e-3).
  • gross_total_return is the final equity minus 1.0; net_total_return subtracts the estimated total cost.
  • net_sharpe is the Sharpe ratio of the per-bar returns net of costs: each bar's strategy return minus abs(position change into that bar) * cost_per_turn (the first bar pays nothing), so the per-bar costs add up to the estimated total cost. It is the mean over the sample standard deviation of those net returns, times sqrt(periods_per_year), and 0 when the deviation is 0.

Parameters

dataset : ResearchDataset

Pipeline inputs.

config : dict[str, Any] or None, default None

Overrides for the defaults: cusum_threshold (0.001), num_classes (2), step_size (0.1), risk_free_rate (0.0, annual), confidence_level (0.05) and periods_per_year (None: from the dataset, see above), passed to the pipeline; commission_bps (1.5), spread_bps (2.0) and slippage_vol_mult (8.0) for the cost estimate; min_net_sharpe (0.30) and min_realized_sharpe (0.25) for promotion. Unknown keys are ignored.

Returns

dict[str, Any]

The pipeline output (events, signals, portfolio, risk, backtest, leakage_checks, frames) plus:

  • costs: turnover, periods_per_year, bar_vol, realized_vol, cost_per_turn, estimated_total_cost, gross_total_return, net_total_return and net_sharpe.
  • promotion: booleans passed_realized_sharpe (pipeline realized Sharpe >= min_realized_sharpe), passed_net_sharpe, passed_alignment_guard, passed_event_order_guard and promote_candidate (all of them).
  • summary: the one-row openquant.pipeline.summarize_pipeline frame with columns turnover, realized_vol, estimated_cost, gross_total_return, net_total_return and net_sharpe added.