code wiki / (root) / nx_fin_backtest_gate.nx

nx_fin_backtest_gate.nx source

↩ module page · 59 lines · 3450 B

1// nx_fin_backtest_gate.nx -- R2 GATE: proves the backtester on KNOWN bars + a KNOWN signal, with EVERY metric 2// hand-computed (no network, no false-green). Integrates R1 (md_parse_csv -> bars) into R2 (bt_run). The two 3// trades are +50 (win) and -50 (loss) per share so the gate PROVES the engine reports losses honestly -- not the 4// "no-loss" fantasy. Exits 0 iff all pass. license_tier: ORIGINAL 5import "nx_gate.nx" 6import "nx_fin_marketdata.nx" 7import "nx_fin_backtest.nx" 8 9func chk(name: *u8, got: i64, want: i64, st: *i64) -> i64 { 10 if got == want { st[0] = st[0] + 1; gw(" PASS " as *u8); gw(name); gw("\n" as *u8) } 11 else { st[1] = st[1] + 1; gw(" FAIL " as *u8); gw(name); gw(" got=" as *u8); gn(got); gw(" want=" as *u8); gn(want); gw("\n" as *u8) } 12 return 0 13} 14 15func main() -> i64 { 16 let st: *i64 = sys_mmap(16) as *i64 17 st[0] = 0; st[1] = 0 18 19 // -- position sizing + the ADV/capacity cap (the scaling wall) -- 20 chk("size cash-bound (no cap)" as *u8, bt_position_size(1000000, 1000, 0, 0), 1000, st) 21 chk("size capacity-capped @10bps ADV" as *u8, bt_position_size(1000000, 1000, 100000000, 10), 100, st) 22 chk("size loose cap @100% -> cash-bound" as *u8, bt_position_size(1000000, 1000, 100000000, 10000), 1000, st) 23 24 // -- backtest on KNOWN bars (closes 1000,1100,1050,1200,1150 cents) + signal [1,1,0,1,0] -- 25 let csv: *u8 = "Date,Open,High,Low,Close,Volume\n2024-01-02,10.00,10.00,10.00,10.00,1000000\n2024-01-03,11.00,11.00,11.00,11.00,1000000\n2024-01-04,10.50,10.50,10.50,10.50,1000000\n2024-01-05,12.00,12.00,12.00,12.00,1000000\n2024-01-06,11.50,11.50,11.50,11.50,1000000\n" as *u8 26 var n: i64 = 0; while csv[n] != (0 as u8) { n = n + 1 } 27 let bars: *i64 = sys_mmap(8 * MD_FIELDS * 16) as *i64 28 let nbars: i64 = md_parse_csv(csv, n, bars, 16) 29 chk("parsed 5 bars (R1->R2)" as *u8, nbars, 5, st) 30 31 let sig: *i64 = sys_mmap(8 * 8) as *i64 32 sig[0]=1; sig[1]=1; sig[2]=0; sig[3]=1; sig[4]=0 33 let out: *i64 = sys_mmap(8 * 16) as *i64 34 bt_run(bars, nbars, sig, 1000000, 0, 0, 0, 0, out) // start $10,000; no slippage/commission/cap 35 36 chk("n_trades = 2" as *u8, out[BT_TRADES], 2, st) 37 chk("n_wins = 1" as *u8, out[BT_WINS], 1, st) 38 chk("n_losses = 1 (HONEST: reports the loss)" as *u8, out[BT_LOSSES], 1, st) 39 chk("gross_win cents (+50 x 1000sh)" as *u8, out[BT_GROSS_WIN], 50000, st) 40 chk("gross_loss cents (-50 x 875sh)" as *u8, out[BT_GROSS_LOSS], 43750, st) 41 chk("net_pnl cents" as *u8, out[BT_NET], 6250, st) 42 chk("expectancy/trade cents" as *u8, out[BT_EXPECTANCY], 3125, st) 43 chk("win_rate bps (50%)" as *u8, out[BT_WINRATE], 5000, st) 44 chk("profit_factor bps (1.142x)" as *u8, out[BT_PF], 11428, st) 45 chk("max_drawdown bps (8.52%)" as *u8, out[BT_MAXDD], 852, st) 46 chk("return bps (0.625%)" as *u8, out[BT_RET], 62, st) 47 chk("final_equity cents" as *u8, out[BT_FINAL_EQ], 1006250, st) 48 49 // -- costs are wired: 100bps slippage must REDUCE net pnl -- 50 let out2: *i64 = sys_mmap(8 * 16) as *i64 51 bt_run(bars, nbars, sig, 1000000, 100, 0, 0, 0, out2) 52 var slip_less: i64 = 0; if out2[BT_NET] < 6250 { slip_less = 1 } 53 chk("slippage 100bps reduces net pnl" as *u8, slip_less, 1, st) 54 55 gw("nx_fin_backtest_gate: PASS=" as *u8); gn(st[0]); gw(" FAIL=" as *u8); gn(st[1]); gw("\n" as *u8) 56 if st[1] == 0 { gw("R2 nx_fin_backtest: GREEN\n" as *u8); return 0 } 57 gw("R2 nx_fin_backtest: RED\n" as *u8) 58 return 1 59}