code wiki / (root) / nx_fin_marketdata_fetch.nx

nx_fin_marketdata_fetch.nx source

↩ module page · 172 lines · 9008 B

1// nx_fin_marketdata_fetch.nx -- MAKE IT REAL: the live ingestion adapter + end-to-end demo. Fetches a symbol's 2// daily OHLCV from Alpha Vantage (CSV) over the SOVEREIGN TLS fetcher (no curl), parses via md_parse_csv, 3// reverses to chronological order (Alpha Vantage returns newest-first), then runs the ENTIRE pipeline on REAL 4// data: ADV/capacity (R1) -> SMA signals (R3) -> backtest with slippage + ADV cap (R2) -> honest metrics. This 5// proves the whole stack on real market data -- SIM ONLY, no live capital. The API key is DATA (Cardinal 11/17: 6// env/config > default "demo"); the demo key serves IBM. Composes the proven fetch + the fin_* organs. 7// license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_x509_trust_store.nx" 10import "nx_trust_store_load_from_certdata.nx" 11import "nx_https_fetch_follow.nx" 12import "nx_fin_marketdata.nx" 13import "nx_fin_strategy.nx" 14import "nx_fin_backtest.nx" 15import "nx_fin_paper.nx" 16const K_MAGIC_10000: i64 = 10000 17const K_MAGIC_4194304: i64 = 4194304 18const K_MAGIC_4096: i64 = 4096 19const K_MAGIC_8388608: i64 = 8388608 20const K_MAGIC_1000000: i64 = 1000000 21const K_MAGIC_7000: i64 = 7000 22 23func pp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 24func pn(v: i64) -> i64 { 25 if v==0 { sys_write(1,"0" as *u8,1); return 0 } 26 var m: i64=v; if m<0 { sys_write(1,"-" as *u8,1); m=0-m } 27 let d: *u8=sys_mmap(24); var k: i64=0 28 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 29 var i: i64=k-1; while i>=0 { let o: *u8=sys_mmap(1); o[0]=d[i]; sys_write(1,o,1); i=i-1 } 30 return 0 31} 32func mf_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ dst[off+i]=s[i]; i=i+1 } return off+i } 33 34// reverse bars in place (newest-first -> chronological, so the backtester walks time forward). 35func mf_reverse(bars: *i64, n: i64) -> i64 { 36 var i: i64=0 37 while i < n/2 { 38 let j: i64 = n-1-i 39 var f: i64 = 0 40 while f < MD_FIELDS { 41 let t: i64 = bars[i*MD_FIELDS+f] 42 bars[i*MD_FIELDS+f] = bars[j*MD_FIELDS+f] 43 bars[j*MD_FIELDS+f] = t 44 f = f + 1 45 } 46 i = i + 1 47 } 48 return 0 49} 50 51// print one strategy's tournament row + an honest EDGE flag (needs profit factor > 1.0x AND positive expectancy). 52func tour_print(name: *u8, out: *i64) -> i64 { 53 pp(" " as *u8); pp(name) 54 pp(": trades=" as *u8); pn(out[BT_TRADES]) 55 pp(" ret_bps=" as *u8); pn(out[BT_RET]) 56 pp(" PF_bps=" as *u8); pn(out[BT_PF]) 57 pp(" maxDD_bps=" as *u8); pn(out[BT_MAXDD]) 58 var edge: i64 = 0 59 if out[BT_PF] > K_MAGIC_10000 { if out[BT_EXPECTANCY] > 0 { edge = 1 } } 60 if edge == 1 { pp(" <-- EDGE\n" as *u8) } else { pp(" (no edge)\n" as *u8) } 61 return 0 62} 63 64func mf_strlen(s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){i=i+1} return i } 65 66// read the value after "<key>" (e.g. "symbol=") from a config buffer, up to newline/EOF, into out. Returns len. 67func cfg_get(buf: *u8, n: i64, key: *u8, out: *u8, out_cap: i64) -> i64 { 68 let klen: i64 = mf_strlen(key) 69 var i: i64 = 0 70 while i <= n - klen { 71 var hit: i64 = 1; var j: i64 = 0 72 while j < klen { if (buf[i+j] as i64) != (key[j] as i64) { hit = 0; j = klen } else { j = j + 1 } } 73 if hit == 1 { 74 var p: i64 = i + klen; var k: i64 = 0; var stop: i64 = 0 75 while stop == 0 { 76 if p >= n { stop = 1 } else { 77 let c: i64 = buf[p] as i64 78 if c == 10 { stop = 1 } else { if c == 13 { stop = 1 } else { 79 if k < out_cap - 1 { out[k] = buf[p]; k = k + 1 } 80 p = p + 1 81 } } 82 } 83 } 84 out[k] = 0 as u8 85 return k 86 } 87 i = i + 1 88 } 89 out[0] = 0 as u8 90 return 0 91} 92 93func main() -> i64 { 94 let r: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, 512, K_MAGIC_4194304) 95 if r <= 0 { pp("certdata load failed\n" as *u8); return 1 } 96 let store: *TrustStore = r as *TrustStore 97 98 // -- config (Cardinal 17): key + symbol from knowledge/finance/fin_data.conf, else demo/IBM defaults -- 99 let keybuf: *u8 = sys_mmap(128); let symbuf: *u8 = sys_mmap(64) 100 mf_cat(keybuf, 0, "demo" as *u8); keybuf[4] = 0 as u8 101 mf_cat(symbuf, 0, "IBM" as *u8); symbuf[3] = 0 as u8 102 let cfd: i64 = sys_openat_rd("knowledge/finance/fin_data.conf" as *u8) 103 if cfd >= 0 { 104 let cbuf: *u8 = sys_mmap(K_MAGIC_4096) 105 let cn: i64 = sys_read(cfd, cbuf, K_MAGIC_4096) 106 sys_close(cfd) 107 if cn > 0 { 108 cfg_get(cbuf, cn, "alphavantage_key=" as *u8, keybuf, 128) 109 cfg_get(cbuf, cn, "symbol=" as *u8, symbuf, 64) 110 if mf_strlen(keybuf) <= 0 { mf_cat(keybuf, 0, "demo" as *u8); keybuf[4] = 0 as u8 } 111 if mf_strlen(symbuf) <= 0 { mf_cat(symbuf, 0, "IBM" as *u8); symbuf[3] = 0 as u8 } 112 } 113 } 114 pp("config: symbol=" as *u8); pp(symbuf); pp(" key=" as *u8); pp(keybuf); pp("\n" as *u8) 115 let url: *u8 = sys_mmap(512); var o: i64 = 0 116 o = mf_cat(url, o, "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=" as *u8) 117 o = mf_cat(url, o, symbuf) 118 o = mf_cat(url, o, "&apikey=" as *u8) 119 o = mf_cat(url, o, keybuf) 120 o = mf_cat(url, o, "&datatype=csv" as *u8) 121 url[o] = 0 as u8 122 123 let cap: i64 = K_MAGIC_8388608 124 let scratch: *u8 = sys_mmap(cap) 125 let status: *i64 = sys_mmap(8) as *i64 126 let n: i64 = nx_https_fetch_follow(url, store, scratch, cap, 6, status) 127 pp("fetch IBM: status=" as *u8); pn(status[0]); pp(" bytes=" as *u8); pn(n); pp("\n" as *u8) 128 if n <= 0 { pp("FETCH-FAIL (rate-limit? re-run; demo key = 25/day)\n" as *u8); return 1 } 129 130 let bars: *i64 = sys_mmap(8 * MD_FIELDS * 600) as *i64 131 let nbars: i64 = md_parse_csv(scratch, n, bars, 600) 132 if nbars <= 0 { pp("0 bars parsed (rate-limit JSON note? re-run)\n" as *u8); return 1 } 133 mf_reverse(bars, nbars) 134 pp("REAL bars parsed=" as *u8); pn(nbars); pp(" (chronological)\n" as *u8) 135 let last: i64 = nbars - 1 136 pp("latest bar: date=" as *u8); pn(bars[last*MD_FIELDS+0]); pp(" close_cents=" as *u8); pn(bars[last*MD_FIELDS+4]); pp(" vol=" as *u8); pn(bars[last*MD_FIELDS+5]); pp("\n" as *u8) 137 138 var advd: i64 = 20; if advd > nbars { advd = nbars } 139 let adv: i64 = md_adv(bars, nbars, advd) 140 pp("ADV(" as *u8); pn(advd); pp("d) cents=" as *u8); pn(adv); pp(" capacity@1% cents=" as *u8); pn(md_capacity(adv, 100)); pp("\n" as *u8) 141 142 let sig: *i64 = sys_mmap(8 * 600) as *i64 143 let out: *i64 = sys_mmap(8 * 16) as *i64 144 pp("\n== STRATEGY TOURNAMENT on REAL IBM data ($10k, 10bps slip, 1% ADV cap) ==\n" as *u8) 145 st_sma_cross(bars, nbars, 5, 20, sig); bt_run(bars, nbars, sig, K_MAGIC_1000000, 10, 0, adv, 100, out) 146 tour_print("SMA 5/20 crossover " as *u8, out) 147 st_above_sma(bars, nbars, 20, sig); bt_run(bars, nbars, sig, K_MAGIC_1000000, 10, 0, adv, 100, out) 148 tour_print("momentum >SMA20 " as *u8, out) 149 st_below_sma(bars, nbars, 20, sig); bt_run(bars, nbars, sig, K_MAGIC_1000000, 10, 0, adv, 100, out) 150 tour_print("mean-rev <SMA20 " as *u8, out) 151 st_above_sma(bars, nbars, 50, sig); bt_run(bars, nbars, sig, K_MAGIC_1000000, 10, 0, adv, 100, out) 152 tour_print("momentum >SMA50 " as *u8, out) 153 154 // -- THE OVERFIT TEST: a REAL edge must win BOTH halves with ENOUGH trades (2 winners != a signal) -- 155 pp("\n== OOS CHECK (mean-rev <SMA20): 70% in-sample / 30% held-out ==\n" as *u8) 156 let split: i64 = pp_split(nbars, K_MAGIC_7000) 157 st_below_sma(bars, nbars, 20, sig) 158 let out_is: *i64 = sys_mmap(8 * 16) as *i64 159 bt_run(bars, split, sig, K_MAGIC_1000000, 10, 0, adv, 100, out_is) 160 pp(" in-sample (70%): trades=" as *u8); pn(out_is[BT_TRADES]); pp(" ret_bps=" as *u8); pn(out_is[BT_RET]); pp(" PF_bps=" as *u8); pn(out_is[BT_PF]); pp("\n" as *u8) 161 pp_oos_run(bars, nbars, sig, split, K_MAGIC_1000000, 10, 0, adv, 100, out) 162 pp(" out-of-sample (30%): trades=" as *u8); pn(out[BT_TRADES]); pp(" ret_bps=" as *u8); pn(out[BT_RET]); pp(" PF_bps=" as *u8); pn(out[BT_PF]); pp("\n" as *u8) 163 // HONEST verdict: profit in BOTH halves AND >=5 OOS trades. Otherwise it is a window/sample artifact. 164 var real_edge: i64 = 0 165 if out_is[BT_PF] > K_MAGIC_10000 { if out[BT_PF] > K_MAGIC_10000 { if out[BT_TRADES] >= 5 { real_edge = 1 } } } 166 if real_edge == 1 { pp(" VERDICT: consistent IS+OOS with enough trades (promising -- still ONE symbol, needs a universe).\n" as *u8) } 167 else { pp(" VERDICT: NO real edge -- lost in-sample (PF<1) and/or too few OOS trades. The full-sample 'edge' was a WINDOW ARTIFACT. Overfit-kill working as designed.\n" as *u8) } 168 169 pp("\nMAKE-IT-REAL PROVEN: real market data -> full sovereign pipeline -> HONEST ranking + OOS overfit-kill (SIM).\n" as *u8) 170 pp("(none showing an edge on 100 bars of ONE symbol is EXPECTED + honest -- a real edge needs a universe + OOS.)\n" as *u8) 171 return 0 172}