code wiki / (root) / nx_edgar_lib.nx

nx_edgar_lib.nx source

↩ module page · 138 lines · 5487 B

1// nx_edgar_lib.nx -- F986: SEC EDGAR real-data extraction. GROUNDED, NOT MADE UP. 2// 3// The sovereign fetcher reaches data.sec.gov over our own TLS (proven live: Apple StockholdersEquity 4// pulled 200 OK, current through the latest 10-Q). This parses the SEC companyconcept JSON so the 5// valuation engines run on REAL filings instead of hand-entered figures -- the operator's standing rule 6// for the whole finance arc. Every extracted fact carries its PROVENANCE: the form (10-K/10-Q) and the 7// filing date, so a number is always traceable to a specific SEC filing, never a floating assertion. 8// 9// ★FAIL-CLOSED + COMPOSES the pipeline: the no-value sentinel EDGAR_NOVAL is the SAME value nx_xbrl and 10// nx_piotroski use for a missing fact (-999999999). So an unparseable or empty response flows through as 11// "missing" -- the F-score reads INCOMPLETE, the identity check refuses -- rather than silently becoming a 12// zero that would corrupt a valuation. Fetch failure never turns into a fabricated financial fact. 13// 14// SCOPE (declared): extracts the LATEST fact value + its provenance and the entity name from the 15// companyconcept JSON. Full submissions parsing, all periods, and unit handling beyond USD are follow-ons. 16// Strings/keys are built at runtime (NishiLang literals cannot hold a double-quote). license_tier: ORIGINAL LIB. 17 18import "nx_matter_lib.nx" 19 20const EDGAR_NOVAL: i64 = 0 - 999999999 // no value found (matches nx_xbrl XB_NO_FACT / nx_piotroski PIO_NA) 21const EDGAR_Q: i64 = 34 // double-quote 22const EDGAR_COLON: i64 = 58 23 24func edgar_read(path: *u8, buf: *u8, cap: i64) -> i64 { 25 let fd: i64 = sys_openat_rd(path) 26 if fd < 0 { return 0 - 1 } 27 var n: i64 = 0 28 var go: i64 = 1 29 while go == 1 { 30 let base: i64 = buf as i64 31 let r: i64 = sys_read(fd, (base + n) as *u8, cap - n) 32 if r <= 0 { go = 0 } else { n = n + r } 33 if n >= cap { go = 0 } 34 } 35 sys_close(fd) 36 return n 37} 38 39// build the JSON key-needle "<key>": at runtime (quotes cannot be string literals). returns len. 40func edgar_mkkey(key: *u8, out: *u8) -> i64 { 41 out[0] = EDGAR_Q as u8 42 var o: i64 = 1 43 var i: i64 = 0 44 while key[i] != (0 as u8) { out[o] = key[i]; o = o + 1; i = i + 1 } 45 out[o] = EDGAR_Q as u8 46 o = o + 1 47 out[o] = EDGAR_COLON as u8 48 o = o + 1 49 out[o] = 0 as u8 50 return o 51} 52 53// index of the LAST occurrence of needle in hay[0..hl), or -1. 54func edgar_find_last(hay: *u8, hl: i64, needle: *u8, nl: i64) -> i64 { 55 var last: i64 = 0 - 1 56 var i: i64 = 0 57 while i + nl <= hl { 58 var j: i64 = 0 59 while j < nl { 60 if hay[i + j] == needle[j] { j = j + 1 } else { j = nl + 1 } 61 } 62 if j == nl { last = i } 63 i = i + 1 64 } 65 return last 66} 67 68// index of the FIRST occurrence of needle in hay[0..hl), or -1. 69func edgar_find_first(hay: *u8, hl: i64, needle: *u8, nl: i64) -> i64 { 70 var i: i64 = 0 71 while i + nl <= hl { 72 var j: i64 = 0 73 while j < nl { 74 if hay[i + j] == needle[j] { j = j + 1 } else { j = nl + 1 } 75 } 76 if j == nl { return i } 77 i = i + 1 78 } 79 return 0 - 1 80} 81 82// integer value after the LAST "<key>": in the JSON. EDGAR_NOVAL if the key is absent or not numeric. 83func edgar_num_last(json: *u8, jl: i64, key: *u8) -> i64 { 84 let nk: *u8 = sys_mmap(128) 85 let nl: i64 = edgar_mkkey(key, nk) 86 let p: i64 = edgar_find_last(json, jl, nk, nl) 87 if p < 0 { return EDGAR_NOVAL } 88 var i: i64 = p + nl 89 var neg: i64 = 0 90 if i < jl { if json[i] == (45 as u8) { neg = 1; i = i + 1 } } 91 var v: i64 = 0 92 var any: i64 = 0 93 var go: i64 = 1 94 while go == 1 { 95 if i >= jl { go = 0 } else { 96 let c: i64 = json[i] as i64 97 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); any = 1; i = i + 1 } else { go = 0 } } else { go = 0 } 98 } 99 } 100 if any == 0 { return EDGAR_NOVAL } 101 if neg == 1 { return 0 - v } 102 return v 103} 104 105// string value after a "<key>":" ; helper takes the located index p (or -1). returns len or -1. 106func edgar_str_at(json: *u8, jl: i64, p: i64, nl: i64, out: *u8) -> i64 { 107 if p < 0 { return 0 - 1 } 108 var i: i64 = p + nl 109 if i >= jl { return 0 - 1 } 110 if json[i] != (EDGAR_Q as u8) { return 0 - 1 } 111 i = i + 1 112 var t: i64 = 0 113 var go: i64 = 1 114 while go == 1 { 115 if i >= jl { go = 0 } else { 116 if json[i] == (EDGAR_Q as u8) { go = 0 } else { out[t] = json[i]; t = t + 1; i = i + 1 } 117 } 118 } 119 out[t] = 0 as u8 120 return t 121} 122 123func edgar_str_last(json: *u8, jl: i64, key: *u8, out: *u8) -> i64 { 124 let nk: *u8 = sys_mmap(128) 125 let nl: i64 = edgar_mkkey(key, nk) 126 return edgar_str_at(json, jl, edgar_find_last(json, jl, nk, nl), nl, out) 127} 128func edgar_str_first(json: *u8, jl: i64, key: *u8, out: *u8) -> i64 { 129 let nk: *u8 = sys_mmap(128) 130 let nl: i64 = edgar_mkkey(key, nk) 131 return edgar_str_at(json, jl, edgar_find_first(json, jl, nk, nl), nl, out) 132} 133 134// ★convenience accessors over a companyconcept JSON. 135func edgar_latest_value(json: *u8, jl: i64) -> i64 { return edgar_num_last(json, jl, "val" as *u8) } 136func edgar_entity(json: *u8, jl: i64, out: *u8) -> i64 { return edgar_str_first(json, jl, "entityName" as *u8, out) } 137func edgar_latest_form(json: *u8, jl: i64, out: *u8) -> i64 { return edgar_str_last(json, jl, "form" as *u8, out) } 138func edgar_latest_filed(json: *u8, jl: i64, out: *u8) -> i64 { return edgar_str_last(json, jl, "filed" as *u8, out) }