code wiki / (root) / nx_fin_optimizer.nx

nx_fin_optimizer.nx source

↩ module page · 60 lines · 2762 B

1// nx_fin_optimizer.nx -- portfolio OPTIMIZATION, analytic (no matrix inverse needed): the closed-form 2// mean-variance solutions. (1) inverse-variance weighting (risk-parity's simple cousin): w_i ~ 1/var_i; 3// (2) diagonal max-Sharpe / tangency for uncorrelated assets: w_i ~ max(0,mu_i)/var_i (long-only); (3) 2-asset 4// min-variance WITH correlation, closed form; (4) portfolio variance of ANY weight vector given the full 5// covariance (the objective to evaluate/compare allocations). Weights in bps (sum ~10000). i64 fixed-point. 6// The full N-asset correlated convex QP (cvxpy/PyPortfolioOpt) is the refinement still ahead. license_tier: ORIGINAL 7import "nx_syscalls.nx" 8const K_MAGIC_1000000000: i64 = 1000000000 9const K_MAGIC_10000: i64 = 10000 10const K_MAGIC_1000000: i64 = 1000000 11const K_MAGIC_5000: i64 = 5000 12const K_MAGIC_100000000: i64 = 100000000 13 14// inverse-variance weights (bps, sum ~10000): lower variance -> higher weight. 15func op_inv_var_weight(varr: *i64, n: i64, wout: *i64) -> i64 { 16 let inv: *i64 = sys_mmap(8*n) as *i64 17 var tot: i64 = 0; var i: i64 = 0 18 while i < n { var v: i64 = varr[i]; if v <= 0 { v = 1 } inv[i] = K_MAGIC_1000000000 / v; tot = tot + inv[i]; i = i + 1 } 19 if tot <= 0 { return 0 } 20 i = 0; while i < n { wout[i] = inv[i] * K_MAGIC_10000 / tot; i = i + 1 } 21 return n 22} 23 24// diagonal max-Sharpe (tangency for uncorrelated assets), long-only: w_i ~ max(0,mu_i)/var_i. 25func op_max_sharpe_diag(mu: *i64, varr: *i64, n: i64, wout: *i64) -> i64 { 26 let sc: *i64 = sys_mmap(8*n) as *i64 27 var tot: i64 = 0; var i: i64 = 0 28 while i < n { 29 var m: i64 = mu[i]; if m < 0 { m = 0 } 30 var v: i64 = varr[i]; if v <= 0 { v = 1 } 31 sc[i] = m * K_MAGIC_1000000 / v 32 tot = tot + sc[i]; i = i + 1 33 } 34 if tot <= 0 { return 0 } 35 i = 0; while i < n { wout[i] = sc[i] * K_MAGIC_10000 / tot; i = i + 1 } 36 return n 37} 38 39// 2-asset MIN-VARIANCE weight of asset 1 (bps), closed form with covariance: 40// w1 = (var2 - cov) / (var1 + var2 - 2*cov), clamped to [0,10000]. 41func op_minvar_2asset(v1: i64, v2: i64, cov: i64) -> i64 { 42 let denom: i64 = v1 + v2 - 2*cov 43 if denom == 0 { return K_MAGIC_5000 } 44 var w1: i64 = (v2 - cov) * K_MAGIC_10000 / denom 45 if w1 < 0 { w1 = 0 } 46 if w1 > K_MAGIC_10000 { w1 = K_MAGIC_10000 } 47 return w1 48} 49 50// portfolio variance for a weight vector (bps) given the full n x n covariance (flat cov[i*n+j]): 51// var_p = sum_i sum_j w_i w_j cov_ij (w in bps -> divide by 10000^2). 52func op_port_variance(w: *i64, cov: *i64, n: i64) -> i64 { 53 var s: i64 = 0; var i: i64 = 0 54 while i < n { 55 var j: i64 = 0 56 while j < n { s = s + w[i]*w[j]*cov[i*n+j]; j = j + 1 } 57 i = i + 1 58 } 59 return s / K_MAGIC_100000000 60}