Functional Weave
Code in Python

lending.overpayment-effect@1.0.0

vectors.json

8,530 bytes · view raw

[
 {
  "name": "\u00a310,000 off a new \u00a3100,000 5% 25-year mortgage",
  "args": [
   {
    "minor": 10000000,
    "currency": "GBP"
   },
   500,
   300,
   12,
   {
    "minor": 58459,
    "currency": "GBP"
   },
   {
    "minor": 1000000,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expect": {
   "newBalance": {
    "minor": 9000000,
    "currency": "GBP"
   },
   "baselinePayments": 300,
   "baselineInterest": {
    "minor": 7537705,
    "currency": "GBP"
   },
   "reducedTermPayments": 247,
   "reducedTermFinalPayment": {
    "minor": 40629,
    "currency": "GBP"
   },
   "reducedTermInterest": {
    "minor": 5421543,
    "currency": "GBP"
   },
   "paymentsSaved": 53,
   "reducedPayment": {
    "minor": 52613,
    "currency": "GBP"
   },
   "reducedPaymentInterest": {
    "minor": 6783966,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "\u00a3200 off \u00a31,000 at 12% with a year left",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   1200,
   12,
   12,
   {
    "minor": 8885,
    "currency": "GBP"
   },
   {
    "minor": 20000,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expect": {
   "newBalance": {
    "minor": 80000,
    "currency": "GBP"
   },
   "baselinePayments": 12,
   "baselineInterest": {
    "minor": 6619,
    "currency": "GBP"
   },
   "reducedTermPayments": 10,
   "reducedTermFinalPayment": {
    "minor": 4299,
    "currency": "GBP"
   },
   "reducedTermInterest": {
    "minor": 4264,
    "currency": "GBP"
   },
   "paymentsSaved": 2,
   "reducedPayment": {
    "minor": 7108,
    "currency": "GBP"
   },
   "reducedPaymentInterest": {
    "minor": 5294,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "the recalculated payment rounded down",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   1200,
   12,
   12,
   {
    "minor": 8885,
    "currency": "GBP"
   },
   {
    "minor": 20000,
    "currency": "GBP"
   },
   "down"
  ],
  "expect": {
   "newBalance": {
    "minor": 80000,
    "currency": "GBP"
   },
   "baselinePayments": 12,
   "baselineInterest": {
    "minor": 6619,
    "currency": "GBP"
   },
   "reducedTermPayments": 10,
   "reducedTermFinalPayment": {
    "minor": 4299,
    "currency": "GBP"
   },
   "reducedTermInterest": {
    "minor": 4264,
    "currency": "GBP"
   },
   "paymentsSaved": 2,
   "reducedPayment": {
    "minor": 7107,
    "currency": "GBP"
   },
   "reducedPaymentInterest": {
    "minor": 5294,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "interest-free: the term shortens by whole payments only",
  "args": [
   {
    "minor": 120000,
    "currency": "GBP"
   },
   0,
   12,
   12,
   {
    "minor": 10000,
    "currency": "GBP"
   },
   {
    "minor": 25000,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expect": {
   "newBalance": {
    "minor": 95000,
    "currency": "GBP"
   },
   "baselinePayments": 12,
   "baselineInterest": {
    "minor": 0,
    "currency": "GBP"
   },
   "reducedTermPayments": 10,
   "reducedTermFinalPayment": {
    "minor": 5000,
    "currency": "GBP"
   },
   "reducedTermInterest": {
    "minor": 0,
    "currency": "GBP"
   },
   "paymentsSaved": 2,
   "reducedPayment": {
    "minor": 7917,
    "currency": "GBP"
   },
   "reducedPaymentInterest": {
    "minor": 0,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "a penny overpayment saves no payments",
  "args": [
   {
    "minor": 500000,
    "currency": "GBP"
   },
   600,
   6,
   12,
   {
    "minor": 84798,
    "currency": "GBP"
   },
   {
    "minor": 1,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expect": {
   "newBalance": {
    "minor": 499999,
    "currency": "GBP"
   },
   "baselinePayments": 6,
   "baselineInterest": {
    "minor": 8787,
    "currency": "GBP"
   },
   "reducedTermPayments": 6,
   "reducedTermFinalPayment": {
    "minor": 84796,
    "currency": "GBP"
   },
   "reducedTermInterest": {
    "minor": 8787,
    "currency": "GBP"
   },
   "paymentsSaved": 0,
   "reducedPayment": {
    "minor": 84798,
    "currency": "GBP"
   },
   "reducedPaymentInterest": {
    "minor": 8787,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "quarterly loan, half the balance overpaid",
  "args": [
   {
    "minor": 1000000,
    "currency": "GBP"
   },
   800,
   24,
   4,
   {
    "minor": 136510,
    "currency": "GBP"
   },
   {
    "minor": 500000,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expect": {
   "newBalance": {
    "minor": 500000,
    "currency": "GBP"
   },
   "baselinePayments": 8,
   "baselineInterest": {
    "minor": 92080,
    "currency": "GBP"
   },
   "reducedTermPayments": 4,
   "reducedTermFinalPayment": {
    "minor": 115086,
    "currency": "GBP"
   },
   "reducedTermInterest": {
    "minor": 24616,
    "currency": "GBP"
   },
   "paymentsSaved": 4,
   "reducedPayment": {
    "minor": 68255,
    "currency": "GBP"
   },
   "reducedPaymentInterest": {
    "minor": 46039,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "a payment above the level payment clears even the baseline early",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   1200,
   12,
   12,
   {
    "minor": 10000,
    "currency": "GBP"
   },
   {
    "minor": 10000,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expect": {
   "newBalance": {
    "minor": 90000,
    "currency": "GBP"
   },
   "baselinePayments": 11,
   "baselineInterest": {
    "minor": 5898,
    "currency": "GBP"
   },
   "reducedTermPayments": 10,
   "reducedTermFinalPayment": {
    "minor": 4794,
    "currency": "GBP"
   },
   "reducedTermInterest": {
    "minor": 4794,
    "currency": "GBP"
   },
   "paymentsSaved": 1,
   "reducedPayment": {
    "minor": 7996,
    "currency": "GBP"
   },
   "reducedPaymentInterest": {
    "minor": 5956,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "mid-term: 10 years left on \u00a360,000 at 4%",
  "args": [
   {
    "minor": 6000000,
    "currency": "GBP"
   },
   400,
   120,
   12,
   {
    "minor": 60747,
    "currency": "GBP"
   },
   {
    "minor": 500000,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expect": {
   "newBalance": {
    "minor": 5500000,
    "currency": "GBP"
   },
   "baselinePayments": 120,
   "baselineInterest": {
    "minor": 1289651,
    "currency": "GBP"
   },
   "reducedTermPayments": 108,
   "reducedTermFinalPayment": {
    "minor": 57932,
    "currency": "GBP"
   },
   "reducedTermInterest": {
    "minor": 1057861,
    "currency": "GBP"
   },
   "paymentsSaved": 12,
   "reducedPayment": {
    "minor": 55685,
    "currency": "GBP"
   },
   "reducedPaymentInterest": {
    "minor": 1182177,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "an overpayment of the whole balance is a settlement, not an overpayment",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   1200,
   12,
   12,
   {
    "minor": 8885,
    "currency": "GBP"
   },
   {
    "minor": 100000,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expectError": "overpayment must be less than the balance"
 },
 {
  "name": "a zero overpayment is refused",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   1200,
   12,
   12,
   {
    "minor": 8885,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expectError": "overpayment must be greater than zero"
 },
 {
  "name": "mixed currencies are refused",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   1200,
   12,
   12,
   {
    "minor": 8885,
    "currency": "GBP"
   },
   {
    "minor": 1000,
    "currency": "EUR"
   },
   "half-up"
  ],
  "expectError": "currency mismatch"
 },
 {
  "name": "a payment that does not cover the interest never repays",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   1200,
   12,
   12,
   {
    "minor": 1000,
    "currency": "GBP"
   },
   {
    "minor": 1000,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expectError": "does not cover the interest"
 },
 {
  "name": "a zero payment is refused",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   1200,
   12,
   12,
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 1000,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expectError": "payment must be greater than zero"
 },
 {
  "name": "the remaining term must hold whole payments",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   1200,
   13,
   4,
   {
    "minor": 8885,
    "currency": "GBP"
   },
   {
    "minor": 1000,
    "currency": "GBP"
   },
   "half-up"
  ],
  "expectError": "is not a whole number of payments"
 }
]