code wiki / (root) / nx_piotroski_gate.nx

nx_piotroski_gate.nx source

↩ module page · 111 lines · 5921 B

1// nx_piotroski_gate.nx -- F-SCORE INDEPENDENT GATE. 2// Proves the exact 9-point score on a strong / weak / mixed firm, the grade mapping, and the fail-closed 3// composition with nx_xbrl: a firm with any missing (XB_NO_FACT) metric scores INCOMPLETE, not a number. 4// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 5 6import "nx_piotroski_lib.nx" 7 8func pg_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 9func pg_putn(v: i64) -> i64 { 10 let t: *u8 = sys_mmap(32) 11 var o: i64 = 0 12 var m: i64 = v 13 if m < 0 { t[o] = 45 as u8; o = o + 1; m = 0 - m } 14 let d: *u8 = sys_mmap(32) 15 var k: i64 = 0 16 if m == 0 { d[0] = 48 as u8; k = 1 } 17 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 18 var i: i64 = 0 19 while i < k { t[o] = d[k - 1 - i]; o = o + 1; i = i + 1 } 20 sys_write(1, t, o) 21 return 0 22} 23func pg_ck(cnt: *i64, name: *u8, got: i64, want: i64) -> i64 { 24 if got == want { 25 cnt[0] = cnt[0] + 1 26 pg_puts(" PASS " as *u8); pg_puts(name); pg_puts(" = " as *u8); pg_putn(got); pg_puts("\n" as *u8) 27 return 1 28 } 29 cnt[1] = cnt[1] + 1 30 pg_puts(" FAIL " as *u8); pg_puts(name); pg_puts(" got " as *u8); pg_putn(got) 31 pg_puts(" want " as *u8); pg_putn(want); pg_puts("\n" as *u8) 32 return 0 33} 34func pg_ckstr(cnt: *i64, name: *u8, got: *u8, want: *u8) -> i64 { 35 if mt_streq(got, want) == 1 { 36 cnt[0] = cnt[0] + 1 37 pg_puts(" PASS " as *u8); pg_puts(name); pg_puts(" = " as *u8); pg_puts(got); pg_puts("\n" as *u8) 38 return 1 39 } 40 cnt[1] = cnt[1] + 1 41 pg_puts(" FAIL " as *u8); pg_puts(name); pg_puts(" got " as *u8); pg_puts(got); pg_puts("\n" as *u8) 42 return 0 43} 44 45// fill a metrics array. order = the declared contract. 46func pg_fill(m: *i64, ni: i64, roa: i64, roap: i64, cfo: i64, ltd: i64, ltdp: i64, cur: i64, curp: i64, sh: i64, shp: i64, gm: i64, gmp: i64, at: i64, atp: i64) -> i64 { 47 m[0] = ni; m[1] = roa; m[2] = roap; m[3] = cfo; m[4] = ltd; m[5] = ltdp; m[6] = cur 48 m[7] = curp; m[8] = sh; m[9] = shp; m[10] = gm; m[11] = gmp; m[12] = at; m[13] = atp 49 return 0 50} 51 52func main(argc: i64, argv: *i64) -> i64 { 53 let cnt: *i64 = sys_mmap(16) as *i64 54 cnt[0] = 0 55 cnt[1] = 0 56 57 pg_puts("NISHI-PIOTROSKI-GATE (F-score 0..9 fundamental strength, integer-exact, fail-closed on missing facts)\n" as *u8) 58 59 let m: *i64 = sys_mmap(8 * PIO_N) as *i64 60 61 // ---- P1: a STRONG firm passing all 9 tests -> 9 ---- 62 // ROA 800bp>0, improving from 600; CFO 1200>0 and > NI 1000; LTD 2000<2500; current 15000>14000; 63 // shares 500<=500; gross margin 4200>4000; asset turnover 9000>8500. 64 pg_fill(m, 1000, 800, 600, 1200, 2000, 2500, 15000, 14000, 500, 500, 4200, 4000, 9000, 8500) 65 pg_ck(cnt, "P1 all-9-pass firm -> F-score 9" as *u8, pio_fscore(m), 9) 66 pg_ckstr(cnt, "P1a grade = STRONG" as *u8, pio_grade(pio_fscore(m)), "STRONG" as *u8) 67 68 // ---- P2: a WEAK firm failing all 9 -> 0 ---- 69 // ROA -300<0, worsening from 100; CFO -200<0 and < NI -100; LTD 3000>2500; current 13000<14000; 70 // shares 600>500 (dilution); gross margin 3800<4000; asset turnover 8000<8500. 71 pg_fill(m, 0 - 100, 0 - 300, 100, 0 - 200, 3000, 2500, 13000, 14000, 600, 500, 3800, 4000, 8000, 8500) 72 pg_ck(cnt, "P2 all-9-fail firm -> F-score 0" as *u8, pio_fscore(m), 0) 73 pg_ckstr(cnt, "P2a grade = WEAK" as *u8, pio_grade(pio_fscore(m)), "WEAK" as *u8) 74 75 // ---- P3: a MIXED firm -- exactly the 4 profitability tests pass, the other 5 fail -> 4 ---- 76 // ROA 500>0, improving from 400, CFO 900>0 and > NI 800 (T1-4 pass); LTD 3000>2500 (T5 fail), 77 // current 13000<14000 (T6 fail), shares 600>500 (T7 fail), gm 3800<4000 (T8 fail), at 8000<8500 (T9 fail). 78 pg_fill(m, 800, 500, 400, 900, 3000, 2500, 13000, 14000, 600, 500, 3800, 4000, 8000, 8500) 79 pg_ck(cnt, "P3 mixed firm (4 profitability pass, 5 fail) -> F-score 4" as *u8, pio_fscore(m), 4) 80 pg_ckstr(cnt, "P3a grade = MODERATE" as *u8, pio_grade(pio_fscore(m)), "MODERATE" as *u8) 81 82 // ---- P4: individual-test isolation -- flip ONLY the dilution test (T7) on the strong firm -> 8 ---- 83 pg_fill(m, 1000, 800, 600, 1200, 2000, 2500, 15000, 14000, 700, 500, 4200, 4000, 9000, 8500) 84 pg_ck(cnt, "P4 strong firm but with dilution (shares 700>500) -> 8" as *u8, pio_fscore(m), 8) 85 86 // ---- P5: T4 accruals -- CFO must EXCEED net income; equal CFO==NI fails T4 -> 8 ---- 87 pg_fill(m, 1200, 800, 600, 1200, 2000, 2500, 15000, 14000, 500, 500, 4200, 4000, 9000, 8500) 88 pg_ck(cnt, "P5 CFO == NI (not >) fails the accruals test -> 8" as *u8, pio_fscore(m), 8) 89 90 // ---- P6: FAIL-CLOSED -- a missing fact (PIO_NA, == nx_xbrl XB_NO_FACT) -> INCOMPLETE, not a number ---- 91 pg_fill(m, 1000, 800, 600, 1200, 2000, 2500, 15000, 14000, 500, 500, 4200, 4000, 9000, 8500) 92 m[6] = PIO_NA // current ratio could not be parsed from the filing 93 pg_ck(cnt, "P6 a missing metric -> PIO_INCOMPLETE (-1), not a fabricated score" as *u8, pio_fscore(m), PIO_INCOMPLETE) 94 pg_ckstr(cnt, "P6a grade = INCOMPLETE (surfaced, not silently WEAK)" as *u8, pio_grade(pio_fscore(m)), "INCOMPLETE" as *u8) 95 pg_ck(cnt, "P6b pio_complete = 0 on missing data" as *u8, pio_complete(m), 0) 96 97 // ---- P7: complete data reports complete ---- 98 pg_fill(m, 1000, 800, 600, 1200, 2000, 2500, 15000, 14000, 500, 500, 4200, 4000, 9000, 8500) 99 pg_ck(cnt, "P7 full data -> pio_complete = 1" as *u8, pio_complete(m), 1) 100 101 pg_puts("nx_piotroski_gate: pass=" as *u8); pg_putn(cnt[0]) 102 pg_puts(" fail=" as *u8); pg_putn(cnt[1]); pg_puts("\n" as *u8) 103 if cnt[1] == 0 { 104 pg_puts("F-SCORE nx_piotroski: VERDICT=GREEN (exact 9-point score; INCOMPLETE on a missing fact, never a fabricated number)\n" as *u8) 105 sys_exit(0) 106 return 0 107 } 108 pg_puts("F-SCORE nx_piotroski: VERDICT=RED\n" as *u8) 109 sys_exit(1) 110 return 1 111}