openquant.dynamic_allocation
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
all_weights
all_weights(k: int, n: int) -> list[list[float]]The set of signed weight vectors searched by the dynamic allocation (AFML Snippet 21.2).
Every partition from pigeonhole_partitions(k, n) is divided by k, so its absolute weights sum to 1 (gross exposure 1), and given every combination of signs. Unlike the book, which repeats vectors whose zero entries are sign-flipped, each vector appears once, at its first occurrence in the book's order.
Parameters
k: intNumber of units of capital; weights are multiples of
1 / k. Must be positive.n: intNumber of assets. Must be positive.
Returns
- list[list[float]]
One weight vector of length
nper element of the set.
Raises
- ValueError
If
kornis 0.
dynamic_optimal_portfolio
dynamic_optimal_portfolio(
means: Sequence[Sequence[float]],
covariances: Sequence[Sequence[Sequence[float]]],
costs: Sequence[Sequence[float]],
k: int | None = None,
initial_weights: Sequence[float] | None = None,
max_trajectories: int = ...,
) -> AnyBest weight trajectory by exhaustive integer search (AFML Snippet 21.3, dynOptPort).
Enumerates every trajectory in Omega^H, where Omega is all_weights(k, N) and H the number of horizons, scores each with trajectory_sharpe_ratio and keeps the first trajectory with the highest score (the book's order and tie-breaking). The count |Omega|^H grows fast (38 vectors for N = k = 3, so 54,872 trajectories over three horizons but 79,235,168 over five); a problem above max_trajectories is rejected before any work is done. The search releases the GIL.
Parameters
means: list[list[float]]Expected return of each asset, one list of length
Nper horizon.covariances: list[list[list[float]]]Symmetric positive definite
N x Ncovariance matrix per horizon (row lists).costs: list[list[float]]Non-negative cost coefficient of each asset, one list of length
Nper horizon; tradingxof weight costsc * sqrt(|x|).k: int | None, default NoneUnits of capital; weights are multiples of
1 / k. None uses the book's defaultk = N.initial_weights: list[float] | None, default NonePortfolio held before the first horizon; None starts from cash (all zeros).
max_trajectories: int, default 1000000Largest number of trajectories the search may evaluate.
Returns
- dict[str, Any]
weights(list[list[float]], one vector of lengthNper horizon; the book returns the transpose),sharpe_ratio(float, net of costs),transaction_costs(list[float], one per horizon) andtrajectories_evaluated(int,|Omega|^H).
Raises
- ValueError
If
means,covariancesandcostsdiffer in length, a covariance is not square, or the core rejects the input (e.g. no horizons or assets,kof 0, a length that does not matchN, a NaN or infinity, a negative cost, a covariance that is not symmetric positive definite, or more thanmax_trajectoriestrajectories).
pigeonhole_partitions
pigeonhole_partitions(k: int, n: int) -> list[list[int]]Every way to place k indivisible units of capital into n assets (AFML Snippet 21.1).
Each partition is a list of n non-negative counts summing to k, in the book's order (the order itertools.combinations_with_replacement(range(n), k) implies): [k, 0, ..., 0] first and [0, ..., 0, k] last. There are C(k + n - 1, n - 1) of them, so large inputs produce very long lists. With n = 0 there is one (empty) partition of k = 0 and none of any larger k.
Parameters
k: intNumber of units of capital.
n: intNumber of assets (slots).
Returns
- list[list[int]]
One list of
ncounts per partition.
trajectory_sharpe_ratio
trajectory_sharpe_ratio(
trajectory: Sequence[Sequence[float]],
means: Sequence[Sequence[float]],
covariances: Sequence[Sequence[Sequence[float]]],
costs: Sequence[Sequence[float]],
initial_weights: Sequence[float] | None = None,
) -> floatSharpe ratio of a weight trajectory net of transaction costs (AFML Snippet 21.3, evalSR).
SR = sum_h (mu_h' w_h - tau_h) / sqrt(sum_h w_h' V_h w_h), with tau_h from transaction_costs. Costs are subtracted from the mean only; the variance is that of the gross returns, as in the book.
Parameters
trajectory: list[list[float]]One weight vector of length
Nper horizon, in horizon order.means: list[list[float]]Expected return of each asset, one list of length
Nper horizon.covariances: list[list[list[float]]]Symmetric positive definite
N x Ncovariance matrix per horizon (row lists).costs: list[list[float]]Non-negative cost coefficient of each asset, one list of length
Nper horizon.initial_weights: list[float] | None, default NonePortfolio held before the first horizon; None starts from cash (all zeros).
Returns
- float
The trajectory's net Sharpe ratio.
Raises
- ValueError
If
means,covariancesandcostsdiffer in length, a covariance is not square, or the core rejects the input (e.g. no horizons or assets, a length that does not matchNor the number of horizons, a NaN or infinity, a negative cost, a covariance that is not symmetric positive definite, or a trajectory whose total variance is not positive, such as all zeros).
transaction_costs
transaction_costs(
trajectory: Sequence[Sequence[float]],
means: Sequence[Sequence[float]],
covariances: Sequence[Sequence[Sequence[float]]],
costs: Sequence[Sequence[float]],
initial_weights: Sequence[float] | None = None,
) -> list[float]Transaction cost of each horizon of a weight trajectory (AFML Snippet 21.3, evalTCosts).
tau_h = sum_n c[h][n] * sqrt(|w[h][n] - w[h-1][n]|), where w[-1] is initial_weights. The square root makes the cost concave in the trade size. The forecasts are validated as in dynamic_optimal_portfolio, including the covariances.
Parameters
trajectory: list[list[float]]One weight vector of length
Nper horizon, in horizon order.means: list[list[float]]Expected return of each asset, one list of length
Nper horizon.covariances: list[list[list[float]]]Symmetric positive definite
N x Ncovariance matrix per horizon (row lists).costs: list[list[float]]Non-negative cost coefficient of each asset, one list of length
Nper horizon.initial_weights: list[float] | None, default NonePortfolio held before the first horizon; None starts from cash (all zeros).
Returns
- list[float]
The cost
tau_hof each horizon.
Raises
- ValueError
If
means,covariancesandcostsdiffer in length, a covariance is not square, or the core rejects the input (e.g. no horizons or assets, a length that does not matchNor the number of horizons, a NaN or infinity, a negative cost, or a covariance that is not symmetric positive definite).