moneyfunx 0.0.30 → 0.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.d.ts +6 -0
- package/build/index.js +5 -0
- package/build/lib/errors.d.ts +6 -0
- package/build/lib/errors.js +14 -0
- package/build/lib/helperFunctions.d.ts +39 -0
- package/build/lib/helperFunctions.js +51 -0
- package/build/lib/loan.d.ts +86 -0
- package/{src → build}/lib/loan.js +19 -112
- package/build/lib/paymentTypes.d.ts +13 -0
- package/build/lib/paymentTypes.js +1 -0
- package/build/lib/payments.d.ts +38 -0
- package/{src → build}/lib/payments.js +35 -90
- package/build/lib/sorting.d.ts +31 -0
- package/{src → build}/lib/sorting.js +2 -5
- package/jest.config.js +11 -0
- package/package.json +17 -6
- package/src/index.ts +18 -0
- package/src/lib/errors.ts +15 -0
- package/src/lib/helperFunctions.ts +72 -0
- package/src/lib/loan.ts +170 -0
- package/src/lib/paymentTypes.ts +15 -0
- package/src/lib/payments.ts +199 -0
- package/src/lib/sorting.ts +41 -0
- package/tsconfig.json +12 -0
- package/src/index.js +0 -19
- package/src/lib/errors.js +0 -6
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { PaymentTooLowError } from "./lib/errors";
|
|
2
|
+
export { calculateMinPayment, numPaymentsToZero, principalRemaining, } from "./lib/helperFunctions";
|
|
3
|
+
export { ILoan, Loan } from "./lib/loan";
|
|
4
|
+
export { determineExtraPayment, amortizePayments, payLoans, } from "./lib/payments";
|
|
5
|
+
export { AmortizationRecord, LoansPaymentSummary, PaymentSummary, } from "./lib/paymentTypes";
|
|
6
|
+
export { snowball, avalanche, sortLoans } from "./lib/sorting";
|
package/build/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { PaymentTooLowError } from "./lib/errors";
|
|
2
|
+
export { calculateMinPayment, numPaymentsToZero, principalRemaining, } from "./lib/helperFunctions";
|
|
3
|
+
export { Loan } from "./lib/loan";
|
|
4
|
+
export { determineExtraPayment, amortizePayments, payLoans, } from "./lib/payments";
|
|
5
|
+
export { snowball, avalanche, sortLoans } from "./lib/sorting";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export class NegativeBalanceError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
Object.setPrototypeOf(this, NegativeBalanceError.prototype);
|
|
5
|
+
this.name = "NegativeBalanceError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export class PaymentTooLowError extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
Object.setPrototypeOf(this, PaymentTooLowError.prototype);
|
|
12
|
+
this.name = "PaymentTooLowError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper Functions
|
|
3
|
+
*
|
|
4
|
+
* These functions are inner primitives used in lifecycle calculations for Loans
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Calculates the minimum payment to pay the principal back in the number of periods at the periodic rate
|
|
8
|
+
*
|
|
9
|
+
* balance = principal + interest
|
|
10
|
+
*
|
|
11
|
+
* @param {number} principal The amount borrowed
|
|
12
|
+
* @param {number} periodicRate The rate the balance accrues interest at per period
|
|
13
|
+
* @param {number [int]} periods The number of periods the principal is repaid over
|
|
14
|
+
* @returns {number} The minimum payment
|
|
15
|
+
*/
|
|
16
|
+
export declare function calculateMinPayment(principal: number, periodicRate: number, periods: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Calculates the principal remaining after a certain number of payments from a beginning principal at a periodic rate
|
|
19
|
+
*
|
|
20
|
+
* balance = principal + interest
|
|
21
|
+
*
|
|
22
|
+
* @param {number} principal The amount borrowed
|
|
23
|
+
* @param {number} payment The amount paid at each period
|
|
24
|
+
* @param {number} periodicRate The rate the balance accrues interest at per period
|
|
25
|
+
* @param {number [int]} periods The number of periods paid to compute the desired principal remaining
|
|
26
|
+
* @returns {number} The remaining principal
|
|
27
|
+
*/
|
|
28
|
+
export declare function principalRemaining(principal: number, payment: number, periodicRate: number, periods: number): number;
|
|
29
|
+
/**
|
|
30
|
+
* Calculates the number of payments required to pay off a principal
|
|
31
|
+
*
|
|
32
|
+
* balance = principal + interest
|
|
33
|
+
*
|
|
34
|
+
* @param {number} principal The amount borrowed
|
|
35
|
+
* @param {number} payment The amount paid at each period
|
|
36
|
+
* @param {number} periodicRate The rate the balance accrues interest at per period
|
|
37
|
+
* @returns The number of payments needed to pay off the principal
|
|
38
|
+
*/
|
|
39
|
+
export declare function numPaymentsToZero(principal: number, payment: number, periodicRate: number): number;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper Functions
|
|
3
|
+
*
|
|
4
|
+
* These functions are inner primitives used in lifecycle calculations for Loans
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Calculates the minimum payment to pay the principal back in the number of periods at the periodic rate
|
|
8
|
+
*
|
|
9
|
+
* balance = principal + interest
|
|
10
|
+
*
|
|
11
|
+
* @param {number} principal The amount borrowed
|
|
12
|
+
* @param {number} periodicRate The rate the balance accrues interest at per period
|
|
13
|
+
* @param {number [int]} periods The number of periods the principal is repaid over
|
|
14
|
+
* @returns {number} The minimum payment
|
|
15
|
+
*/
|
|
16
|
+
export function calculateMinPayment(principal, periodicRate, periods) {
|
|
17
|
+
return periodicRate > 0
|
|
18
|
+
? principal *
|
|
19
|
+
((periodicRate * Math.pow((1 + periodicRate), periods)) /
|
|
20
|
+
(Math.pow((1 + periodicRate), periods) - 1))
|
|
21
|
+
: principal / periods;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Calculates the principal remaining after a certain number of payments from a beginning principal at a periodic rate
|
|
25
|
+
*
|
|
26
|
+
* balance = principal + interest
|
|
27
|
+
*
|
|
28
|
+
* @param {number} principal The amount borrowed
|
|
29
|
+
* @param {number} payment The amount paid at each period
|
|
30
|
+
* @param {number} periodicRate The rate the balance accrues interest at per period
|
|
31
|
+
* @param {number [int]} periods The number of periods paid to compute the desired principal remaining
|
|
32
|
+
* @returns {number} The remaining principal
|
|
33
|
+
*/
|
|
34
|
+
export function principalRemaining(principal, payment, periodicRate, periods) {
|
|
35
|
+
return Math.max(principal * Math.pow((1 + periodicRate), periods) -
|
|
36
|
+
payment * ((Math.pow((1 + periodicRate), periods) - 1) / periodicRate), 0);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Calculates the number of payments required to pay off a principal
|
|
40
|
+
*
|
|
41
|
+
* balance = principal + interest
|
|
42
|
+
*
|
|
43
|
+
* @param {number} principal The amount borrowed
|
|
44
|
+
* @param {number} payment The amount paid at each period
|
|
45
|
+
* @param {number} periodicRate The rate the balance accrues interest at per period
|
|
46
|
+
* @returns The number of payments needed to pay off the principal
|
|
47
|
+
*/
|
|
48
|
+
export function numPaymentsToZero(principal, payment, periodicRate) {
|
|
49
|
+
return Math.ceil(Math.log(payment / (payment - principal * periodicRate)) /
|
|
50
|
+
Math.log(periodicRate + 1));
|
|
51
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* *****************
|
|
4
|
+
* *** MoneyFunx ***
|
|
5
|
+
* *****************
|
|
6
|
+
*
|
|
7
|
+
* mek it funx up
|
|
8
|
+
*
|
|
9
|
+
* This library contains functions used to in personal financial analysis
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Represents a financial loan
|
|
14
|
+
*/
|
|
15
|
+
export interface ILoan {
|
|
16
|
+
id: string;
|
|
17
|
+
principal: number;
|
|
18
|
+
annualRate: number;
|
|
19
|
+
periodsPerYear: number;
|
|
20
|
+
termInYears: number;
|
|
21
|
+
periodicRate: number;
|
|
22
|
+
periods: number;
|
|
23
|
+
minPayment: number;
|
|
24
|
+
totalInterest: number;
|
|
25
|
+
}
|
|
26
|
+
export declare class Loan implements ILoan {
|
|
27
|
+
id: string;
|
|
28
|
+
principal: number;
|
|
29
|
+
annualRate: number;
|
|
30
|
+
periodsPerYear: number;
|
|
31
|
+
termInYears: number;
|
|
32
|
+
periodicRate: number;
|
|
33
|
+
periods: number;
|
|
34
|
+
minPayment: number;
|
|
35
|
+
totalInterest: number;
|
|
36
|
+
/**
|
|
37
|
+
* @constructor
|
|
38
|
+
* @param {number} principal The amount borrowed
|
|
39
|
+
* @param {number} annualRate The yearly rate the loan accrues interest at
|
|
40
|
+
* @param {number} periodsPerYear The number of times the interest is accrued in a year
|
|
41
|
+
* @param {number} termInYears The number of years the loan is repaid over
|
|
42
|
+
*/
|
|
43
|
+
constructor(principal: number, annualRate: number, periodsPerYear: number, termInYears: number);
|
|
44
|
+
/**
|
|
45
|
+
* Verifies a payment amount is valid
|
|
46
|
+
* Throws a PaymentTooLowError if the payment amount is less than the loan's minimum payment
|
|
47
|
+
*
|
|
48
|
+
* @param {number} payment The amount to pay the loan with
|
|
49
|
+
* @returns {number} The validated payment amount
|
|
50
|
+
*/
|
|
51
|
+
validatePayment(payment?: number): number;
|
|
52
|
+
/**
|
|
53
|
+
* Calculates the minimum payment to pay off the loan in the required number of periods
|
|
54
|
+
* @returns {number} The minimum amount to pay off the loan in the required number of periods
|
|
55
|
+
*/
|
|
56
|
+
calculateMinPayment(): number;
|
|
57
|
+
/**
|
|
58
|
+
* Calculates the amount of interest accrued in a period on a provided balance
|
|
59
|
+
* @param {number} balance The amunt of money owed on a loan
|
|
60
|
+
* @returns {number} The amount of interest accrued in one period
|
|
61
|
+
*/
|
|
62
|
+
accrueInterest(balance?: number): number;
|
|
63
|
+
/**
|
|
64
|
+
* Calculates the number of payments needed to pay off a balance at a provided payemnt amount
|
|
65
|
+
* @param {number} payment The amount to pay the loan with
|
|
66
|
+
* @param {number} balance The amout of money owed on a loan
|
|
67
|
+
* @returns {number} The number of payments neede to pay the loan off
|
|
68
|
+
*/
|
|
69
|
+
numPaymentsToZero(payment?: number, balance?: number): number;
|
|
70
|
+
/**
|
|
71
|
+
* Calculates the amout of pricipal remaining after paying a starting balance with a payment for a number of periods
|
|
72
|
+
* @param {number} periods The number of payemnts to make
|
|
73
|
+
* @param {number} payment The amount to pay the loan with
|
|
74
|
+
* @param {number} balance The amount of money owed on a loan
|
|
75
|
+
* @returns {number} The share of the amount borrowed left to pay
|
|
76
|
+
*/
|
|
77
|
+
principalRemaining(periods: number, payment?: number, balance?: number): number;
|
|
78
|
+
/**
|
|
79
|
+
* Calculates the amount of interest paid after paying a starting balance with a payment for a number of periods
|
|
80
|
+
* @param {number} periods The number of payments to make
|
|
81
|
+
* @param {number} payment The amount to pay the loan with
|
|
82
|
+
* @param {number} balance The amount of money owed on a loan
|
|
83
|
+
* @returns The total amount of interest paid
|
|
84
|
+
*/
|
|
85
|
+
interestPaid(periods: number, payment?: number, balance?: number): number;
|
|
86
|
+
}
|
|
@@ -9,74 +9,8 @@
|
|
|
9
9
|
* This library contains functions used to in personal financial analysis
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
12
|
import * as errors from "./errors";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Calculates the minimum payment to pay the principal back in the number of periods at the periodic rate
|
|
17
|
-
*
|
|
18
|
-
* balance = principal + interest
|
|
19
|
-
*
|
|
20
|
-
* @param {number} principal The amount borrowed
|
|
21
|
-
* @param {number} periodicRate The rate the balance accrues interest at per period
|
|
22
|
-
* @param {number [int]} periods The number of periods the principal is repaid over
|
|
23
|
-
* @returns {number} The minimum payment
|
|
24
|
-
*/
|
|
25
|
-
export function calculateMinPayment(principal, periodicRate, periods) {
|
|
26
|
-
return periodicRate > 0 ?
|
|
27
|
-
principal * (
|
|
28
|
-
(
|
|
29
|
-
periodicRate * (1 + periodicRate) ** periods
|
|
30
|
-
) / (
|
|
31
|
-
(1 + periodicRate) ** periods - 1
|
|
32
|
-
)
|
|
33
|
-
) :
|
|
34
|
-
principal / periods;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Calculates the principal remaining after a certain number of payments from a beginning principal at a periodic rate
|
|
39
|
-
*
|
|
40
|
-
* balance = principal + interest
|
|
41
|
-
*
|
|
42
|
-
* @param {number} principal The amount borrowed
|
|
43
|
-
* @param {number} payment The amount paid at each period
|
|
44
|
-
* @param {number} periodicRate The rate the balance accrues interest at per period
|
|
45
|
-
* @param {number [int]} periods The number of periods paid to compute the desired principal remaining
|
|
46
|
-
* @returns {number} The remaining principal
|
|
47
|
-
*/
|
|
48
|
-
export function principalRemaining(principal, payment, periodicRate, periods) {
|
|
49
|
-
return Math.max(
|
|
50
|
-
(principal * (1 + periodicRate) ** periods) - (
|
|
51
|
-
payment * (
|
|
52
|
-
((1 + periodicRate) ** periods - 1) / (periodicRate)
|
|
53
|
-
)
|
|
54
|
-
),
|
|
55
|
-
0
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Calculates the number of payments required to pay off a principal
|
|
61
|
-
*
|
|
62
|
-
* balance = principal + interest
|
|
63
|
-
*
|
|
64
|
-
* @param {number} principal The amount borrowed
|
|
65
|
-
* @param {number} payment The amount paid at each period
|
|
66
|
-
* @param {number} periodicRate The rate the balance accrues interest at per period
|
|
67
|
-
* @returns The number of payments needed to pay off the principal
|
|
68
|
-
*/
|
|
69
|
-
export function numPaymentsToZero(principal, payment, periodicRate) {
|
|
70
|
-
return Math.ceil(
|
|
71
|
-
Math.log(
|
|
72
|
-
(payment / (payment - principal * periodicRate))
|
|
73
|
-
) / Math.log(periodicRate + 1)
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Represents a financial loan
|
|
79
|
-
*/
|
|
13
|
+
import * as helpers from "./helperFunctions";
|
|
80
14
|
export class Loan {
|
|
81
15
|
/**
|
|
82
16
|
* @constructor
|
|
@@ -94,9 +28,8 @@ export class Loan {
|
|
|
94
28
|
this.periodicRate = this.annualRate / this.periodsPerYear;
|
|
95
29
|
this.periods = this.periodsPerYear * this.termInYears;
|
|
96
30
|
this.minPayment = this.calculateMinPayment();
|
|
97
|
-
this.totalInterest =
|
|
31
|
+
this.totalInterest = this.minPayment * this.periods - this.principal;
|
|
98
32
|
}
|
|
99
|
-
|
|
100
33
|
/**
|
|
101
34
|
* Verifies a payment amount is valid
|
|
102
35
|
* Throws a PaymentTooLowError if the payment amount is less than the loan's minimum payment
|
|
@@ -107,19 +40,18 @@ export class Loan {
|
|
|
107
40
|
validatePayment(payment = this.minPayment) {
|
|
108
41
|
if (payment < this.minPayment) {
|
|
109
42
|
throw new errors.PaymentTooLowError(`payment of ${payment} cannot be less than ${this.minPayment}`);
|
|
110
|
-
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
111
45
|
return payment;
|
|
112
46
|
}
|
|
113
47
|
}
|
|
114
|
-
|
|
115
48
|
/**
|
|
116
49
|
* Calculates the minimum payment to pay off the loan in the required number of periods
|
|
117
50
|
* @returns {number} The minimum amount to pay off the loan in the required number of periods
|
|
118
51
|
*/
|
|
119
52
|
calculateMinPayment() {
|
|
120
|
-
return calculateMinPayment(this.principal, this.periodicRate, this.periods);
|
|
53
|
+
return helpers.calculateMinPayment(this.principal, this.periodicRate, this.periods);
|
|
121
54
|
}
|
|
122
|
-
|
|
123
55
|
/**
|
|
124
56
|
* Calculates the amount of interest accrued in a period on a provided balance
|
|
125
57
|
* @param {number} balance The amunt of money owed on a loan
|
|
@@ -128,7 +60,6 @@ export class Loan {
|
|
|
128
60
|
accrueInterest(balance = this.principal) {
|
|
129
61
|
return balance * this.periodicRate;
|
|
130
62
|
}
|
|
131
|
-
|
|
132
63
|
/**
|
|
133
64
|
* Calculates the number of payments needed to pay off a balance at a provided payemnt amount
|
|
134
65
|
* @param {number} payment The amount to pay the loan with
|
|
@@ -136,14 +67,9 @@ export class Loan {
|
|
|
136
67
|
* @returns {number} The number of payments neede to pay the loan off
|
|
137
68
|
*/
|
|
138
69
|
numPaymentsToZero(payment = this.minPayment, balance = this.principal) {
|
|
139
|
-
|
|
140
|
-
return numPaymentsToZero(
|
|
141
|
-
balance,
|
|
142
|
-
payment,
|
|
143
|
-
this.periodicRate
|
|
144
|
-
);
|
|
70
|
+
this.validatePayment(payment);
|
|
71
|
+
return helpers.numPaymentsToZero(balance, payment, this.periodicRate);
|
|
145
72
|
}
|
|
146
|
-
|
|
147
73
|
/**
|
|
148
74
|
* Calculates the amout of pricipal remaining after paying a starting balance with a payment for a number of periods
|
|
149
75
|
* @param {number} periods The number of payemnts to make
|
|
@@ -152,17 +78,11 @@ export class Loan {
|
|
|
152
78
|
* @returns {number} The share of the amount borrowed left to pay
|
|
153
79
|
*/
|
|
154
80
|
principalRemaining(periods, payment = this.minPayment, balance = this.principal) {
|
|
155
|
-
|
|
156
|
-
return periods < this.numPaymentsToZero(payment, balance)
|
|
157
|
-
principalRemaining(
|
|
158
|
-
|
|
159
|
-
payment,
|
|
160
|
-
this.periodicRate,
|
|
161
|
-
periods
|
|
162
|
-
) :
|
|
163
|
-
0;
|
|
81
|
+
this.validatePayment(payment);
|
|
82
|
+
return periods < this.numPaymentsToZero(payment, balance)
|
|
83
|
+
? helpers.principalRemaining(balance, payment, this.periodicRate, periods)
|
|
84
|
+
: 0;
|
|
164
85
|
}
|
|
165
|
-
|
|
166
86
|
/**
|
|
167
87
|
* Calculates the amount of interest paid after paying a starting balance with a payment for a number of periods
|
|
168
88
|
* @param {number} periods The number of payments to make
|
|
@@ -171,26 +91,13 @@ export class Loan {
|
|
|
171
91
|
* @returns The total amount of interest paid
|
|
172
92
|
*/
|
|
173
93
|
interestPaid(periods, payment = this.minPayment, balance = this.principal) {
|
|
174
|
-
|
|
175
|
-
return periods < this.numPaymentsToZero(payment, balance)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
balance
|
|
183
|
-
)
|
|
184
|
-
) + (
|
|
185
|
-
this.accrueInterest(
|
|
186
|
-
this.principalRemaining(
|
|
187
|
-
this.numPaymentsToZero(payment) - 1,
|
|
188
|
-
payment,
|
|
189
|
-
balance
|
|
190
|
-
)
|
|
191
|
-
)
|
|
192
|
-
),
|
|
193
|
-
0
|
|
194
|
-
);
|
|
94
|
+
this.validatePayment(payment);
|
|
95
|
+
return periods < this.numPaymentsToZero(payment, balance)
|
|
96
|
+
? payment * periods -
|
|
97
|
+
(balance - this.principalRemaining(periods, payment, balance))
|
|
98
|
+
: Math.max(payment * (this.numPaymentsToZero(payment, balance) - 1) -
|
|
99
|
+
(balance -
|
|
100
|
+
this.principalRemaining(this.numPaymentsToZero(payment) - 1, payment, balance)) +
|
|
101
|
+
this.accrueInterest(this.principalRemaining(this.numPaymentsToZero(payment) - 1, payment, balance)), 0);
|
|
195
102
|
}
|
|
196
103
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface AmortizationRecord {
|
|
2
|
+
period: number;
|
|
3
|
+
principal: number;
|
|
4
|
+
interest: number;
|
|
5
|
+
principalRemaining: number;
|
|
6
|
+
}
|
|
7
|
+
export interface PaymentSummary {
|
|
8
|
+
lifetimeInterest: number;
|
|
9
|
+
amortizationSchedule: Array<AmortizationRecord>;
|
|
10
|
+
}
|
|
11
|
+
export interface LoansPaymentSummary {
|
|
12
|
+
[id: string]: PaymentSummary;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* This file contains functions for computing detailed information on paying loans
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
import { ILoan, Loan } from "./loan";
|
|
7
|
+
import { AmortizationRecord, LoansPaymentSummary } from "./paymentTypes";
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* Calculates the extra amount in a payment after all loans' minimum payments are met
|
|
11
|
+
* Throws an exception if the payment provided is less than the collective minimum payments for all loans
|
|
12
|
+
*
|
|
13
|
+
* @param {Array<Loan>} loans The loans to allocate minimum payments
|
|
14
|
+
* @param {number} payment The amount to pay across all loans
|
|
15
|
+
* @returns {number} The extra amount of payment
|
|
16
|
+
*/
|
|
17
|
+
export declare function determineExtraPayment(loans: Array<ILoan>, payment: number): number;
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* Calculates the amortization schedule for a loan paid with a payment
|
|
21
|
+
*
|
|
22
|
+
* @param {Loan} loan The loan to amortize payments for
|
|
23
|
+
* @param {number} payment The amount to pay to the loan's balance each period
|
|
24
|
+
* @param {number} numPayments The number of periods to make payments to the loan
|
|
25
|
+
* @param {number} startPeriod An initial offset of periods to "fast-forward" the state of the loan to prior to calculation of each period
|
|
26
|
+
* @returns {Array<AmortizationRecord>} The amortization schdule for the number of payments of payment made to the loan from the provided start period
|
|
27
|
+
*/
|
|
28
|
+
export declare function amortizePayments(loan: Loan, payment: number, numPayments: number, startPeriod?: number): Array<AmortizationRecord>;
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* Calculates a wealth of information about paying of a set of loans with a total payment amount
|
|
32
|
+
*
|
|
33
|
+
* @param {Array<Loans>} loans The loans to pay off
|
|
34
|
+
* @param {number} payment The total amount of money budgeted to pay all loans each period
|
|
35
|
+
* @param {boolean} reduceMinimum Flag to reduce the total payment amount by a loan's minimum when that loan is paid off
|
|
36
|
+
* @returns {LoansPaymentSummary} Various totals and series of data regarding paying off the loans at the payment amount
|
|
37
|
+
*/
|
|
38
|
+
export declare function payLoans(loans: Array<Loan>, payment: number, reduceMinimum?: boolean): LoansPaymentSummary;
|
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
* This file contains functions for computing detailed information on paying loans
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
6
|
import * as errors from "./errors";
|
|
8
|
-
import * as
|
|
9
|
-
|
|
7
|
+
import * as helpers from "./helperFunctions";
|
|
10
8
|
/**
|
|
11
9
|
*
|
|
12
10
|
* Calculates the extra amount in a payment after all loans' minimum payments are met
|
|
@@ -17,16 +15,12 @@ import * as loanLib from "./loan";
|
|
|
17
15
|
* @returns {number} The extra amount of payment
|
|
18
16
|
*/
|
|
19
17
|
export function determineExtraPayment(loans, payment) {
|
|
20
|
-
const totalMinPayment = loans.reduce(
|
|
21
|
-
(previousValue, currentValue) => previousValue + currentValue.minPayment,
|
|
22
|
-
0
|
|
23
|
-
);
|
|
18
|
+
const totalMinPayment = loans.reduce((previousValue, currentValue) => previousValue + currentValue.minPayment, 0);
|
|
24
19
|
if (totalMinPayment > payment) {
|
|
25
20
|
throw new errors.PaymentTooLowError(`Payment amount of ${payment} must be greater than ${totalMinPayment}`);
|
|
26
21
|
}
|
|
27
22
|
return payment - totalMinPayment;
|
|
28
23
|
}
|
|
29
|
-
|
|
30
24
|
/**
|
|
31
25
|
*
|
|
32
26
|
* Calculates the amortization schedule for a loan paid with a payment
|
|
@@ -35,56 +29,30 @@ export function determineExtraPayment(loans, payment) {
|
|
|
35
29
|
* @param {number} payment The amount to pay to the loan's balance each period
|
|
36
30
|
* @param {number} numPayments The number of periods to make payments to the loan
|
|
37
31
|
* @param {number} startPeriod An initial offset of periods to "fast-forward" the state of the loan to prior to calculation of each period
|
|
38
|
-
* @returns {Array<
|
|
32
|
+
* @returns {Array<AmortizationRecord>} The amortization schdule for the number of payments of payment made to the loan from the provided start period
|
|
39
33
|
*/
|
|
40
|
-
export function amortizePayments(loan, payment
|
|
34
|
+
export function amortizePayments(loan, payment, numPayments, startPeriod = 0) {
|
|
41
35
|
if (payment === null) {
|
|
42
36
|
payment = loan.minPayment;
|
|
43
37
|
}
|
|
44
38
|
payment = loan.validatePayment(payment);
|
|
45
|
-
|
|
46
39
|
if (numPayments === null) {
|
|
47
40
|
numPayments = loan.numPaymentsToZero(payment);
|
|
48
41
|
}
|
|
49
|
-
|
|
50
42
|
let amortizationSchedule = [];
|
|
51
|
-
for (
|
|
52
|
-
let
|
|
53
|
-
period
|
|
54
|
-
period
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
62
|
-
);
|
|
63
|
-
let principalThisPeriod = Math.min(
|
|
64
|
-
payment - interestThisPeriod,
|
|
65
|
-
loan.principalRemaining(
|
|
66
|
-
period,
|
|
67
|
-
payment,
|
|
68
|
-
loan.principalRemaining(startPeriod)
|
|
69
|
-
)
|
|
70
|
-
);
|
|
71
|
-
let principalRemaining = loan.principalRemaining(
|
|
72
|
-
period + 1,
|
|
73
|
-
payment,
|
|
74
|
-
loan.principalRemaining(startPeriod)
|
|
75
|
-
);
|
|
76
|
-
amortizationSchedule.push(
|
|
77
|
-
{
|
|
78
|
-
period: startPeriod + period + 1,
|
|
79
|
-
principal: principalThisPeriod,
|
|
80
|
-
interest: interestThisPeriod,
|
|
81
|
-
principalRemaining: principalRemaining,
|
|
82
|
-
}
|
|
83
|
-
);
|
|
43
|
+
for (let period = 0; period < numPayments; period++) {
|
|
44
|
+
let interestThisPeriod = loan.accrueInterest(loan.principalRemaining(period, payment, loan.principalRemaining(startPeriod)));
|
|
45
|
+
let principalThisPeriod = Math.min(payment - interestThisPeriod, loan.principalRemaining(period, payment, loan.principalRemaining(startPeriod)));
|
|
46
|
+
let principalRemaining = loan.principalRemaining(period + 1, payment, loan.principalRemaining(startPeriod));
|
|
47
|
+
amortizationSchedule.push({
|
|
48
|
+
period: startPeriod + period + 1,
|
|
49
|
+
principal: principalThisPeriod,
|
|
50
|
+
interest: interestThisPeriod,
|
|
51
|
+
principalRemaining: principalRemaining,
|
|
52
|
+
});
|
|
84
53
|
}
|
|
85
54
|
return amortizationSchedule;
|
|
86
55
|
}
|
|
87
|
-
|
|
88
56
|
/**
|
|
89
57
|
*
|
|
90
58
|
* Calculates a wealth of information about paying of a set of loans with a total payment amount
|
|
@@ -97,84 +65,61 @@ export function amortizePayments(loan, payment = null, numPayments = null, start
|
|
|
97
65
|
export function payLoans(loans, payment, reduceMinimum = false) {
|
|
98
66
|
let monthlyPayment = payment;
|
|
99
67
|
let paymentData = {};
|
|
100
|
-
loans.map(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
);
|
|
105
|
-
|
|
68
|
+
loans.map((loan) => {
|
|
69
|
+
paymentData[loan.id] = { lifetimeInterest: 0, amortizationSchedule: [] };
|
|
70
|
+
});
|
|
106
71
|
let periodsElapsed = 0;
|
|
107
72
|
let paidLoans = 0;
|
|
108
73
|
let lifetimeInterest = 0;
|
|
109
74
|
let totalAmortizationSchedule = [];
|
|
110
|
-
|
|
111
75
|
while (paidLoans < loans.length) {
|
|
112
76
|
let firstLoan = loans.slice(paidLoans)[0];
|
|
113
|
-
let firstLoanPayment = firstLoan.minPayment +
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
firstLoan.periodicRate
|
|
118
|
-
);
|
|
119
|
-
let firstLoanInterestPaid = firstLoan.interestPaid(
|
|
120
|
-
periodsToPay,
|
|
121
|
-
firstLoanPayment,
|
|
122
|
-
firstLoan.principalRemaining(periodsElapsed)
|
|
123
|
-
);
|
|
77
|
+
let firstLoanPayment = firstLoan.minPayment +
|
|
78
|
+
determineExtraPayment(loans.slice(paidLoans), monthlyPayment);
|
|
79
|
+
let periodsToPay = helpers.numPaymentsToZero(firstLoan.principalRemaining(periodsElapsed), firstLoanPayment, firstLoan.periodicRate);
|
|
80
|
+
let firstLoanInterestPaid = firstLoan.interestPaid(periodsToPay, firstLoanPayment, firstLoan.principalRemaining(periodsElapsed));
|
|
124
81
|
let firstLoanPaidPeriods = amortizePayments(firstLoan, firstLoanPayment, periodsToPay, periodsElapsed);
|
|
125
|
-
|
|
126
82
|
paymentData[firstLoan.id].lifetimeInterest += firstLoanInterestPaid;
|
|
127
83
|
paymentData[firstLoan.id].amortizationSchedule = [
|
|
128
84
|
...paymentData[firstLoan.id].amortizationSchedule,
|
|
129
|
-
...firstLoanPaidPeriods
|
|
85
|
+
...firstLoanPaidPeriods,
|
|
130
86
|
];
|
|
131
|
-
|
|
132
87
|
totalAmortizationSchedule = [
|
|
133
88
|
...totalAmortizationSchedule,
|
|
134
|
-
...firstLoanPaidPeriods
|
|
89
|
+
...firstLoanPaidPeriods,
|
|
135
90
|
];
|
|
136
|
-
|
|
137
91
|
// the first loan is paid off, handle totals
|
|
138
92
|
paidLoans += 1;
|
|
139
93
|
lifetimeInterest += paymentData[firstLoan.id].lifetimeInterest;
|
|
140
94
|
if (reduceMinimum) {
|
|
141
95
|
monthlyPayment -= firstLoan.minPayment;
|
|
142
96
|
}
|
|
143
|
-
|
|
144
97
|
// handle calculating information for the rest of the loans
|
|
145
98
|
loans.slice(paidLoans).map((loan) => {
|
|
146
|
-
paymentData[loan.id].lifetimeInterest += loan.interestPaid(
|
|
147
|
-
periodsToPay,
|
|
148
|
-
loan.minPayment,
|
|
149
|
-
loan.principalRemaining(periodsElapsed)
|
|
150
|
-
);
|
|
99
|
+
paymentData[loan.id].lifetimeInterest += loan.interestPaid(periodsToPay, loan.minPayment, loan.principalRemaining(periodsElapsed));
|
|
151
100
|
let paidPeriods = amortizePayments(loan, loan.minPayment, periodsToPay, periodsElapsed);
|
|
152
101
|
paymentData[loan.id].amortizationSchedule = [
|
|
153
102
|
...paymentData[loan.id].amortizationSchedule,
|
|
154
|
-
...paidPeriods
|
|
103
|
+
...paidPeriods,
|
|
155
104
|
];
|
|
156
|
-
|
|
157
105
|
totalAmortizationSchedule = totalAmortizationSchedule.map((element) => {
|
|
158
106
|
const matchedInnerElement = paidPeriods.find((innerElement) => innerElement.period === element.period);
|
|
159
|
-
return matchedInnerElement
|
|
160
|
-
{
|
|
107
|
+
return matchedInnerElement
|
|
108
|
+
? {
|
|
161
109
|
period: element.period,
|
|
162
110
|
principal: element.principal + matchedInnerElement.principal,
|
|
163
111
|
interest: element.interest + matchedInnerElement.interest,
|
|
164
|
-
principalRemaining: element.principalRemaining +
|
|
165
|
-
|
|
166
|
-
|
|
112
|
+
principalRemaining: element.principalRemaining +
|
|
113
|
+
matchedInnerElement.principalRemaining,
|
|
114
|
+
}
|
|
115
|
+
: element;
|
|
167
116
|
});
|
|
168
117
|
});
|
|
169
118
|
periodsElapsed += periodsToPay;
|
|
170
119
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
amortizationSchedule: totalAmortizationSchedule
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
|
|
120
|
+
paymentData["totals"] = {
|
|
121
|
+
lifetimeInterest: lifetimeInterest,
|
|
122
|
+
amortizationSchedule: totalAmortizationSchedule,
|
|
123
|
+
};
|
|
179
124
|
return paymentData;
|
|
180
125
|
}
|