Optimization
Mean-variance objectives, risk parity and efficient-frontier construction with diagnostics.
See the usage guide for task-oriented examples. Signatures below are generated from the public headers at the same commit as the rest of this site.
-
struct efficient_frontier_result
Efficient-frontier points and endpoint portfolios.
Public Members
-
std::vector<double> frontier_returns
Annualized expected return of each point, from the minimum-variance return to the maximum-return endpoint.
-
std::vector<double> frontier_volatilities
Annualized volatility of each point.
-
std::vector<double> frontier_sharpe
Sharpe ratio of each point; 0 where volatility is negligible.
-
std::vector<std::vector<double>> frontier_weights
Asset weights of each point, in
asset_namesorder.
-
portfolio_point min_variance
Minimum-variance endpoint portfolio.
-
portfolio_point max_sharpe
Maximum-Sharpe portfolio.
-
double max_sharpe_ratio = 0.0
Sharpe ratio of
max_sharpe; 0 where volatility is negligible.
-
std::vector<std::string> asset_names
Asset names, in returns column order.
-
double periods_per_year = 252.0
Annualization factor copied from the configuration.
-
frontier_point_diagnostics min_variance_diagnostics
Residuals of the minimum-variance endpoint.
-
frontier_point_diagnostics max_sharpe_diagnostics
Residuals of the max-Sharpe portfolio.
-
std::vector<frontier_point_diagnostics> frontier_diagnostics
Per-point residuals, parallel to
frontier_returns.
-
std::vector<double> frontier_returns
-
struct frontier_config
Efficient-frontier computation settings.
Public Members
-
std::size_t n_points = 50U
Number of frontier points; must be at least 2.
-
double risk_free_rate = 0.0
Annualized risk-free rate used for Sharpe ratios; must be finite.
-
bool short_allowed = false
Allow weights down to
-max_weightinstead of 0.
-
double max_weight = 1.0
Per-asset upper bound; must be finite and greater than 0.
-
double periods_per_year = 252.0
Annualization factor; must be positive and finite.
-
std::size_t n_points = 50U
-
struct frontier_point_diagnostics
Constraint residuals measured for one frontier point.
Public Members
-
frontier_solver solver = frontier_solver::projected_gradient
Solver used for the point.
-
double sum_residual = 0.0
Absolute deviation of the weight sum from 1.
-
double lower_bound_residual = 0.0
Largest lower-bound violation; 0 when feasible.
-
double upper_bound_residual = 0.0
Largest upper-bound violation; 0 when feasible.
-
double target_return_residual = 0.0
Absolute target-return deviation; 0 when no target was imposed.
-
frontier_solver solver = frontier_solver::projected_gradient
-
struct portfolio_optimization_config
Inputs for optimize_portfolio.
Public Members
-
portfolio_objective objective = portfolio_objective::max_sharpe
Objective to optimize.
-
double risk_free_rate = 0.0
Annualized risk-free rate used by
max_sharpeand the reported Sharpe ratio; must be finite.
-
std::optional<double> target_return
Annualized expected return required by
target_return; must be finite when used.
-
std::optional<double> target_volatility
Annualized volatility required by
target_risk; must be finite and attainable.
-
bool short_allowed = false
Allow weights down to
-max_weightwhenmin_weightis unset.min_variancewithoutsector_constraintsis solved over the unit simplex, so that combination yields a long-only book regardless of this flag.
-
double max_weight = 1.0
Per-asset upper bound; must be finite and greater than 0.
-
std::optional<double> min_weight
Optional per-asset lower bound; must not exceed
max_weightand overrides theshort_alloweddefault.
-
std::vector<sector_allocation_constraint> sector_constraints
Sector weight bounds; requires
sector_map, and sectors without a mapped asset are ignored.
-
std::map<std::string, std::string> sector_map
Asset name to sector name mapping used by
sector_constraints.
-
portfolio_objective objective = portfolio_objective::max_sharpe
-
struct portfolio_optimization_result
Optimized weights and their annualized summary statistics.
Public Members
-
std::vector<double> weights
Asset weights in
asset_namesorder; they sum to 1.
-
double expected_return = 0.0
Annualized expected return, using 252 periods per year.
-
double volatility = 0.0
Annualized volatility, using 252 periods per year.
-
double sharpe = 0.0
(expected_return - risk_free_rate) / volatility; 0 where volatility is negligible.
-
std::vector<std::string> asset_names
Asset names, in returns column order.
-
portfolio_objective objective = portfolio_objective::max_sharpe
Objective that produced the result.
-
std::vector<double> weights
-
struct portfolio_point
One portfolio on the efficient frontier.
-
struct risk_parity_result
Risk-parity weights and their risk contributions.
Public Members
-
std::vector<double> weights
Asset weights in
asset_namesorder, normalized to sum to 1.
-
std::vector<double> risk_contributions
w_i * (Sigma w)_i / volatilityper asset; the values sum to the portfolio volatility.
-
double volatility = 0.0
Annualized portfolio volatility, using 252 periods per year.
-
std::vector<std::string> asset_names
Asset names, in returns column order.
-
std::vector<double> weights
-
struct sector_allocation_constraint
Bounds on the summed weights of the assets mapped to one sector.
-
enum class fincore::frontier_solver
Solver that produced one frontier point.
Values:
-
enumerator min_variance_degenerate
Minimum-variance weights reused for every point because the attainable return range is degenerate.
-
enumerator min_variance
First point, solved as a variance minimization.
-
enumerator projected_gradient
Interior target-return point or the max-Sharpe portfolio, solved by projected gradient descent.
-
enumerator bounded_linear_max_return
Last point, filled greedily by descending expected return up to the weight bounds.
-
enumerator min_variance_degenerate
-
enum class fincore::portfolio_objective
Portfolio optimization objective.
Values:
-
enumerator max_sharpe
Maximize the Sharpe ratio using
risk_free_rate.
-
enumerator min_variance
Minimize portfolio variance.
-
enumerator target_return
Minimize variance subject to the expected return equaling
target_return.
-
enumerator target_risk
Maximize expected return subject to the volatility equaling
target_volatility.
-
enumerator max_sharpe
-
efficient_frontier_result fincore::efficient_frontier(const dataframe &returns, const frontier_config &config = {})
Computes an efficient frontier from daily simple returns.
Points are evenly spaced in expected return between the minimum-variance portfolio and a maximum-return endpoint built by filling assets in descending mean-return order up to the weight bounds. Returns and volatilities are annualized with
config.periods_per_year, and Sharpe ratios useconfig.risk_free_rate. Solvers report constraint residuals infrontier_diagnosticsrather than a convergence status.- Parameters:
returns – Daily simple returns with one finite double column per asset and at least two observations.
config – Frontier settings;
n_pointsmust be at least 2.
- Throws:
input_error – If
returnsis empty or too short, fewer than two assets are present, values are non-finite, or a configuration value is invalid.optimization_error – If the covariance matrix is not positive semidefinite, the weight bounds cannot fund a fully invested portfolio, or a solver returns infeasible weights.
- Returns:
Frontier points, endpoint portfolios and per-point diagnostics.
-
portfolio_optimization_result fincore::optimize_portfolio(const dataframe &returns, const portfolio_optimization_config &config = {})
Optimizes portfolio weights for one supported objective.
Returns are annualized with a fixed 252-period year. Sector constraints apply only to assets listed in
sector_map, and infeasible targets are reported by throwing rather than through a status field.- Parameters:
returns – Daily simple returns with one finite double column per asset and at least two observations.
config – Objective, bounds and optional sector constraints.
- Throws:
input_error – If
returnsis empty, too short or non-finite, an objective-specific target is missing, weight bounds are invalid, sector constraints lack a sector map, or the objective is unknown.optimization_error – If the weight bounds cannot produce a fully invested portfolio,
target_volatilitylies outside the attainable range, or the solver returns infeasible weights.
- Returns:
Optimized weights, annualized return, volatility, Sharpe ratio and asset names.
-
risk_parity_result fincore::risk_parity(const dataframe &returns, std::optional<std::vector<double>> risk_budget = std::nullopt, std::size_t max_iter = 1000U)
Computes risk-parity weights with equal or user-supplied risk budgets.
The solver minimizes squared deviations between realized risk-contribution shares and the normalized risk budget, then renormalizes the weights to sum to 1. Returns and volatility use a fixed 252-period year. Weights are bounded to
[1e-6, 1.0]during the solve.- Parameters:
returns – Daily simple returns with one finite double column per asset and at least two observations.
risk_budget – Optional per-asset budget with finite, non-negative entries and a positive sum; it is normalized internally. A uniform budget is used when omitted.
max_iter – Maximum projected-gradient iterations per penalty stage; must be at least 1.
- Throws:
input_error – If
returnsis empty, too short or non-finite,max_iteris zero, or the risk budget is malformed.optimization_error – If the solved weights cannot be normalized to a positive sum.
- Returns:
Risk-parity weights, risk contributions, annualized volatility and asset names.