nx_fin_zscore.nx source
↩ module page · 41 lines · 2416 B
1// nx_fin_zscore.nx -- R-MKT1 of the MARKETS-INVESTING finance arc: the ALTMAN Z-SCORE, a distress/bankruptcy
2// predictor that answers "is this company financially healthy or in trouble?" from its balance sheet + income
3// statement (the numbers you pull from an EDGAR 10-K). Grounded in the Nishi researcher's fetched source
4// knowledge/fetched/fin_val_altman.raw (Altman 1968, public manufacturers):
5// Z = 1.2*X1 + 1.4*X2 + 3.3*X3 + 0.6*X4 + 1.0*X5
6// X1 = working capital / total assets (short-term liquidity)
7// X2 = retained earnings / total assets (cumulative profitability / age)
8// X3 = EBIT / total assets (operating productivity)
9// X4 = market value of equity / total liabs (solvency cushion)
10// X5 = sales / total assets (asset turnover)
11// Zones: Z > 2.99 SAFE | 1.81..2.99 GREY | Z < 1.81 DISTRESS.
12// NO FLOATS: ratios are scaled x1000 (Xi_s = num*1000/den), coefficients x10 (12/14/33/6/10), the final
13// /10 returns Z scaled x1000 -- exact integer arithmetic, the only correct way to do money. Thresholds are
14// DATA (#11). Pure function, no store, no hardware writes -- safe to run in any request path. license_tier: ORIGINAL
15import "nx_syscalls.nx"
16const AZ_MAGIC_2990: i64 = 2990
17const AZ_MAGIC_1810: i64 = 1810
18
19const AZ_DISTRESS: i64 = 0
20const AZ_GREY: i64 = 1
21const AZ_SAFE: i64 = 2
22
23// Altman Z-score x1000 from raw figures (consistent monetary units -- $thousands, $, or cents, any, as long as
24// all seven are the same unit). Returns Z*1000. total_assets==0 -> 0 (no data -> treated as distress by az_zone).
25func az_zscore(working_capital: i64, retained_earnings: i64, ebit: i64, mv_equity: i64, total_liabilities: i64, sales: i64, total_assets: i64) -> i64 {
26 if total_assets == 0 { return 0 }
27 let x1: i64 = working_capital * 1000 / total_assets
28 let x2: i64 = retained_earnings * 1000 / total_assets
29 let x3: i64 = ebit * 1000 / total_assets
30 var x4: i64 = 0
31 if total_liabilities != 0 { x4 = mv_equity * 1000 / total_liabilities }
32 let x5: i64 = sales * 1000 / total_assets
33 return (12 * x1 + 14 * x2 + 33 * x3 + 6 * x4 + 10 * x5) / 10
34}
35
36// classify a x1000 Z-score into a zone. Thresholds = DATA (2.99 / 1.81, scaled x1000).
37func az_zone(z1000: i64) -> i64 {
38 if z1000 > AZ_MAGIC_2990 { return AZ_SAFE }
39 if z1000 >= AZ_MAGIC_1810 { return AZ_GREY }
40 return AZ_DISTRESS
41}