nx_fin_finance.nx source
↩ module page · 86 lines · 4635 B
1// nx_fin_finance.nx -- R7 (financing-cost optimizer) of THE NISHI FINANCIAL ECOSYSTEM: find AFFORDABLE
2// funding by ranking options on TRUE TOTAL COST + screening RISK. Operator's crisis: the US system isn't
3// offering an affordable rate; the answer is NOT a fantasy "cheap international loan" (that space is mostly
4// ADVANCE-FEE FRAUD), it is (1) exact apples-to-apples total-cost ranking of REAL options (credit unions,
5// CDFIs, balance transfers, debt-management plans, member/microfinance) and (2) a SCAM/PREDATORY shield.
6//
7// TRUE COST (#11 no magic, exact no-float via nx_debt amortization): an option's cost = origination fee +
8// total interest to pay off `balance` at `payment`/month. Headline APR alone is a LIE -- fees + term decide
9// the real cost; this compares them honestly on ONE scenario.
10// RISK (the never-brick analog #26: the system must NEVER lead a desperate borrower into a scam): flags
11// ADVANCE_FEE (lender demands money BEFORE disbursing -> the #1 loan-scam tell; a real lender never does)
12// PREDATORY (APR above the usury line -- payday/loan-shark territory)
13// UNLICENSED (no recognized regulator -- offshore/"international" cold-offers)
14// An option carrying ADVANCE_FEE or UNLICENSED is EXCLUDED from ranking even if its ADVERTISED rate is the
15// lowest -- the scam's bait rate must never win. Data-driven: options + the usury line are DATA (any lender,
16// any country). No floats, no hardware writes, no auto-apply (emit ranking; the operator decides). license_tier: ORIGINAL
17import "nx_syscalls.nx"
18import "nx_money.nx"
19import "nx_debt_payoff.nx"
20
21const FE_ADVANCE_FEE: i64 = 1
22const FE_PREDATORY: i64 = 2
23const FE_UNLICENSED: i64 = 4
24
25// true total cost of an option = origination fee + total interest to payoff `balance` at `payment`/month.
26// writes months-to-payoff to out_months[0]. returns -1 if the payment can't amortize it (unaffordable).
27func fe_total_cost(balance: i64, payment: i64, apr_scaled: i64, orig_fee: i64, out_months: *i64) -> i64 {
28 let intr: *i64 = sys_mmap(16) as *i64
29 let months: i64 = dbt_payoff_months(balance, apr_scaled, payment, intr)
30 if months < 0 { out_months[0] = months; return 0 - 1 }
31 out_months[0] = months
32 return mny_add(orig_fee, intr[0])
33}
34
35// risk flags for an option vs the usury line. 0 = clean.
36func fe_risk(apr_scaled: i64, upfront_required: i64, licensed: i64, usury_apr_scaled: i64) -> i64 {
37 var f: i64 = 0
38 if upfront_required == 1 { f = f + FE_ADVANCE_FEE }
39 if apr_scaled > usury_apr_scaled { f = f + FE_PREDATORY }
40 if licensed == 0 { f = f + FE_UNLICENSED }
41 return f
42}
43
44// recommendable only if it carries NEITHER the advance-fee scam tell NOR the unlicensed tell. (A predatory-
45// but-licensed option is not excluded here -- it simply loses on true cost; the scam baits do NOT.)
46func fe_is_safe(flags: i64) -> i64 {
47 if (flags & FE_ADVANCE_FEE) != 0 { return 0 }
48 if (flags & FE_UNLICENSED) != 0 { return 0 }
49 return 1
50}
51
52// rank: among SAFE + affordable options, the lowest true cost. writes best index to out_idx[0];
53// returns the best total cost, or -1 if none qualify.
54func fe_rank_best(balance: i64, payment: i64, aprs: *i64, fees: *i64, upfronts: *i64, lic: *i64, n: i64, usury: i64, out_idx: *i64) -> i64 {
55 var best: i64 = 0 - 1
56 var bestcost: i64 = 0
57 let m: *i64 = sys_mmap(16) as *i64
58 var i: i64 = 0
59 while i < n {
60 let flags: i64 = fe_risk(aprs[i], upfronts[i], lic[i], usury)
61 if fe_is_safe(flags) == 1 {
62 let cost: i64 = fe_total_cost(balance, payment, aprs[i], fees[i], m)
63 if cost >= 0 {
64 if best < 0 { best = i; bestcost = cost }
65 else { if cost < bestcost { best = i; bestcost = cost } }
66 }
67 }
68 i = i + 1
69 }
70 out_idx[0] = best
71 if best < 0 { return 0 - 1 }
72 return bestcost
73}
74
75// SURVIVAL RUNWAY (financial resilience -- the core JOB-LOSS question): if income stopped today, how long
76// does `savings` (liquid cash on hand) cover `monthly_obligations` (cadence-normalized bills)? Exact integer
77// arithmetic, no floats. Returns -1 ("indefinite": no recurring obligations). Months = savings / obligations.
78func fe_runway_months(savings: i64, monthly_obligations: i64) -> i64 {
79 if monthly_obligations <= 0 { return 0 - 1 }
80 return savings / monthly_obligations
81}
82// runway in DAYS (30-day month), so a sub-month runway stays legible ("6 days", not a floored "0 months").
83func fe_runway_days(savings: i64, monthly_obligations: i64) -> i64 {
84 if monthly_obligations <= 0 { return 0 - 1 }
85 return savings * 30 / monthly_obligations
86}