Functional Weave
Code in Rust

lending.affordability@1.0.1

vectors.json

6,067 bytes · view raw

[
 {
  "name": "\u00a3200k mortgage on \u00a34,500 a month, stressed at +3 points, passes 40%",
  "args": [
   {
    "minor": 450000,
    "currency": "GBP"
   },
   {
    "minor": 30000,
    "currency": "GBP"
   },
   {
    "minor": 20000000,
    "currency": "GBP"
   },
   450,
   750,
   300,
   4000
  ],
  "expect": {
   "payment": {
    "minor": 111167,
    "currency": "GBP"
   },
   "stressedPayment": {
    "minor": 147799,
    "currency": "GBP"
   },
   "debtToIncomeBasisPoints": 3138,
   "stressedDebtToIncomeBasisPoints": 3952,
   "affordable": true,
   "headroom": {
    "minor": 2201,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "the same loan with \u00a3800 of other debts fails",
  "args": [
   {
    "minor": 450000,
    "currency": "GBP"
   },
   {
    "minor": 80000,
    "currency": "GBP"
   },
   {
    "minor": 20000000,
    "currency": "GBP"
   },
   450,
   750,
   300,
   4000
  ],
  "expect": {
   "payment": {
    "minor": 111167,
    "currency": "GBP"
   },
   "stressedPayment": {
    "minor": 147799,
    "currency": "GBP"
   },
   "debtToIncomeBasisPoints": 4249,
   "stressedDebtToIncomeBasisPoints": 5063,
   "affordable": false,
   "headroom": {
    "minor": -47799,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "no other commitments",
  "args": [
   {
    "minor": 300000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 15000000,
    "currency": "GBP"
   },
   500,
   800,
   360,
   4500
  ],
  "expect": {
   "payment": {
    "minor": 80524,
    "currency": "GBP"
   },
   "stressedPayment": {
    "minor": 110065,
    "currency": "GBP"
   },
   "debtToIncomeBasisPoints": 2685,
   "stressedDebtToIncomeBasisPoints": 3669,
   "affordable": true,
   "headroom": {
    "minor": 24935,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "stress rate equal to the actual rate",
  "args": [
   {
    "minor": 250000,
    "currency": "GBP"
   },
   {
    "minor": 10000,
    "currency": "GBP"
   },
   {
    "minor": 1000000,
    "currency": "GBP"
   },
   700,
   700,
   60,
   3000
  ],
  "expect": {
   "payment": {
    "minor": 19802,
    "currency": "GBP"
   },
   "stressedPayment": {
    "minor": 19802,
    "currency": "GBP"
   },
   "debtToIncomeBasisPoints": 1193,
   "stressedDebtToIncomeBasisPoints": 1193,
   "affordable": true,
   "headroom": {
    "minor": 45198,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "interest-free loan: the stress still bites",
  "args": [
   {
    "minor": 200000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 1200000,
    "currency": "GBP"
   },
   0,
   300,
   24,
   3500
  ],
  "expect": {
   "payment": {
    "minor": 50000,
    "currency": "GBP"
   },
   "stressedPayment": {
    "minor": 51578,
    "currency": "GBP"
   },
   "debtToIncomeBasisPoints": 2500,
   "stressedDebtToIncomeBasisPoints": 2579,
   "affordable": true,
   "headroom": {
    "minor": 18422,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "a borderline: payment lands exactly on the ceiling",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 1200000,
    "currency": "GBP"
   },
   0,
   0,
   24,
   5000
  ],
  "expect": {
   "payment": {
    "minor": 50000,
    "currency": "GBP"
   },
   "stressedPayment": {
    "minor": 50000,
    "currency": "GBP"
   },
   "debtToIncomeBasisPoints": 5000,
   "stressedDebtToIncomeBasisPoints": 5000,
   "affordable": true,
   "headroom": {
    "minor": 0,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "a penny over the ceiling fails",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   {
    "minor": 1,
    "currency": "GBP"
   },
   {
    "minor": 1200000,
    "currency": "GBP"
   },
   0,
   0,
   24,
   5000
  ],
  "expect": {
   "payment": {
    "minor": 50000,
    "currency": "GBP"
   },
   "stressedPayment": {
    "minor": 50000,
    "currency": "GBP"
   },
   "debtToIncomeBasisPoints": 5001,
   "stressedDebtToIncomeBasisPoints": 5001,
   "affordable": false,
   "headroom": {
    "minor": -1,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "zero income is refused",
  "args": [
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 1000000,
    "currency": "GBP"
   },
   500,
   800,
   60,
   4000
  ],
  "expectError": "monthlyIncome must be greater than zero"
 },
 {
  "name": "negative commitments are refused",
  "args": [
   {
    "minor": 300000,
    "currency": "GBP"
   },
   {
    "minor": -1,
    "currency": "GBP"
   },
   {
    "minor": 1000000,
    "currency": "GBP"
   },
   500,
   800,
   60,
   4000
  ],
  "expectError": "monthlyCommitments must not be negative"
 },
 {
  "name": "a stress rate below the actual rate is refused",
  "args": [
   {
    "minor": 300000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 1000000,
    "currency": "GBP"
   },
   500,
   400,
   60,
   4000
  ],
  "expectError": "stressRateBasisPoints must not be below the actual rate"
 },
 {
  "name": "a ceiling above 100% is refused",
  "args": [
   {
    "minor": 300000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 1000000,
    "currency": "GBP"
   },
   500,
   800,
   60,
   10001
  ],
  "expectError": "maxDebtToIncomeBasisPoints must be between 1 and 10000"
 },
 {
  "name": "mixed currencies are refused",
  "args": [
   {
    "minor": 300000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "EUR"
   },
   {
    "minor": 1000000,
    "currency": "GBP"
   },
   500,
   800,
   60,
   4000
  ],
  "expectError": "currency mismatch"
 },
 {
  "name": "a zero term is refused, by lending.loan-payment",
  "args": [
   {
    "minor": 300000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 1000000,
    "currency": "GBP"
   },
   500,
   800,
   0,
   4000
  ],
  "expectError": "termMonths must be at least 1"
 }
]