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}