Finance#
Portfolio projection lives on the mixture itself
(project()); there is no
separate finance-layer wrapper.
Risk Measures#
Coherent risk measures for univariate normal-mixture portfolio returns.
The current implementation provides Conditional Value at Risk (CVaR), with
value, first derivatives, and second derivatives in both the projected
parameter space \((\tilde\mu, \tilde\gamma, \tilde\sigma)\) and the
portfolio-weight space \(w \in \mathbb{R}^d\). Formulas follow
docs/theory/cvar_derivatives.md.
Monte Carlo for CVaR value and derivatives is conditional over the
subordinator \(Y\) (common random numbers). Deterministic VaR uses
the Univariate* PINV ppf().
- class normix.finance.risk.RiskMeasure[source]#
Bases:
ModuleAbstract base for portfolio risk measures.
- abstractmethod value(univariate, Y)[source]#
Risk of the univariate normal mixture represented by
univariate.
- abstractmethod value_reduced(mu, gamma, sigma, Y)[source]#
Risk from raw scalar parameters \((\tilde\mu, \tilde\gamma, \tilde\sigma)\).
The univariate normal mixture is \(\tilde\mu + \tilde\gamma Y + \tilde\sigma\sqrt{Y}Z\). Unlike
value(), this signature takes plain scalars (no distribution object) and must be Bessel-/PINV-free so it can bejax.vmap()-ed across an efficient-surface grid that shares the subordinator drawsY.
- value_grad_hess_w(model, w, Y)[source]#
Fused \((r(w), \nabla_w r, H_r(w))\) under one CRN sample
Y.Consumed by
transaction_costsanddiversification. Concrete measures override with an analytically fused implementation (CVaR shares one CMC VaR solve); the base raises — a value-only measure cannot participate in the derivative-consuming layers.
- class normix.finance.risk.CVaR(alpha)[source]#
Bases:
RiskMeasureConditional Value at Risk at confidence \(\alpha \in (0, 1)\).
For a univariate normal mixture \(X = \tilde\mu + \tilde\gamma Y + \tilde\sigma \sqrt{Y} Z\), the value is computed in closed form conditional on \(Y\):
\[\operatorname{CVaR}_\alpha(X) = \frac{1}{\alpha} E_Y\!\left[ \tilde\sigma \sqrt{Y} \, \varphi(z_Y) - (\tilde\mu + \tilde\gamma Y) \Phi(z_Y) \right],\]where \(z_Y = (x_\alpha - \tilde\mu - \tilde\gamma Y) / (\tilde\sigma \sqrt{Y})\) and \(x_\alpha = -\operatorname{VaR}_\alpha\) is found by bisection on the conditional Monte Carlo CDF (same
Yas the integral, for common random numbers).- Parameters:
alpha (float)
- var(univariate)[source]#
\(\operatorname{VaR}_\alpha\) via deterministic PINV
ppf().- Parameters:
univariate (_UnivariateNormalMixtureMixin)
- Return type:
- value_reduced(mu, gamma, sigma, Y)[source]#
CVaR from raw scalar parameters, vectorizable over a surface grid.
Inverts the conditional-MC CDF for \(x_\alpha\) within an analytic bracket \(E[X] \pm 20\,\mathrm{std}[X]\) derived from the subordinator sample moments of
Y— no PINV table, no Bessel evaluation — then reuses_cvar_from_quantile().
- gradient_scalar(univariate, Y)[source]#
Return \((\partial r / \partial \tilde\mu, \partial r / \partial \tilde\gamma, \partial r / \partial \tilde\sigma)\).
- hessian_scalar(univariate, Y)[source]#
Return the \(3 \times 3\) Hessian in \((\tilde\mu, \tilde\gamma, \tilde\sigma)\).
\(\partial^2/\partial \tilde\mu \, \cdot = 0\) exactly; the other non-trivial blocks follow
docs/theory/cvar_derivatives.md(4).
- value_w(model, w, Y)[source]#
- Parameters:
model (NormalMixture)
w (Array)
Y (Array)
- Return type:
- gradient_w(model, w, Y)[source]#
Gradient \(\nabla_w r_{\operatorname{CVaR}_\alpha}(w)\).
- Parameters:
model (NormalMixture)
w (Array)
Y (Array)
- Return type:
- hessian_w(model, w, Y)[source]#
Hessian \(H_{r_{\operatorname{CVaR}_\alpha}}(w)\).
- Parameters:
model (NormalMixture)
w (Array)
Y (Array)
- Return type:
- value_grad_hess_w(model, w, Y)[source]#
Fused \((r, \nabla_w r, H_r)\) with one CMC VaR solve.
Equivalent to calling
value_w(),gradient_w(), andhessian_w()separately, but projects once and bisects the conditional-MC CDF once.
Mean-Risk Optimization#
Mean-risk portfolio optimization for normal-mixture models.
For a multivariate normal mixture \(X \stackrel{d}{=} \mu + \gamma Y + \sqrt{Y} Z\) with \(Z \sim \mathcal{N}(0, \Sigma)\), the mean-risk problem
reduces — for any coherent risk measure \(\rho\) — to a two-dimensional problem in the reduced coordinates \(\tilde\mu = w^\top\mu\) and \(\tilde\gamma = w^\top\gamma\). The minimum-dispersion weights that realise a given \((\tilde\mu, \tilde\gamma)\) are
and the realised dispersion is \(g(\tilde\mu, \tilde\gamma) = [\tilde\mu\;\tilde\gamma\;1] A^{-1} [\tilde\mu\;\tilde\gamma\;1]^\top\). The map \((\tilde\mu, \tilde\gamma) \mapsto \rho\) is the efficient surface; its lower envelope under the return constraint is the efficient frontier.
See Mean-Risk Optimization for Normal Mixture Distributions for the derivation.
- class normix.finance.optimization.EfficientSurface(mu_tilde, gamma_tilde, risk, expected_return)[source]#
Bases:
ModuleEfficient surface \((\tilde\mu, \tilde\gamma) \mapsto \rho\) on a grid.
risk[i, j]is the risk of the minimum-dispersion portfolio with reduced coordinates(mu_tilde[i], gamma_tilde[j]);expected_return[i, j] = mu_tilde[i] + gamma_tilde[j] * E[Y].
- class normix.finance.optimization.EfficientFrontier(expected_return, risk, mu_tilde, gamma_tilde, weights)[source]#
Bases:
ModuleMean-risk efficient frontier: minimum risk per target expected return.
Each entry is the solution of the reduced problem on the constraint line \(\tilde\mu + \tilde\gamma E[Y] = m\), including the realised portfolio
weightsof shape(K, d).- Parameters:
- class normix.finance.optimization.MeanRiskProblem(model, risk)[source]#
Bases:
ModuleMean-risk optimization in reduced \((\tilde\mu, \tilde\gamma)\) coordinates.
Bundles a fitted
NormalMixtureand aRiskMeasure. All heavy evaluations share a fixed subordinator sampleY(common random numbers); draw it once viamodel.joint.subordinator().rvs(n, seed).The Cholesky factors \(A\), \(A^{-1}\), and \(\Sigma^{-1}M\) are computed once at construction (w-independent).
- Parameters:
model (NormalMixture)
risk (RiskMeasure)
- model: NormalMixture#
- risk: RiskMeasure#
- weights(mu_tilde, gamma_tilde)[source]#
Minimum-dispersion weights realising \((\tilde\mu, \tilde\gamma)\).
- dispersion(mu_tilde, gamma_tilde)[source]#
Realised dispersion \(g(\tilde\mu, \tilde\gamma) = w^{*\top}\Sigma w^*\).
- min_variance_point()[source]#
Reduced coordinates \((\tilde\mu, \tilde\gamma)\) of the global minimum-variance portfolio \(w = \Sigma^{-1}e / (e^\top\Sigma^{-1}e)\).
A convenient anchor for choosing efficient-surface grid ranges.
- projection_at(mu_tilde, gamma_tilde)[source]#
Univariate portfolio return at \((\tilde\mu, \tilde\gamma)\).
Projects the minimum-dispersion
weights(); the result is aUnivariate*instance with location \(\tilde\mu\), skewness \(\tilde\gamma\), variance \(g(\tilde\mu, \tilde\gamma)\).
- risk_at(mu_tilde, gamma_tilde, Y)[source]#
Efficient-surface risk at a single \((\tilde\mu, \tilde\gamma)\).
- efficient_surface(mu_tilde, gamma_tilde, Y)[source]#
Evaluate the efficient surface over the grid
mu_tilde × gamma_tilde.mu_tildeandgamma_tildeare 1-D arrays; the returnedriskhas shape(len(mu_tilde), len(gamma_tilde)). Memory scales aslen(mu_tilde) * len(gamma_tilde) * len(Y).- Parameters:
- Return type:
- efficient_frontier(returns, Y, gamma_bounds, n_iter=48)[source]#
Minimum risk for each target expected return in
returns.For every target \(m\), minimises the risk along the constraint line \(\tilde\mu = m - \tilde\gamma E[Y]\) over \(\tilde\gamma \in\)
gamma_boundsby golden-section search (the surface is convex, so the restriction is unimodal).
Transaction Costs#
Local-quadratic transaction-cost portfolio rebalancing.
The mean-risk problem with an \(\ell_1\) turnover penalty
cannot use the two-dimensional efficient-surface reduction, because the turnover term breaks translation invariance in the reduced coordinates. When costs keep the solution near the current portfolio \(w_0\), a second-order Taylor expansion of the convex risk \(r\) yields a convex quadratic program in buy/sell variables \(v = (v^+; v^-)\) with \(w = w_0 + v^+ - v^-\) (see Portfolio Optimization with Transaction Costs).
This module builds the QP matrices from any RiskMeasure
that supplies gradient_w() /
hessian_w(). Solving is optional and uses
scipy.optimize (already a core dependency); heavier QP backends can
consume the same matrices later.
- class normix.finance.transaction_costs.QuadraticApproximation(w0, value, gradient, hessian)[source]#
Bases:
ModuleLocal Taylor model of \(r\) at the current portfolio \(w_0\).
\[r(w) \approx r(w_0) + (w - w_0)^\top \nabla r(w_0) + \tfrac12 (w - w_0)^\top H_r(w_0)\,(w - w_0).\]
- class normix.finance.transaction_costs.TransactionCostQP(m_tilde, H_tilde, e_tilde, A_tilde, b_tilde, w0, c1, c2, approx, m)[source]#
Bases:
ModuleBuy/sell quadratic program for the local transaction-cost problem.
Maximises \(v^\top \tilde m - (c_1/2)\, v^\top \tilde H\, v\) over \(v \ge 0\) subject to \(v^\top \tilde e = 0\) and optional \(\tilde A v \le \tilde b\). Reconstruct \(w^* = w_0 + (I\;-I)\,v^*\).
- Parameters:
- A_tilde, b_tilde
Optional inequality block;
Nonewhen only the budget constraint is active.
- w0, c1, c2
Anchor portfolio and objective coefficients.
- approx#
Underlying risk Taylor model (for objective bookkeeping).
- approx: QuadraticApproximation#
- class normix.finance.transaction_costs.TransactionCostResult(weights, v, turnover, approx_objective, hold_objective, improved, qp)[source]#
Bases:
ModuleSolution of the local transaction-cost QP.
improvedisTruewhen the approximate objective atweightsexceeds the hold objective; otherwise the theory recommends keeping \(w_0\) (see the note in Portfolio Optimization with Transaction Costs).- Parameters:
- normix.finance.transaction_costs.build_quadratic_approximation(risk, model, w0, Y)[source]#
Evaluate \(r(w_0)\), \(\nabla r(w_0)\), and \(H_r(w_0)\).
Uses
value_grad_hess_w()so the CMC VaR bisection runs once rather than three times.- Parameters:
risk (RiskMeasure)
model (NormalMixture)
w0 (Array)
Y (Array)
- Return type:
- normix.finance.transaction_costs.build_transaction_cost_qp(approx, m, c1, c2, A=None, b=None, hess_reg=1e-06)[source]#
Assemble the buy/sell QP matrices from a risk Taylor model.
- Parameters:
approx (QuadraticApproximation) – Local approximation of \(r\) at \(w_0\).
m (Array) – Expected-return vector (\(E[X]\) for a normal mixture).
A (Array | None) – Optional inequality \(A w \le b\) (same \(w_0\) must be feasible). Pass
Nonefor the budget-only problem.b (Array | None) – Optional inequality \(A w \le b\) (same \(w_0\) must be feasible). Pass
Nonefor the budget-only problem.hess_reg (float) – Tikhonov damping added to \(\tilde H\) so the QP is strictly convex (\(\tilde H\) has a nontrivial nullspace along \(v^+ = v^-\)).
- Return type:
- normix.finance.transaction_costs.solve_transaction_cost_qp(qp, *, x0=None, options=None)[source]#
Solve the local QP with
scipy.optimize.minimize(SLSQP).Minimises \((c_1/2)\, v^\top \tilde H\, v - \tilde m^\top v\) subject to \(v \ge 0\), \(\tilde e^\top v = 0\), and optional \(\tilde A v \le \tilde b\). If the approximate objective does not beat holding \(w_0\), returns the hold portfolio.
- Parameters:
qp (TransactionCostQP)
x0 (Array | None)
- Return type:
- class normix.finance.transaction_costs.TransactionCostProblem(model, risk, c1, c2)[source]#
Bases:
ModuleLocal-quadratic transaction-cost rebalancing for a normal mixture.
Bundles a fitted
NormalMixtureand aRiskMeasurewith coefficients \((c_1, c_2)\). The risk object is reused unchanged — only its weight-space gradient and Hessian at \(w_0\) enter the QP.- Parameters:
model (NormalMixture)
risk (RiskMeasure)
c1 (float)
c2 (float)
- model: NormalMixture#
- risk: RiskMeasure#
- expected_return_vector()[source]#
Asset expected returns \(m = E[X] = \mu + \gamma\, E[Y]\).
- Return type:
- approximate(w0, Y)[source]#
Local Taylor model of risk at
w0under subordinator sampleY.- Parameters:
- Return type:
- build_qp(w0, Y, *, m=None, A=None, b=None, hess_reg=1e-06)[source]#
Build the buy/sell QP at
w0.mdefaults toexpected_return_vector(). OptionalA,bencode \(A w \le b\) (e.g. long-only viaA = -I,b = 0).
- solve(w0, Y, *, m=None, A=None, b=None, hess_reg=1e-06, options=None)[source]#
Build and solve the local QP; see
solve_transaction_cost_qp().
Weight Functional#
Risk measures as JIT-able functions of portfolio weights.
WeightFunctional bundles a RiskMeasure,
a multivariate normal-mixture model, and a fixed subordinator sample Y into
a callable w -> ℝ with gradient and Hessian companions for optimisation.
- class normix.finance.functional.WeightFunctional(risk, model, Y)[source]#
Bases:
ModuleRisk measure as a function of weights, with frozen model and
Y.Bundles a
RiskMeasure, aNormalMixturemodel, and a realisationYof the subordinator into JIT-able callables intended for mean-risk optimisation (Phase E).- Parameters:
risk (RiskMeasure)
model (NormalMixture)
Y (Array)
- risk: RiskMeasure#
- model: NormalMixture#
Diversification#
Diversification analytics: effective number of bets under a torsion.
Variance ENB diagonalizes the return covariance \(\mathrm{Cov}[X] = E[Y]\Sigma + \mathrm{Var}[Y]\,\gamma\gamma^\top\) (Effective Number of Bets and Minimum Torsion); generalized ENB diagonalizes the Hessian of the squared coherent risk \(H_{r^2} = 2\nabla r\,\nabla r^\top + 2 r H_r\) (Generalized Effective Number of Bets). Both reduce to one core: normalize \(d_k v_k^2\) over a torsion \(T H T^\top = \operatorname{diag}(d)\), \(v = (T^\top)^{-1} w\), and exponentiate the entropy.
Minimum torsion is a diagonalization strategy, not a diversification measure.
- class normix.finance.diversification.TorsionDecomposition(T, T_inv_T, d, eigenvalues, valid)[source]#
Bases:
ModuleDiagonalization \(T H T^\top = \operatorname{diag}(d)\) of a PSD matrix.
T_inv_Tis \((T^\top)^{-1}\), the map from portfolio weights \(w\) to torsion-adjusted weights \(v\). Both concrete torsions supply it in closed form (no solve at evaluation time).eigenvaluesis the pre-clamp spectrum used for validity checks.validisFalsewhen a material negative eigenvalue was present.
- class normix.finance.diversification.Torsion[source]#
Bases:
ModuleStrategy: how to diagonalize a PSD matrix into uncorrelated bets.
- class normix.finance.diversification.MinimumTorsion[source]#
Bases:
TorsionConstrained minimum torsion (Meucci 2014): \(T = C^{-1/2}\operatorname{diag}(s)^{-1}\).
Closed form at \(D = I\). The iterative algorithm (unconstrained \(D\)) is deferred; it would land as a sibling
IterativeMinimumTorsionwithout touching callers.
- class normix.finance.diversification.PCATorsion[source]#
Bases:
TorsionPrincipal-components torsion (Meucci 2010): \(T = E^\top\), \(d = \Lambda\).
Rows ordered by descending eigenvalue. Eigenvector sign/order is unstable under near-ties — documented;
MinimumTorsionis the default.
- class normix.finance.diversification.ENBResult(enb, p, risk, v, d, T, eigenvalues)[source]#
Bases:
ModuleEffective number of bets and its decomposition at one portfolio.
pis normalized by \(\sum_k d_k v_k^2\) (a simplex up to floating point).riskis the 1-homogeneous risk whose square was diagonalized: portfolio volatility \(\sqrt{w^\top\Sigma_X w}\) forVarianceENB, \(\rho(w^\top X)\) forGeneralizedENB.enbis NaN when the local matrix is materially indefinite, the portfolio risk is non-positive, or the total contribution vanishes.
- class normix.finance.diversification.VarianceENB(torsion=MinimumTorsion())[source]#
Bases:
ModuleVariance-based effective number of bets (Effective Number of Bets and Minimum Torsion).
Diagonalizes the return covariance
model.cov()\(= E[Y]\Sigma + \mathrm{Var}[Y]\,\gamma\gamma^\top\) — not the dispersion \(\Sigma\). Deterministic: no subordinator sample. Requires a finiteVar[Y](same moment caveat asskewness()).- Parameters:
torsion (Torsion)
- evaluate(model, w)[source]#
ENB of \(w^\top X\) under the fitted model. Y-free by design.
vmap-able over a weight grid:
jax.vmap(enb.evaluate, in_axes=(None, 0)).- Parameters:
model (NormalMixture)
w (Array)
- Return type:
- class normix.finance.diversification.GeneralizedENB(risk, torsion=MinimumTorsion())[source]#
Bases:
ModuleENB of a squared coherent risk measure (Generalized Effective Number of Bets).
For 1-homogeneous \(\rho\), diagonalizes \(H_{r^2}(w) = 2\nabla r\,\nabla r^\top + 2 r H_r\) where \((r, \nabla r, H_r)\) come from one call to
risk.value_grad_hess_w(model, w, Y). Meaningful only for \(r(w) > 0\) (else \(r^2\) is not convex atwandenbis NaN).- Parameters:
risk (RiskMeasure)
torsion (Torsion)
- risk: RiskMeasure#
- evaluate(model, w, Y)[source]#
ENB at
wunder subordinator sampleY(common random numbers).Yis mandatory — draw once viamodel.joint.subordinator().rvs(n, seed)and share across finance evaluations. Not promised vmap-able overw: the fused bundle seeds its CMC bracket from the PINVppf.- Parameters:
model (NormalMixture)
w (Array)
Y (Array)
- Return type: