construction¶
Constraint objects (re-exported from portpy.models.base), plus the optimize/build/efficient_frontier recipe layer over portpy.models.optimization. optimize/build/efficient_frontier are also exposed directly on Portfolio.models for convenience - see Construction, optimization & management.
Constraint objects¶
constraints ¶
Constraint objects for portpy.models.optimization/.construction.
Re-exported from portpy.models.base, which is where they're actually defined
(alongside the plumbing that translates them into scipy's constraint format) -
this module exists so they're discoverable at the "recipe layer" a typical
user reaches for: portpy.models.construction.constraints.WeightBounds(...).
GrossExposure
dataclass
¶
sum(abs(w)) == target - caps total (long + short) exposure, the natural
constraint for a long/short book (e.g. a 130/30 fund uses target=1.6).
GroupCap
dataclass
¶
GroupCap(
groups: dict[str, list[str]],
max_weight: float | dict[str, float],
min_weight: float | dict[str, float] | None = None,
)
Caps (and optionally floors) total exposure to named groups of assets -
e.g. sectors or core.asset.AssetClass buckets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
groups
|
dict[str, list[str]]
|
|
required |
max_weight
|
float | dict[str, float]
|
Maximum summed weight per group - either one number applied
to every group, or a |
required |
min_weight
|
float | dict[str, float] | None
|
Optional minimum summed weight per group, same shape as |
None
|
NetExposure
dataclass
¶
sum(w) == target - the usual full-investment constraint (target=1.0).
Applied automatically with target=1.0 when a constraint list has neither
this nor GrossExposure, so every solver is fully-invested by default.
TurnoverCap
dataclass
¶
Caps how far the solved weights may move away from a starting weight vector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_turnover
|
float
|
Maximum allowed |
required |
current_weights
|
Series | None
|
Starting weights. When left |
None
|
WeightBounds
dataclass
¶
WeightBounds(
low: float = 0.0,
high: float = 1.0,
per_asset: dict[str, tuple[float, float]] | None = None,
)
Per-asset weight bounds. low/high apply to every asset unless overridden
in per_asset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
low
|
float
|
Minimum weight for any asset not listed in |
0.0
|
high
|
float
|
Maximum weight for any asset not listed in |
1.0
|
per_asset
|
dict[str, tuple[float, float]] | None
|
Optional |
None
|
optimize / build / efficient_frontier¶
builders ¶
The recipe layer users hit most often: dispatch to a named optimizer
(optimize), or estimate expected_returns/cov_matrix from raw returns first
and then dispatch (build) - both wrapped into a ModelResult. efficient_frontier
lives here too (not in optimize's dispatch table - see its own docstring)
since it needs the same ModelResult-wrapping treatment.
optimize ¶
optimize(
expected_returns: Series | None = None,
cov_matrix: DataFrame | None = None,
method: str = "mean_variance",
constraints: Sequence[Any] | None = None,
**kwargs: Any,
) -> ModelResult
Dispatch to a named solver in portpy.models.optimization, wrapping its
result into a ModelResult with solver diagnostics attached.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expected_returns
|
Series | None
|
Annualized expected return per asset. Required by "mean_variance", "max_sharpe", "target_return", and "target_volatility"; ignored (and not required) by every other method. |
None
|
cov_matrix
|
DataFrame | None
|
Annualized asset covariance matrix. Required by every method. |
None
|
method
|
str
|
One of "mean_variance", "max_sharpe", "min_variance", "target_return", "target_volatility", "black_litterman", "hierarchical_risk_parity", "risk_parity", "risk_budgeting", "maximum_diversification". |
'mean_variance'
|
constraints
|
Sequence[Any] | None
|
Forwarded to the underlying solver - see |
None
|
**kwargs
|
Any
|
Method-specific keyword arguments, e.g. |
{}
|
Returns:
| Type | Description |
|---|---|
ModelResult
|
A |
ModelResult
|
|
ModelResult
|
which isn't numerically solved) |
ModelResult
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/portpy/models/construction/builders.py
build ¶
build(
y: DataFrame | None = None,
method: str = "mean_variance",
constraints: Sequence[Any] | None = None,
expected_returns_kwargs: dict[str, Any] | None = None,
covariance_kwargs: dict[str, Any] | None = None,
**kwargs: Any,
) -> ModelResult
The recipe most users actually want: estimate expected_returns/cov_matrix
from raw returns via portpy.models.estimators, then optimize().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
DataFrame | None
|
Per-asset periodic returns (the full multi-asset DataFrame). Required
explicitly here; auto-filled from the portfolio when called via
|
None
|
method
|
str
|
See |
'mean_variance'
|
constraints
|
Sequence[Any] | None
|
See |
None
|
expected_returns_kwargs
|
dict[str, Any] | None
|
Extra keyword arguments for
|
None
|
covariance_kwargs
|
dict[str, Any] | None
|
Extra keyword arguments for |
None
|
**kwargs
|
Any
|
Forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
ModelResult
|
A |
ModelResult
|
additionally recording the estimator kwargs and data shape used. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/portpy/models/construction/builders.py
efficient_frontier ¶
efficient_frontier(
expected_returns: Series,
cov_matrix: DataFrame,
n_points: int = 50,
constraints: Sequence[Any] | None = None,
min_return: float | None = None,
max_return: float | None = None,
) -> ModelResult
Trace the efficient frontier and wrap it into a ModelResult - kept as its
own call rather than folded into optimize()/build(), since it returns a
curve of portfolios, not one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expected_returns
|
Series
|
Annualized expected return per asset. |
required |
cov_matrix
|
DataFrame
|
Annualized asset covariance matrix. |
required |
n_points
|
int
|
Number of frontier points to compute. |
50
|
constraints
|
Sequence[Any] | None
|
Forwarded to every point's solve - see |
None
|
min_return
|
float | None
|
See |
None
|
max_return
|
float | None
|
See |
None
|
Returns:
| Type | Description |
|---|---|
ModelResult
|
A |
ModelResult
|
point on the curve; the full curve is |
ModelResult
|
what |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If not even one grid point was solvable. |