This repository includes a Python package built from Rust using PyO3 and maturin, with uv as the Python package and virtual environment manager.
Prerequisites:
- Rust stable toolchain
uv(https://docs.astral.sh/uv/)
From repo root:
uv venv --python 3.13 .venv
uv sync --group dev
uv run --python .venv/bin/python maturin develop --manifest-path crates/pyopenquant/Cargo.toml
uv run --python .venv/bin/python python -c "import openquant; print('openquant import ok')"
uv run --python .venv/bin/python pytest python/tests -qQuick performance showcase:
uv run --python .venv/bin/python python python/benchmarks/benchmark_pipeline.py --iterations 30 --bars 2048
uv run --python .venv/bin/python python python/benchmarks/benchmark_data_processing.py --rows-per-symbol 200000 --symbols 4 --iterations 7 --out benchmarks/data_processing/latest.jsonBuild a wheel:
uv run --python .venv/bin/python maturin build --manifest-path crates/pyopenquant/Cargo.toml --out distcalculate_value_at_risk(returns, confidence_level)calculate_expected_shortfall(returns, confidence_level)calculate_conditional_drawdown_risk(returns, confidence_level)
Input conventions:
returns: list of floatsconfidence_level: float in[0, 1]
cusum_filter_indices(close, threshold)cusum_filter_timestamps(close, timestamps, threshold)z_score_filter_indices(close, mean_window, std_window, threshold)z_score_filter_timestamps(close, timestamps, mean_window, std_window, threshold)
Input conventions:
close: list of floatstimestamps: list of strings formatted as%Y-%m-%d %H:%M:%S- timestamp variants require
len(close) == len(timestamps)
build_time_bars(df, interval="1d")build_tick_bars(df, ticks_per_bar=50)build_volume_bars(df, volume_per_bar=100_000.0)build_dollar_bars(df, dollar_value_per_bar=5_000_000.0)bar_diagnostics(df)
Input conventions:
df: polars DataFrame with canonical OHLCV columns (ts,symbol,open,high,low,close,volume,adj_close)
load_ohlcv(path, symbol=None, return_report=False)clean_ohlcv(df, dedupe_keep="last", return_report=False)data_quality_report(df)align_calendar(df, interval="1d")
Notes:
- File IO and column alias canonicalization happen in Python for ergonomics.
- Core cleaning, deduplication, quality reporting, and calendar alignment are executed in Rust through
_core.data.
get_ind_matrix(label_endtime, bar_index)get_ind_mat_average_uniqueness(ind_mat)seq_bootstrap(ind_mat, sample_length=None, warmup_samples=None)
Input conventions:
label_endtime: list of(start_idx, end_idx)tuplesbar_index: list of integer bar indicesind_mat: nested list of 0/1 integers
get_signal(prob, num_classes, pred=None)discrete_signal(signal0, step_size)bet_size(w_param, price_div, func)
Input conventions:
funcforbet_sizemust besigmoidorpower
allocate_inverse_variance(prices)allocate_min_vol(prices)allocate_max_sharpe(prices, risk_free_rate=0.0)
Return conventions:
- tuple
(weights, portfolio_risk, portfolio_return, portfolio_sharpe)
Input conventions:
prices: rectangular nested list of floats (rows=time,cols=assets)
to_polars_signal_frame(...)to_polars_event_frame(...)to_polars_indicator_matrix(...)to_polars_weights_frame(...)to_polars_frontier_frame(...)to_polars_backtest_frame(...)SignalStreamBufferfor incremental signal updates in streaming/online notebook loops
run_mid_frequency_pipeline(...)run_mid_frequency_pipeline_frames(...)summarize_pipeline(...)
run_mid_frequency_pipeline contract:
- Inputs:
timestamps,close,model_probabilities(aligned 1:1)asset_prices(rows=time,cols=assets)- optional
model_sides,asset_names - params:
cusum_threshold,num_classes,step_size,risk_free_rate,confidence_level
- Outputs:
events: event indices/timestamps/probabilities/sidessignals: event signal + aligned timeline signalportfolio: max-sharpe allocation summaryrisk: VaR/ES/CDaR + realized Sharpebacktest: strategy returns, equity curve, drawdown metricsleakage_checks: alignment and ordering guards
run_mid_frequency_pipeline_frames adds notebook-ready polars frames for signals, events, backtest, and weights.
make_synthetic_futures_dataset(n_bars=..., seed=..., asset_names=...)run_flywheel_iteration(dataset, config=...)
run_flywheel_iteration extends pipeline output with:
- cost model summary (turnover + vol/spread proxy),
- net/gross return and net Sharpe,
- promotion decision gates (statistical + economic).
prepare_feature_importance_payload(...)prepare_drawdown_payload(...)prepare_regime_payload(...)prepare_frontier_payload(...)prepare_cluster_payload(...)
Example:
import openquant
signal_df = openquant.adapters.to_polars_signal_frame(
timestamps=["2024-01-01 09:30:00", "2024-01-01 09:31:00"],
signal=[0.2, -0.1],
symbol="ES",
)
drawdown_payload = openquant.viz.prepare_drawdown_payload(
timestamps=["2024-01-01 09:30:00", "2024-01-01 09:31:00"],
equity_curve=[100.0, 99.5],
)
pipe = openquant.pipeline.run_mid_frequency_pipeline_frames(
timestamps=["2024-01-01 09:30:00", "2024-01-01 09:31:00", "2024-01-01 09:32:00"],
close=[100.0, 100.2, 100.1],
model_probabilities=[0.55, 0.58, 0.52],
asset_prices=[[100.0, 100.0], [100.2, 99.8], [100.1, 100.1]],
)
summary = openquant.pipeline.summarize_pipeline(pipe)ValueError: prices matrix must be rectangular- Ensure every row in
priceshas identical length.
- Ensure every row in
ValueError: close/timestamps length mismatch- Align prices and timestamps one-to-one before calling timestamp APIs.
ValueError: invalid datetime ...- Use
%Y-%m-%d %H:%M:%Stimestamp strings.
- Use
ModuleNotFoundError: No module named 'openquant'- Re-run
uv run --python .venv/bin/python maturin develop --manifest-path crates/pyopenquant/Cargo.toml.
- Re-run
- The binding layer is intentionally thin: Rust
openquantremains the source of truth. - Polars-first adapters, plotting payload builders, and notebook flywheel helpers are included for research UX.