sf_quant.optimizer.dynamic_mve_optimizer#
- sf_quant.optimizer.dynamic_mve_optimizer(ids: list[str], alphas: ndarray, factor_exposures: ndarray, factor_covariance: ndarray, specific_risk: ndarray, constraints: list[Constraint], initial_gamma: float = 100, betas: ndarray | None = None, target_active_risk: float | None = None, benchmark_weights: ndarray | None = None, active_weights: bool = False) DataFrame#
Mean-variance optimizer with optional active risk calibration.
Extends
mve_optimizer()with the ability to automatically calibrate the risk aversion parameter (gamma) to achieve a target level of active risk (tracking error) relative to a benchmark portfolio. Uses iterative optimization with linear regression to solve for the gamma that produces the desired active risk.Parameters#
- idslist[str]
Asset identifiers (e.g., ticker symbols or BARRAs).
- alphasnp.ndarray
Expected returns for each asset, shape (n_assets,).
- factor_exposuresnp.ndarray
B matrix of shape (n_assets, n_factors), containing asset factor exposures.
- factor_covariancenp.ndarray
F matrix of shape (n_factors, n_factors), factor covariance matrix.
- specific_risknp.ndarray
D vector of shape (n_assets,), idiosyncratic variance per asset.
- constraintslist[Constraint]
List of constraint objects implementing the
Constraintprotocol.- initial_gammafloat, optional
Starting value for gamma in calibration. Also used as the warm-start seed if
target_active_riskis specified. Default is 100.- betasnp.ndarray, optional
Predicted betas or other asset-level values required by certain constraints.
- target_active_riskfloat, optional
If specified, automatically calibrate gamma to achieve this target annualized active risk (e.g., 0.05 for 5%). Requires
benchmark_weights. If not specified, usesinitial_gammadirectly.- benchmark_weightsnp.ndarray, optional
Benchmark portfolio weights of shape (n_assets,), required if
target_active_riskis specified.- active_weightsbool
Flag indicating how to treat output weights of optimizer. False (default) means that we subtract of benchmark weights before computing active risk.
Returns#
- pl.DataFrame
Polars DataFrame with columns:
barrid: str, asset identifier.weight: float, optimized portfolio weight.gamma: float, calibrated risk aversion parameter.active_risk: float, achieved annualized active risk.
See Also#
mve_optimizer : Base mean-variance optimizer without active risk calibration. _calibrate_gamma : Gamma calibration routine.
Examples#
>>> import sf_quant.optimizer as sfo >>> import numpy as np >>> ids = ['AAPL', 'IBM'] >>> alphas = np.array([1.1, 1.2]) >>> factor_exposures = np.array([[0.8, 0.5], [1.2, 0.3]]) >>> factor_covariance = np.array([[0.5, 0.1], [0.1, 0.2]]) >>> specific_risk = np.array([0.1, 0.15]) >>> benchmark_weights = np.array([0.4, 0.6]) >>> constraints = [sfo.FullInvestment()] >>> weights = sfo.dynamic_mve_optimizer( ... ids=ids, ... alphas=alphas, ... factor_exposures=factor_exposures, ... factor_covariance=factor_covariance, ... specific_risk=specific_risk, ... constraints=constraints, ... initial_gamma=100, ... target_active_risk=0.05, ... benchmark_weights=benchmark_weights ... ) >>> weights shape: (2, 4) ┌────────┬────────┬───────┬──────────────┐ │ barrid ┆ weight ┆ gamma ┆ active_risk │ │ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ f64 ┆ f64 ┆ f64 │ ╞════════╪════════╪═══════╪══════════════╡ │ AAPL ┆ 0.40 ┆ 75.5 ┆ 0.05 │ │ IBM ┆ 0.60 ┆ 75.5 ┆ 0.05 │ └────────┴────────┴───────┴──────────────┘