code wiki / (root) / nx_fin_metrics.nx

nx_fin_metrics.nx source

↩ module page · 47 lines · 2234 B

1// nx_fin_metrics.nx -- risk-adjusted performance metrics, i64 fixed-point, NO floats. Provides the integer 2// sqrt primitive (me_isqrt, Newton's method) the float-free runtime needs, then mean / standard-deviation / 3// SHARPE / downside-deviation / SORTINO over a returns array (per-period returns in basis points). Sharpe and 4// Sortino are returned in MILLI-units (x1000) for integer resolution. Risk-free / MAR passed in (default 0). 5// These are the numbers that grade an edge HONESTLY -- reward per unit of risk, not raw return. Pure; composes 6// with nx_fin_backtest's per-trade/per-period returns. license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_vecmath.nx" 9 10// floor(sqrt(n)) by Newton's method. n<=0 -> 0. 11func me_isqrt(n: i64) -> i64 { return vm_isqrt(n) } 12 13func me_sum(vals: *i64, n: i64) -> i64 { var s: i64 = 0; var i: i64 = 0; while i < n { s = s + vals[i]; i = i + 1 } return s } 14 15// mean of the returns (same units as input, e.g. bps) 16func me_mean(vals: *i64, n: i64) -> i64 { if n <= 0 { return 0 } return me_sum(vals, n) / n } 17 18// population standard deviation (same units as input) 19func me_stddev(vals: *i64, n: i64) -> i64 { 20 if n <= 0 { return 0 } 21 let mean: i64 = me_mean(vals, n) 22 var ss: i64 = 0; var i: i64 = 0 23 while i < n { let d: i64 = vals[i] - mean; ss = ss + d*d; i = i + 1 } 24 return me_isqrt(ss / n) 25} 26 27// Sharpe ratio x1000 = (mean - rf) / stddev. rf in same units as returns. sd==0 -> 0. 28func me_sharpe_milli(vals: *i64, n: i64, rf: i64) -> i64 { 29 let sd: i64 = me_stddev(vals, n) 30 if sd <= 0 { return 0 } 31 return (me_mean(vals, n) - rf) * 1000 / sd 32} 33 34// downside deviation vs a minimum-acceptable-return (mar); only returns below mar contribute; denominator = n. 35func me_downside_dev(vals: *i64, n: i64, mar: i64) -> i64 { 36 if n <= 0 { return 0 } 37 var ss: i64 = 0; var i: i64 = 0 38 while i < n { if vals[i] < mar { let d: i64 = vals[i] - mar; ss = ss + d*d } i = i + 1 } 39 return me_isqrt(ss / n) 40} 41 42// Sortino ratio x1000 = (mean - mar) / downside_dev. dd==0 -> 0. 43func me_sortino_milli(vals: *i64, n: i64, mar: i64) -> i64 { 44 let dd: i64 = me_downside_dev(vals, n, mar) 45 if dd <= 0 { return 0 } 46 return (me_mean(vals, n) - mar) * 1000 / dd 47}