nx_taxlot_gate.nx source
↩ module page · 132 lines · 6463 B
1// nx_taxlot_gate.nx -- CAPITAL-GAINS TAX-LOT + WASH-SALE GATE.
2// Proves realized gain/loss sign, holding-period classification (incl. the exactly-one-year boundary),
3// the IRC 1091 wash-sale disallowance across full / partial / outside-window / symmetric-window cases, the
4// allowed+disallowed==original conservation invariant, the basis deferral, FIFO lot consumption, and the
5// fail-closed overdraw guard. Hand-verified integer values. license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
6
7import "nx_taxlot_lib.nx"
8import "nx_matter_lib.nx"
9
10func xg_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
11func xg_putn(v: i64) -> i64 {
12 let t: *u8 = sys_mmap(32)
13 var o: i64 = 0
14 var m: i64 = v
15 if m < 0 { t[o] = 45 as u8; o = o + 1; m = 0 - m }
16 let d: *u8 = sys_mmap(32)
17 var k: i64 = 0
18 if m == 0 { d[0] = 48 as u8; k = 1 }
19 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
20 var i: i64 = 0
21 while i < k { t[o] = d[k - 1 - i]; o = o + 1; i = i + 1 }
22 sys_write(1, t, o)
23 return 0
24}
25func xg_ck(cnt: *i64, name: *u8, got: i64, want: i64) -> i64 {
26 if got == want {
27 cnt[0] = cnt[0] + 1
28 xg_puts(" PASS " as *u8); xg_puts(name); xg_puts(" = " as *u8); xg_putn(got); xg_puts("\n" as *u8)
29 return 1
30 }
31 cnt[1] = cnt[1] + 1
32 xg_puts(" FAIL " as *u8); xg_puts(name); xg_puts(" got " as *u8); xg_putn(got)
33 xg_puts(" want " as *u8); xg_putn(want); xg_puts("\n" as *u8)
34 return 0
35}
36func xg_ckstr(cnt: *i64, name: *u8, got: *u8, want: *u8) -> i64 {
37 if mt_streq(got, want) == 1 {
38 cnt[0] = cnt[0] + 1
39 xg_puts(" PASS " as *u8); xg_puts(name); xg_puts(" = " as *u8); xg_puts(got); xg_puts("\n" as *u8)
40 return 1
41 }
42 cnt[1] = cnt[1] + 1
43 xg_puts(" FAIL " as *u8); xg_puts(name); xg_puts(" got " as *u8); xg_puts(got); xg_puts("\n" as *u8)
44 return 0
45}
46
47func main(argc: i64, argv: *i64) -> i64 {
48 let cnt: *i64 = sys_mmap(16) as *i64
49 cnt[0] = 0
50 cnt[1] = 0
51
52 xg_puts("NISHI-TAXLOT-GATE (capital gains, wash-sale IRC 1091, FIFO lots, integer-exact, fail-closed)\n" as *u8)
53
54 // ---- realized gain / loss sign ----
55 xg_ck(cnt, "T1 proceeds 1200 basis 1000 -> gain 200" as *u8, tl_realized_gain(1200, 1000), 200)
56 xg_ck(cnt, "T2 proceeds 800 basis 1000 -> loss -200" as *u8, tl_realized_gain(800, 1000), 0 - 200)
57
58 // ---- holding-period classification (1=LONG, 0=SHORT); exactly 365 days is SHORT ----
59 xg_ck(cnt, "T3 held 400 days -> LONG-TERM (1)" as *u8, tl_holding_class(0, 400), 1)
60 xg_ck(cnt, "T4 held 300 days -> SHORT-TERM (0)" as *u8, tl_holding_class(0, 300), 0)
61 xg_ck(cnt, "T5 held exactly 365 days -> SHORT-TERM (not more-than-a-year)" as *u8, tl_holding_class(0, 365), 0)
62 xg_ck(cnt, "T6 held 366 days -> LONG-TERM (1)" as *u8, tl_holding_class(0, 366), 1)
63 xg_ckstr(cnt, "T6a class label 400 days = LONG-TERM" as *u8, tl_class_str(tl_holding_class(0, 400)), "LONG-TERM" as *u8)
64
65 // ---- *WASH SALE: loss 200 on 100 shares sold on day 100 ----
66 xg_ck(cnt, "T7 replacement day 110 (gap 10) -> full loss DISALLOWED 200" as *u8,
67 tl_wash_disallowed(200, 100, 110, 100, 100), 200)
68 xg_ck(cnt, "T7a replacement day 70 (gap 30, before the sale) -> still washed 200" as *u8,
69 tl_wash_disallowed(200, 100, 70, 100, 100), 200)
70 xg_ck(cnt, "T8 allowed loss after full wash = 0" as *u8,
71 tl_allowed_loss(200, 100, 110, 100, 100), 0)
72 xg_ck(cnt, "T9 replacement day 140 (gap 40 > 30) -> NOT washed (0)" as *u8,
73 tl_wash_disallowed(200, 100, 140, 100, 100), 0)
74 xg_ck(cnt, "T10 loss fully claimable outside the window = 200" as *u8,
75 tl_allowed_loss(200, 100, 140, 100, 100), 200)
76
77 // ---- *PARTIAL wash: only 40 of 100 sold shares replaced ----
78 xg_ck(cnt, "T11 partial: 40 of 100 replaced -> disallowed 80" as *u8,
79 tl_wash_disallowed(200, 100, 110, 40, 100), 80)
80 xg_ck(cnt, "T12 partial: allowed loss = 120" as *u8,
81 tl_allowed_loss(200, 100, 110, 40, 100), 120)
82 let dis: i64 = tl_wash_disallowed(200, 100, 110, 40, 100)
83 let alw: i64 = tl_allowed_loss(200, 100, 110, 40, 100)
84 xg_ck(cnt, "T13 conservation: allowed + disallowed = original loss 200" as *u8, dis + alw, 200)
85
86 // ---- a GAIN (or a non-positive loss_amount) is NEVER washed ----
87 xg_ck(cnt, "T14 loss_amount 0 (it was a gain) -> nothing washed" as *u8,
88 tl_wash_disallowed(0, 100, 110, 100, 100), 0)
89 xg_ck(cnt, "T15 negative loss_amount -> nothing washed" as *u8,
90 tl_wash_disallowed(0 - 50, 100, 110, 100, 100), 0)
91
92 // ---- *the disallowed loss is DEFERRED into the replacement lot basis (preserved, not destroyed) ----
93 xg_ck(cnt, "T16 replacement basis 5000 + disallowed 200 -> adjusted 5200" as *u8,
94 tl_adjusted_replacement_basis(5000, 200), 5200)
95
96 // ---- FIFO SALE: lot0[100 sh, basis 1000], lot1[100 sh, basis 1200]; sell 150 @ 11/sh ----
97 let ls: *i64 = sys_mmap(16) as *i64
98 let lb: *i64 = sys_mmap(16) as *i64
99 ls[0] = 100
100 ls[1] = 100
101 lb[0] = 1000
102 lb[1] = 1200
103 let out: *i64 = sys_mmap(24) as *i64
104 let sold: i64 = tl_sell_fifo(ls, lb, 2, 150, 11, out)
105 xg_ck(cnt, "T17 FIFO sold 150 shares" as *u8, sold, 150)
106 xg_ck(cnt, "T17a FIFO basis consumed = 1600 (1000 + 600 from second lot)" as *u8, out[1], 1600)
107 xg_ck(cnt, "T17b FIFO proceeds = 1650" as *u8, out[0], 1650)
108 xg_ck(cnt, "T17c FIFO realized gain = 50" as *u8, out[2], 50)
109 xg_ck(cnt, "T17d oldest lot fully consumed (0 shares left)" as *u8, ls[0], 0)
110
111 // ---- *FAIL-CLOSED: cannot sell more shares than the book holds ----
112 let ls2: *i64 = sys_mmap(16) as *i64
113 let lb2: *i64 = sys_mmap(16) as *i64
114 ls2[0] = 100
115 ls2[1] = 100
116 lb2[0] = 1000
117 lb2[1] = 1200
118 let out2: *i64 = sys_mmap(24) as *i64
119 let sold2: i64 = tl_sell_fifo(ls2, lb2, 2, 250, 11, out2)
120 xg_ck(cnt, "T18 overdraw: asked 250 on a 200-share book -> sold only 200" as *u8, sold2, 200)
121
122 xg_puts("nx_taxlot_gate: pass=" as *u8); xg_putn(cnt[0])
123 xg_puts(" fail=" as *u8); xg_putn(cnt[1]); xg_puts("\n" as *u8)
124 if cnt[1] == 0 {
125 xg_puts("TAXLOT nx_taxlot: VERDICT=GREEN (exact capital gains + wash-sale disallowance/deferral + FIFO overdraw-safe)\n" as *u8)
126 sys_exit(0)
127 return 0
128 }
129 xg_puts("TAXLOT nx_taxlot: VERDICT=RED\n" as *u8)
130 sys_exit(1)
131 return 1
132}