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

openquant.portfolio

Compiled from Rust (crates/pyopenquant). Signatures and types are from the shipped .pyi stubs; descriptions are the functions’ own docstrings, as help() shows them. All Python modules.

Functions

allocate_efficient_risk

allocate_efficient_risk(
    prices: Sequence[Sequence[float]],
    target_return: float,
    bounds: Sequence[tuple[int, float, float]] | None = None,
    tuple_bounds: tuple[float, float] | None = None,
) -> tuple[list[float], float, float, float]

Least-risk portfolio from a price matrix whose expected return is at least a target.

Solves min w' Sigma w subject to mu' w >= target_return, sum(w) = 1 and the bounds. A target below the minimum-variance portfolio's return yields that portfolio. Returns are simple returns and both mu and Sigma are annualised with 252 periods a year (daily rows), so target_return is an annual figure. Markowitz (1952); AFML chapter 16.

Parameters

prices : list[list[float]]

Price matrix, one inner list per date (ascending in time, at least 2 rows) and one column per asset.

target_return : float

Minimum annualised expected return (a floor, not an equality).

bounds : list[tuple[int, float, float]] | None, default None

Per-asset (asset_index, lower, upper) weight bounds; they override tuple_bounds for those assets. Out-of-range indices are ignored.

tuple_bounds : tuple[float, float] | None, default None

(lower, upper) bounds for every asset not in bounds; None means (0, 1). Upper bounds above 1 are treated as 1; negative lower bounds allow shorting.

Returns

tuple[list[float], float, float, float]

(weights, portfolio_risk, portfolio_return, portfolio_sharpe): weights per asset in column order summing to 1, annualised volatility, annualised expected return, and portfolio_return / portfolio_risk (0 when the risk is 0).

Raises

ValueError

If prices is empty or ragged, or the core rejects the input (e.g. fewer than two rows, a zero price, bounds that cannot sum to 1, or an unreachable target_return).

allocate_from_inputs

allocate_from_inputs(
    expected_returns: Sequence[float],
    covariance: Sequence[Sequence[float]],
    solution: str,
    risk_free_rate: float = 0.0,
    target_return: float = 0.0,
    bounds: Sequence[tuple[int, float, float]] | None = None,
    tuple_bounds: tuple[float, float] | None = None,
) -> tuple[list[float], float, float, float]

Allocate a mean-variance portfolio from given expected returns and covariance.

Same solutions as allocate_with_solution ("inverse_variance", "min_volatility", "max_sharpe", "efficient_risk"), but no returns are estimated and nothing is annualised: the units are the caller's, and expected_returns, covariance, risk_free_rate and target_return must agree (an annual mu with a daily covariance overstates the Sharpe ratio by sqrt(252)). Markowitz (1952); AFML chapter 16.

Parameters

expected_returns : list[float]

Expected return per asset.

covariance : list[list[float]]

Square covariance matrix in the same asset order, one inner list per row.

solution : str

"inverse_variance", "min_volatility", "max_sharpe" or "efficient_risk".

risk_free_rate : float, default 0.0

Risk-free rate for "max_sharpe" and the reported Sharpe ratio.

target_return : float, default 0.0

Minimum expected return for "efficient_risk"; ignored otherwise.

bounds : list[tuple[int, float, float]] | None, default None

Per-asset (asset_index, lower, upper) weight bounds; they override tuple_bounds for those assets. Out-of-range indices are ignored.

tuple_bounds : tuple[float, float] | None, default None

(lower, upper) bounds for every asset not in bounds; None means (0, 1). Upper bounds above 1 are treated as 1; negative lower bounds allow shorting.

Returns

tuple[list[float], float, float, float]

(weights, portfolio_risk, portfolio_return, portfolio_sharpe) in the caller's units: weights summing to 1, sqrt(w' Sigma w), mu' w, and (portfolio_return - risk_free_rate) / portfolio_risk (0 when the risk is 0).

