code wiki / (root) / nx_beneish_lib.nx

nx_beneish_lib.nx source

↩ module page · 56 lines · 3183 B

1// nx_beneish_lib.nx -- BENEISH M-SCORE: forensic detection of earnings manipulation, integer-exact. 2// 3// The fourth lens on a company, and the darkest one: Altman asks if it is in distress, Piotroski if it 4// is strengthening, mgmt-grade if the stewards are good -- Beneish asks if the numbers are being COOKED. 5// It is the standard forensic-accounting model (Beneish 1999); students using it flagged Enron a year 6// before it collapsed. Eight indices comparing this year to last across receivables, margins, asset 7// quality, sales growth, depreciation, SG&A, accruals, and leverage combine into one M-score; above the 8// -1.78 threshold the profile matches known manipulators. 9// 10// M = -4.84 + 0.920*DSRI + 0.528*GMI + 0.404*AQI + 0.892*SGI + 0.115*DEPI - 0.172*SGAI + 4.679*TATA - 0.327*LVGI 11// 12// NO FLOATS: each index is scaled x1000 (a ratio of 1.000 -> 1000, i.e. basis points), coefficients are 13// scaled x1000, the accumulation is x1e6, and the result is returned as M x1000 -- exact integer 14// arithmetic, the only reproducible way to score fraud. Threshold is DATA. 15// 16// ★FAIL-CLOSED + COMPOSES: the missing-input sentinel BEN_NA is the pipeline value (-999999999). If any 17// index could not be computed from the filings, ben_mscore returns BEN_INCOMPLETE rather than a fraud 18// verdict on partial data -- accusing a company of cooking books on missing facts is the worst false signal. 19// license_tier: ORIGINAL No hw writes (Rule 26). LIB. 20 21import "nx_matter_lib.nx" 22const BEN_MAGIC_4840000: i64 = 4840000 23const BEN_MAGIC_4679: i64 = 4679 24 25const BEN_NA: i64 = 0 - 999999999 // a required index is missing (matches the pipeline sentinel) 26const BEN_INCOMPLETE: i64 = 0 - 2000000000 // M not computable (well outside the real M x1000 range) 27const BEN_THRESHOLD: i64 = 0 - 1780 // M x1000; ABOVE this the profile matches manipulators 28 29// M-score x1000 from the eight indices, each scaled x1000 (1.000 ratio -> 1000). 30func ben_mscore(dsri: i64, gmi: i64, aqi: i64, sgi: i64, depi: i64, sgai: i64, tata: i64, lvgi: i64) -> i64 { 31 if dsri == BEN_NA { return BEN_INCOMPLETE } 32 if gmi == BEN_NA { return BEN_INCOMPLETE } 33 if aqi == BEN_NA { return BEN_INCOMPLETE } 34 if sgi == BEN_NA { return BEN_INCOMPLETE } 35 if depi == BEN_NA { return BEN_INCOMPLETE } 36 if sgai == BEN_NA { return BEN_INCOMPLETE } 37 if tata == BEN_NA { return BEN_INCOMPLETE } 38 if lvgi == BEN_NA { return BEN_INCOMPLETE } 39 // coefficients x1000; index x1000; product x1e6; constant -4.84 x1e6 = -4840000 40 let raw: i64 = 0 - BEN_MAGIC_4840000 + 920 * dsri + 528 * gmi + 404 * aqi + 892 * sgi + 115 * depi - 172 * sgai + BEN_MAGIC_4679 * tata - 327 * lvgi 41 return raw / 1000 42} 43 44// 1 if the M-score is above the manipulation threshold. INCOMPLETE is NOT a manipulator flag (returns 0). 45func ben_is_manipulator(m1000: i64) -> i64 { 46 if m1000 == BEN_INCOMPLETE { return 0 } 47 if m1000 > BEN_THRESHOLD { return 1 } 48 return 0 49} 50 51// human verdict. 52func ben_verdict_str(m1000: i64) -> *u8 { 53 if m1000 == BEN_INCOMPLETE { return "INCOMPLETE" as *u8 } 54 if m1000 > BEN_THRESHOLD { return "MANIPULATION-RISK" as *u8 } 55 return "LIKELY-CLEAN" as *u8 56}