Raises

ValueError

If covariance is empty or ragged, or the core rejects the input (e.g. a non-square covariance or one whose size differs from expected_returns, an unknown solution, bounds that cannot sum to 1, an unreachable target_return, or no asset above risk_free_rate for "max_sharpe").

allocate_inverse_variance

allocate_inverse_variance(
    prices: Sequence[Sequence[float]],
) -> tuple[list[float], float, float, float]

Inverse-variance portfolio from a price matrix, long-only and fully invested.

Weights are w_i = (1 / Sigma_ii) / sum_j(1 / Sigma_jj) (correlation ignored), where Sigma is the sample covariance of simple returns p_t / p_{t-1} - 1. Expected returns and covariance are annualised with 252 periods a year, so the reported figures are annual for daily rows. The 252 assumes daily rows: for one-minute rows multiply the return by 390 and the risk by sqrt(390); the weights do not depend on it. Markowitz (1952); see AFML chapter 16 for why mean-variance portfolios are fragile.

Parameters

prices : list[list[float]]

Price matrix, one inner list per date (ascending in time, at least 2 rows) and one column per asset.

Returns

tuple[list[float], float, float, float]

(weights, portfolio_risk, portfolio_return, portfolio_sharpe): weights per asset in column order summing to 1, annualised volatility sqrt(w' Sigma w), annualised expected return mu' w, and portfolio_return / portfolio_risk (0 when the risk is 0).

Raises

ValueError

If prices is empty or ragged, or the core rejects the input (e.g. fewer than two rows, a zero price used as a return denominator, or an asset with zero return variance).

allocate_max_sharpe

allocate_max_sharpe(
    prices: Sequence[Sequence[float]],
    risk_free_rate: float | None = None,
    bounds: Sequence[tuple[int, float, float]] | None = None,
    tuple_bounds: tuple[float, float] | None = None,
) -> tuple[list[float], float, float, float]

Maximum-Sharpe portfolio from a price matrix, with weight bounds.

Maximises (mu' w - rf) / sqrt(w' Sigma w) subject to sum(w) = 1 and the bounds, via the substitution y = kappa w. Returns are simple returns and both mu and Sigma are annualised with 252 periods a year, so risk_free_rate is an annual rate. The 252 assumes daily rows; openquant.pipeline.run_mid_frequency_pipeline rescales for other bar frequencies with periods_per_year. The Sharpe ratio is in-sample. Markowitz (1952); AFML chapter 16.

Parameters

prices : list[list[float]]

Price matrix, one inner list per date (ascending in time, at least 2 rows) and one column per asset.

risk_free_rate : float | None, default None

Annual risk-free rate; None means 0.0.

bounds : list[tuple[int, float, float]] | None, default None

Per-asset (asset_index, lower, upper) weight bounds; they override tuple_bounds for those assets. Out-of-range indices are ignored.

tuple_bounds : tuple[float, float] | None, default None

(lower, upper) bounds for every asset not in bounds; None means (0, 1). Upper bounds above 1 are treated as 1; negative lower bounds allow shorting.

Returns

tuple[list[float], float, float, float]

(weights, portfolio_risk, portfolio_return, portfolio_sharpe): weights per asset in column order summing to 1, annualised volatility, annualised expected return, and (portfolio_return - risk_free_rate) / portfolio_risk.

Raises

ValueError

If prices is empty or ragged, or the core rejects the input (e.g. fewer than two rows, a zero price, bounds that cannot sum to 1, no asset with an expected return above risk_free_rate, or a degenerate solution).

allocate_min_vol

allocate_min_vol(
    prices: Sequence[Sequence[float]],
    bounds: Sequence[tuple[int, float, float]] | None = None,
    tuple_bounds: tuple[float, float] | None = None,
) -> tuple[list[float], float, float, float]

Minimum-volatility portfolio from a price matrix, min w' Sigma w with weight bounds.

Solves the quadratic programme subject to sum(w) = 1 and the bounds (the bounds are part of the problem, not applied afterwards). Returns are simple returns and both the expected returns and covariance are annualised with 252 periods a year (daily rows; the weights do not depend on the factor). Markowitz (1952); AFML chapter 16.

Parameters

prices : list[list[float]]

Price matrix, one inner list per date (ascending in time, at least 2 rows) and one column per asset.

bounds : list[tuple[int, float, float]] | None, default None

Per-asset (asset_index, lower, upper) weight bounds; they override tuple_bounds for those assets. Out-of-range indices are ignored.

tuple_bounds : tuple[float, float] | None, default None

(lower, upper) bounds for every asset not in bounds; None means (0, 1). Upper bounds above 1 are treated as 1; negative lower bounds allow shorting.

Returns

tuple[list[float], float, float, float]

(weights, portfolio_risk, portfolio_return, portfolio_sharpe): weights per asset in column order summing to 1, annualised volatility, annualised expected return, and portfolio_return / portfolio_risk (0 when the risk is 0).

Raises

ValueError

If prices is empty or ragged, or the core rejects the input (e.g. fewer than two rows, a zero price, bounds that cannot sum to 1, or no feasible or convergent solution).

allocate_with_solution

allocate_with_solution(
    prices: Sequence[Sequence[float]],
    solution: str,
    risk_free_rate: float = 0.0,
    target_return: float = 0.0,
    bounds: Sequence[tuple[int, float, float]] | None = None,
    tuple_bounds: tuple[float, float] | None = None,
    resample_by: str | None = None,
    returns_method: str | None = None,
) -> tuple[list[float], float, float, float]

Allocate a mean-variance portfolio from a price matrix with a named solution.

Estimates annualised expected returns mu and covariance Sigma from simple returns of the (optionally resampled) prices, both scaled by 252 / step, then solves one of: "inverse_variance" (weights proportional to 1 / Sigma_ii, projected onto the bounds), "min_volatility", "max_sharpe" or "efficient_risk" (least risk with mu' w >= target_return). Weights are fully invested; risk_free_rate and target_return are annual. Markowitz (1952); AFML chapter 16.

Parameters

prices : list[list[float]]

Price matrix, one inner list per date (ascending in time) and one column per asset.

solution : str

"inverse_variance", "min_volatility", "max_sharpe" or "efficient_risk".

risk_free_rate : float, default 0.0

Annual risk-free rate for "max_sharpe" and for the reported Sharpe ratio.

target_return : float, default 0.0

Minimum annual expected return for "efficient_risk"; ignored otherwise.

bounds : list[tuple[int, float, float]] | None, default None

Per-asset (asset_index, lower, upper) weight bounds; they override tuple_bounds for those assets. Out-of-range indices are ignored.

tuple_bounds : tuple[float, float] | None, default None

(lower, upper) bounds for every asset not in bounds; None means (0, 1). Upper bounds above 1 are treated as 1; negative lower bounds allow shorting.

resample_by : str | None, default None

"W"/"week"/"weekly" keeps every 5th row, "M"/"month"/"monthly" every 21st (case-insensitive); anything else, or None, keeps every row.

returns_method : str | None, default None

"mean"/"mean_historical" (arithmetic mean, the default) or "exponential"/"exponential_historical" (exponentially weighted mean, span 500); case-insensitive.

Returns

tuple[list[float], float, float, float]

(weights, portfolio_risk, portfolio_return, portfolio_sharpe): weights per asset in column order summing to 1, annualised volatility, annualised expected return, and (portfolio_return - risk_free_rate) / portfolio_risk (0 when the risk is 0).

Raises

ValueError

If prices is empty or ragged, returns_method is unknown, or the core rejects the input (e.g. an unknown solution, fewer than two rows after resampling, a zero price, bounds that cannot sum to 1, an unreachable target_return, no asset above risk_free_rate for "max_sharpe", or a zero variance for "inverse_variance").