moneyfunx 2.2.0 → 3.0.1
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/src/index.d.ts +17 -0
- package/build/src/index.d.ts.map +1 -0
- package/build/src/index.js +16 -0
- package/build/{lib → src/lib}/constants.d.ts +1 -0
- package/build/src/lib/constants.d.ts.map +1 -0
- package/build/src/lib/debt/loan.d.ts +89 -0
- package/build/src/lib/debt/loan.d.ts.map +1 -0
- package/build/src/lib/debt/loan.js +106 -0
- package/build/{lib → src/lib}/debt/paymentTypes.d.ts +1 -0
- package/build/src/lib/debt/paymentTypes.d.ts.map +1 -0
- package/build/{lib → src/lib}/debt/payments.d.ts +3 -2
- package/build/src/lib/debt/payments.d.ts.map +1 -0
- package/build/{lib → src/lib}/debt/payments.js +3 -3
- package/build/{lib → src/lib}/errors.d.ts +4 -0
- package/build/src/lib/errors.d.ts.map +1 -0
- package/build/{lib → src/lib}/errors.js +7 -0
- package/build/{lib → src/lib}/investment/contributionTypes.d.ts +1 -0
- package/build/src/lib/investment/contributionTypes.d.ts.map +1 -0
- package/build/{lib → src/lib}/investment/contributions.d.ts +3 -2
- package/build/src/lib/investment/contributions.d.ts.map +1 -0
- package/build/{lib → src/lib}/investment/contributions.js +6 -2
- package/build/src/lib/investment/instrument.d.ts +70 -0
- package/build/src/lib/investment/instrument.d.ts.map +1 -0
- package/build/src/lib/investment/instrument.js +79 -0
- package/build/src/lib/investment/strategies.d.ts +19 -0
- package/build/src/lib/investment/strategies.d.ts.map +1 -0
- package/build/src/lib/investment/strategies.js +70 -0
- package/build/src/lib/investment/withdrawalTypes.d.ts +17 -0
- package/build/src/lib/investment/withdrawalTypes.d.ts.map +1 -0
- package/build/src/lib/investment/withdrawalTypes.js +1 -0
- package/build/src/lib/investment/withdrawals.d.ts +30 -0
- package/build/src/lib/investment/withdrawals.d.ts.map +1 -0
- package/build/src/lib/investment/withdrawals.js +110 -0
- package/build/src/lib/shared/primitives.d.ts +43 -0
- package/build/src/lib/shared/primitives.d.ts.map +1 -0
- package/build/src/lib/shared/primitives.js +63 -0
- package/build/{lib → src/lib}/shared/sorting.d.ts +13 -10
- package/build/src/lib/shared/sorting.d.ts.map +1 -0
- package/build/{lib → src/lib}/shared/sorting.js +8 -4
- package/coverage/clover.xml +465 -233
- package/coverage/coverage-final.json +11 -8
- package/coverage/index.html +31 -31
- package/coverage/src/index.html +5 -5
- package/coverage/src/index.ts.html +110 -26
- package/coverage/src/lib/constants.ts.html +1 -1
- package/coverage/src/lib/debt/index.html +8 -23
- package/coverage/src/lib/debt/loan.ts.html +146 -113
- package/coverage/src/lib/debt/paymentTypes.ts.html +1 -1
- package/coverage/src/lib/debt/payments.ts.html +10 -7
- package/coverage/src/lib/errors.ts.html +34 -10
- package/coverage/src/lib/index.html +9 -9
- package/coverage/src/lib/investment/contributionTypes.ts.html +4 -4
- package/coverage/src/lib/investment/contributions.ts.html +14 -11
- package/coverage/src/lib/investment/index.html +57 -12
- package/coverage/src/lib/investment/instrument.ts.html +176 -56
- package/coverage/src/lib/investment/strategies.ts.html +385 -0
- package/coverage/src/lib/investment/withdrawalTypes.ts.html +142 -0
- package/coverage/src/lib/investment/withdrawals.ts.html +559 -0
- package/coverage/src/lib/shared/index.html +22 -7
- package/coverage/src/lib/{debt/helperFunctions.ts.html → shared/primitives.ts.html} +136 -103
- package/coverage/src/lib/shared/sorting.ts.html +30 -15
- package/package.json +2 -1
- package/src/index.ts +50 -22
- package/src/lib/debt/loan.ts +95 -84
- package/src/lib/debt/payments.ts +6 -5
- package/src/lib/errors.ts +8 -0
- package/src/lib/investment/contributionTypes.ts +3 -3
- package/src/lib/investment/contributions.ts +8 -7
- package/src/lib/investment/instrument.ts +70 -30
- package/src/lib/investment/strategies.ts +100 -0
- package/src/lib/investment/withdrawalTypes.ts +19 -0
- package/src/lib/investment/withdrawals.ts +158 -0
- package/src/lib/shared/primitives.ts +98 -0
- package/src/lib/shared/sorting.ts +15 -10
- package/tsconfig.json +9 -2
- package/vite.config.js +2 -2
- package/build/index.d.ts +0 -10
- package/build/index.js +0 -9
- package/build/lib/debt/helperFunctions.d.ts +0 -43
- package/build/lib/debt/helperFunctions.js +0 -58
- package/build/lib/debt/loan.d.ts +0 -96
- package/build/lib/debt/loan.js +0 -106
- package/build/lib/investment/instrument.d.ts +0 -52
- package/build/lib/investment/instrument.js +0 -59
- package/src/lib/debt/helperFunctions.ts +0 -87
- /package/build/{lib → src/lib}/constants.js +0 -0
- /package/build/{lib → src/lib}/debt/paymentTypes.js +0 -0
- /package/build/{lib → src/lib}/investment/contributionTypes.js +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MoneyFunx
|
|
3
|
+
* * mek it funx up
|
|
4
|
+
*/
|
|
5
|
+
export { MAX_DURATION_YEARS, TOTALS, } from '@/lib/constants';
|
|
6
|
+
export { ILoan, Loan } from '@/lib/debt/loan';
|
|
7
|
+
export { determineExtraPayment, amortizePayments, payLoans, } from '@/lib/debt/payments';
|
|
8
|
+
export { PaymentRecord, LoansPaymentSchedule, LoanPrincipals, PaymentSchedule, } from '@/lib/debt/paymentTypes';
|
|
9
|
+
export { NegativeContributionError, PaymentTooLowError, NegativeWithdrawalError } from '@/lib/errors';
|
|
10
|
+
export { amortizeContributions, contributeInstruments, determineExtraContribution, } from '@/lib/investment/contributions';
|
|
11
|
+
export { ContributionRecord, ContributionSchedule, InstrumentsContributionSchedule, } from '@/lib/investment/contributionTypes';
|
|
12
|
+
export { IInstrument, Instrument } from '@/lib/investment/instrument';
|
|
13
|
+
export { calculateAmortizedWithdrawal, drawdownInstruments, } from '@/lib/investment/withdrawals';
|
|
14
|
+
export { WithdrawalRecord, WithdrawalSchedule, InstrumentsWithdrawalSchedule, } from '@/lib/investment/withdrawalTypes';
|
|
15
|
+
export { calculatePeriodicAmount, calculateBalanceRemaining, calculatePeriodsToZero, calculateInterestOverPeriods, } from '@/lib/shared/primitives';
|
|
16
|
+
export { HasRateAndBalance, snowball, avalanche, sortWith } from '@/lib/shared/sorting';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,kBAAkB,EAClB,MAAM,GACP,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,QAAQ,GACT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEtG,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,+BAA+B,GAChC,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EACL,4BAA4B,EAC5B,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,6BAA6B,GAC9B,MAAM,kCAAkC,CAAC;AAM1C,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MoneyFunx
|
|
3
|
+
* * mek it funx up
|
|
4
|
+
*/
|
|
5
|
+
export { MAX_DURATION_YEARS, TOTALS, } from '@/lib/constants';
|
|
6
|
+
export { Loan } from '@/lib/debt/loan';
|
|
7
|
+
export { determineExtraPayment, amortizePayments, payLoans, } from '@/lib/debt/payments';
|
|
8
|
+
export { NegativeContributionError, PaymentTooLowError, NegativeWithdrawalError } from '@/lib/errors';
|
|
9
|
+
export { amortizeContributions, contributeInstruments, determineExtraContribution, } from '@/lib/investment/contributions';
|
|
10
|
+
export { Instrument } from '@/lib/investment/instrument';
|
|
11
|
+
export { calculateAmortizedWithdrawal, drawdownInstruments, } from '@/lib/investment/withdrawals';
|
|
12
|
+
// export {
|
|
13
|
+
// performWaterfallDrawdown,
|
|
14
|
+
// } from '@/lib/investment/strategies';
|
|
15
|
+
export { calculatePeriodicAmount, calculateBalanceRemaining, calculatePeriodsToZero, calculateInterestOverPeriods, } from '@/lib/shared/primitives';
|
|
16
|
+
export { snowball, avalanche, sortWith } from '@/lib/shared/sorting';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,MAAM,WAAW,CAAC;AAG/B,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,gBAAgB,OAAO,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a financial loan and provides methods for amortization and
|
|
3
|
+
* interest calculations.
|
|
4
|
+
*/
|
|
5
|
+
import { HasRateAndBalance } from '@/lib/shared/sorting';
|
|
6
|
+
export interface ILoan extends HasRateAndBalance {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
principal: number;
|
|
10
|
+
annualRate: number;
|
|
11
|
+
periodsPerYear: number;
|
|
12
|
+
termInYears: number;
|
|
13
|
+
periodicRate: number;
|
|
14
|
+
periods: number;
|
|
15
|
+
minPayment: number;
|
|
16
|
+
currentBalance: number;
|
|
17
|
+
fees: number;
|
|
18
|
+
}
|
|
19
|
+
export declare class Loan implements ILoan {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
principal: number;
|
|
23
|
+
annualRate: number;
|
|
24
|
+
periodsPerYear: number;
|
|
25
|
+
termInYears: number;
|
|
26
|
+
periodicRate: number;
|
|
27
|
+
periods: number;
|
|
28
|
+
minPayment: number;
|
|
29
|
+
currentBalance: number;
|
|
30
|
+
fees: number;
|
|
31
|
+
/**
|
|
32
|
+
* @constructor
|
|
33
|
+
* @param {number} principal - The initial amount borrowed.
|
|
34
|
+
* @param {number} annualRate - The yearly interest rate (decimal).
|
|
35
|
+
* @param {number} periodsPerYear - Frequency of interest accrual per year.
|
|
36
|
+
* @param {number} termInYears - Total lifespan of the loan in years.
|
|
37
|
+
* @param {string} name - Identifying name for the loan.
|
|
38
|
+
* @param {number} [currentBalance] - The current outstanding balance.
|
|
39
|
+
* @param {number} [fees] - Any applicable loan fees.
|
|
40
|
+
*/
|
|
41
|
+
constructor(principal: number, annualRate: number, periodsPerYear: number, termInYears: number, name: string, currentBalance?: number, fees?: number);
|
|
42
|
+
/**
|
|
43
|
+
* Validates that a payment amount meets the minimum requirement.
|
|
44
|
+
*
|
|
45
|
+
* @param {number} paymentAmount - The amount intended to be paid.
|
|
46
|
+
* @throws {errors.PaymentTooLowError} If the payment is less than the minimum.
|
|
47
|
+
* @returns {number} The validated payment amount.
|
|
48
|
+
*/
|
|
49
|
+
validatePayment(paymentAmount?: number): number;
|
|
50
|
+
/**
|
|
51
|
+
* Calculates the minimum payment required to amortize the loan over its term.
|
|
52
|
+
* * @returns {number} The minimum periodic payment.
|
|
53
|
+
*/
|
|
54
|
+
calculateMinPayment(): number;
|
|
55
|
+
/**
|
|
56
|
+
* Calculates interest accrued on a specific balance for one period.
|
|
57
|
+
*
|
|
58
|
+
* @param {number} [targetBalance=this.currentBalance] - The balance to accrue interest on.
|
|
59
|
+
* @returns {number} The interest accrued.
|
|
60
|
+
*/
|
|
61
|
+
accrueInterest(targetBalance?: number): number;
|
|
62
|
+
/**
|
|
63
|
+
* Determines the number of periods remaining until the loan reaches a zero balance.
|
|
64
|
+
*
|
|
65
|
+
* @param {number} [paymentAmount=this.minPayment] - Periodic payment amount.
|
|
66
|
+
* @param {number} [targetBalance=this.currentBalance] - Balance to calculate against.
|
|
67
|
+
* @returns {number} Number of periods to zero.
|
|
68
|
+
*/
|
|
69
|
+
numPaymentsToZero(paymentAmount?: number, targetBalance?: number): number;
|
|
70
|
+
/**
|
|
71
|
+
* Calculates the balance remaining after a set number of periods.
|
|
72
|
+
*
|
|
73
|
+
* @param {number} periodsElapsed - Number of periods that have passed.
|
|
74
|
+
* @param {number} [paymentAmount=this.minPayment] - Periodic payment amount.
|
|
75
|
+
* @param {number} [targetBalance=this.currentBalance] - Starting balance.
|
|
76
|
+
* @returns {number} The remaining principal balance.
|
|
77
|
+
*/
|
|
78
|
+
principalRemaining(periodsElapsed: number, paymentAmount?: number, targetBalance?: number): number;
|
|
79
|
+
/**
|
|
80
|
+
* Calculates the total interest paid over a specified number of periods.
|
|
81
|
+
*
|
|
82
|
+
* @param {number} periodsElapsed - Number of periods paid.
|
|
83
|
+
* @param {number} [paymentAmount=this.minPayment] - Periodic payment amount.
|
|
84
|
+
* @param {number} [targetBalance=this.currentBalance] - Starting balance.
|
|
85
|
+
* @returns {number} Total interest paid.
|
|
86
|
+
*/
|
|
87
|
+
interestPaid(periodsElapsed: number, paymentAmount?: number, targetBalance?: number): number;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=loan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loan.d.ts","sourceRoot":"","sources":["../../../../src/lib/debt/loan.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,WAAW,KAAM,SAAQ,iBAAiB;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,IAAK,YAAW,KAAK;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;;;;;OASG;gBAED,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,cAAc,CAAC,EAAE,MAAM,EACvB,IAAI,CAAC,EAAE,MAAM;IAef;;;;;;OAMG;IACH,eAAe,CAAC,aAAa,GAAE,MAAwB,GAAG,MAAM;IAYhE;;;OAGG;IACH,mBAAmB,IAAI,MAAM;IAQ7B;;;;;OAKG;IACH,cAAc,CAAC,aAAa,GAAE,MAA4B,GAAG,MAAM;IAInE;;;;;;OAMG;IACH,iBAAiB,CACf,aAAa,GAAE,MAAwB,EACvC,aAAa,GAAE,MAA4B,GAC1C,MAAM;IAST;;;;;;;OAOG;IACH,kBAAkB,CAChB,cAAc,EAAE,MAAM,EACtB,aAAa,GAAE,MAAwB,EACvC,aAAa,GAAE,MAA4B,GAC1C,MAAM;IAcT;;;;;;;OAOG;IACH,YAAY,CACV,cAAc,EAAE,MAAM,EACtB,aAAa,GAAE,MAAwB,EACvC,aAAa,GAAE,MAA4B,GAC1C,MAAM;CAyBV"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a financial loan and provides methods for amortization and
|
|
3
|
+
* interest calculations.
|
|
4
|
+
*/
|
|
5
|
+
import * as errors from '@/lib/errors';
|
|
6
|
+
import * as primitives from '@/lib/shared/primitives';
|
|
7
|
+
export class Loan {
|
|
8
|
+
/**
|
|
9
|
+
* @constructor
|
|
10
|
+
* @param {number} principal - The initial amount borrowed.
|
|
11
|
+
* @param {number} annualRate - The yearly interest rate (decimal).
|
|
12
|
+
* @param {number} periodsPerYear - Frequency of interest accrual per year.
|
|
13
|
+
* @param {number} termInYears - Total lifespan of the loan in years.
|
|
14
|
+
* @param {string} name - Identifying name for the loan.
|
|
15
|
+
* @param {number} [currentBalance] - The current outstanding balance.
|
|
16
|
+
* @param {number} [fees] - Any applicable loan fees.
|
|
17
|
+
*/
|
|
18
|
+
constructor(principal, annualRate, periodsPerYear, termInYears, name, currentBalance, fees) {
|
|
19
|
+
this.id = String(Math.floor(Math.random() * Date.now()));
|
|
20
|
+
this.name = name;
|
|
21
|
+
this.principal = principal;
|
|
22
|
+
this.annualRate = annualRate;
|
|
23
|
+
this.periodsPerYear = periodsPerYear;
|
|
24
|
+
this.termInYears = termInYears;
|
|
25
|
+
this.periodicRate = this.annualRate / this.periodsPerYear;
|
|
26
|
+
this.periods = this.periodsPerYear * this.termInYears;
|
|
27
|
+
this.minPayment = this.calculateMinPayment();
|
|
28
|
+
this.currentBalance = currentBalance !== undefined ? currentBalance : principal;
|
|
29
|
+
this.fees = fees || 0;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Validates that a payment amount meets the minimum requirement.
|
|
33
|
+
*
|
|
34
|
+
* @param {number} paymentAmount - The amount intended to be paid.
|
|
35
|
+
* @throws {errors.PaymentTooLowError} If the payment is less than the minimum.
|
|
36
|
+
* @returns {number} The validated payment amount.
|
|
37
|
+
*/
|
|
38
|
+
validatePayment(paymentAmount = this.minPayment) {
|
|
39
|
+
const normalizedMinimum = parseInt((100 * this.minPayment).toFixed());
|
|
40
|
+
const normalizedPayment = parseInt((100 * paymentAmount).toFixed());
|
|
41
|
+
if (normalizedMinimum > normalizedPayment) {
|
|
42
|
+
throw new errors.PaymentTooLowError(`payment of ${paymentAmount} cannot be less than ${this.minPayment}`);
|
|
43
|
+
}
|
|
44
|
+
return paymentAmount;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Calculates the minimum payment required to amortize the loan over its term.
|
|
48
|
+
* * @returns {number} The minimum periodic payment.
|
|
49
|
+
*/
|
|
50
|
+
calculateMinPayment() {
|
|
51
|
+
return primitives.calculatePeriodicAmount(this.principal, this.periodicRate, this.periods);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Calculates interest accrued on a specific balance for one period.
|
|
55
|
+
*
|
|
56
|
+
* @param {number} [targetBalance=this.currentBalance] - The balance to accrue interest on.
|
|
57
|
+
* @returns {number} The interest accrued.
|
|
58
|
+
*/
|
|
59
|
+
accrueInterest(targetBalance = this.currentBalance) {
|
|
60
|
+
return targetBalance * this.periodicRate;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Determines the number of periods remaining until the loan reaches a zero balance.
|
|
64
|
+
*
|
|
65
|
+
* @param {number} [paymentAmount=this.minPayment] - Periodic payment amount.
|
|
66
|
+
* @param {number} [targetBalance=this.currentBalance] - Balance to calculate against.
|
|
67
|
+
* @returns {number} Number of periods to zero.
|
|
68
|
+
*/
|
|
69
|
+
numPaymentsToZero(paymentAmount = this.minPayment, targetBalance = this.currentBalance) {
|
|
70
|
+
this.validatePayment(paymentAmount);
|
|
71
|
+
return primitives.calculatePeriodsToZero(targetBalance, paymentAmount, this.periodicRate);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Calculates the balance remaining after a set number of periods.
|
|
75
|
+
*
|
|
76
|
+
* @param {number} periodsElapsed - Number of periods that have passed.
|
|
77
|
+
* @param {number} [paymentAmount=this.minPayment] - Periodic payment amount.
|
|
78
|
+
* @param {number} [targetBalance=this.currentBalance] - Starting balance.
|
|
79
|
+
* @returns {number} The remaining principal balance.
|
|
80
|
+
*/
|
|
81
|
+
principalRemaining(periodsElapsed, paymentAmount = this.minPayment, targetBalance = this.currentBalance) {
|
|
82
|
+
this.validatePayment(paymentAmount);
|
|
83
|
+
const periodsToZero = this.numPaymentsToZero(paymentAmount, targetBalance);
|
|
84
|
+
return periodsElapsed < periodsToZero
|
|
85
|
+
? primitives.calculateBalanceRemaining(targetBalance, paymentAmount, this.periodicRate, periodsElapsed)
|
|
86
|
+
: 0;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Calculates the total interest paid over a specified number of periods.
|
|
90
|
+
*
|
|
91
|
+
* @param {number} periodsElapsed - Number of periods paid.
|
|
92
|
+
* @param {number} [paymentAmount=this.minPayment] - Periodic payment amount.
|
|
93
|
+
* @param {number} [targetBalance=this.currentBalance] - Starting balance.
|
|
94
|
+
* @returns {number} Total interest paid.
|
|
95
|
+
*/
|
|
96
|
+
interestPaid(periodsElapsed, paymentAmount = this.minPayment, targetBalance = this.currentBalance) {
|
|
97
|
+
this.validatePayment(paymentAmount);
|
|
98
|
+
const totalPeriodsToZero = this.numPaymentsToZero(paymentAmount, targetBalance);
|
|
99
|
+
if (periodsElapsed < totalPeriodsToZero) {
|
|
100
|
+
return primitives.calculateInterestOverPeriods(targetBalance, paymentAmount, this.periodicRate, periodsElapsed);
|
|
101
|
+
}
|
|
102
|
+
const lastFullPeriod = totalPeriodsToZero - 1;
|
|
103
|
+
const finalInterestAccrual = this.accrueInterest(this.principalRemaining(lastFullPeriod, paymentAmount, targetBalance));
|
|
104
|
+
return primitives.calculateInterestOverPeriods(targetBalance, paymentAmount, this.periodicRate, lastFullPeriod) + finalInterestAccrual;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paymentTypes.d.ts","sourceRoot":"","sources":["../../../../src/lib/debt/paymentTypes.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,aAAa,EAAE,CAAC;CACvC,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEnE,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC"}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* This file contains functions for computing detailed information on paying loans
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
|
-
import type { ILoan, Loan } from '
|
|
7
|
-
import type { PaymentRecord, LoansPaymentSchedule } from '
|
|
6
|
+
import type { ILoan, Loan } from '@/lib/debt/loan';
|
|
7
|
+
import type { PaymentRecord, LoansPaymentSchedule } from '@/lib/debt/paymentTypes';
|
|
8
8
|
/**
|
|
9
9
|
*
|
|
10
10
|
* Calculates the extra amount in a payment after all loans' minimum payments are met
|
|
@@ -50,3 +50,4 @@ export declare function amortizePayments(loan: Loan, principal: number, payment:
|
|
|
50
50
|
*
|
|
51
51
|
*/
|
|
52
52
|
export declare function payLoans(loans: Loan[], payment: number, reduceMinimum?: boolean): LoansPaymentSchedule;
|
|
53
|
+
//# sourceMappingURL=payments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payments.d.ts","sourceRoot":"","sources":["../../../../src/lib/debt/payments.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EACV,aAAa,EAEb,oBAAoB,EACrB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,KAAK,EAAE,EACd,OAAO,EAAE,MAAM,GACd,MAAM,CAYR;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,EACxB,aAAa,EAAE,OAAO,GACrB,MAAM,CAOR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GAAC,IAAI,EACpB,WAAW,EAAE,MAAM,GAAC,IAAI,EACxB,WAAW,GAAE,MAAU,EACvB,SAAS,GAAE,MAAU,GACpB,aAAa,EAAE,CA+BjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,EAAE,MAAM,EACf,aAAa,GAAE,OAAe,GAC7B,oBAAoB,CAqItB"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* This file contains functions for computing detailed information on paying loans
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
|
-
import * as errors from '
|
|
6
|
+
import * as errors from '@/lib/errors';
|
|
7
7
|
/**
|
|
8
8
|
*
|
|
9
9
|
* Calculates the extra amount in a payment after all loans' minimum payments are met
|
|
@@ -105,8 +105,8 @@ export function payLoans(loans, payment, reduceMinimum = false) {
|
|
|
105
105
|
let totalAmortizationSchedule = [];
|
|
106
106
|
while (paidLoans < loans.length) {
|
|
107
107
|
const firstLoan = loans.slice(paidLoans)[0];
|
|
108
|
-
const firstLoanPayment = firstLoan.minPayment +
|
|
109
|
-
determineExtraPayment(loans.slice(paidLoans), monthlyPayment);
|
|
108
|
+
const firstLoanPayment = (firstLoan.minPayment +
|
|
109
|
+
determineExtraPayment(loans.slice(paidLoans), monthlyPayment));
|
|
110
110
|
const firstLoanPrincipalRemaining = loanPrincipalsRemaining[firstLoan.id];
|
|
111
111
|
const periodsToPay = firstLoan.numPaymentsToZero(firstLoanPayment, firstLoanPrincipalRemaining);
|
|
112
112
|
const firstLoanAmortizedPayments = amortizePayments(firstLoan, firstLoanPrincipalRemaining, firstLoanPayment, periodsToPay, periodsElapsed);
|
|
@@ -4,3 +4,7 @@ export declare class PaymentTooLowError extends Error {
|
|
|
4
4
|
export declare class NegativeContributionError extends Error {
|
|
5
5
|
constructor(message: string);
|
|
6
6
|
}
|
|
7
|
+
export declare class NegativeWithdrawalError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAK5B;AAED,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,OAAO,EAAE,MAAM;CAK5B;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAK5B"}
|
|
@@ -12,3 +12,10 @@ export class NegativeContributionError extends Error {
|
|
|
12
12
|
this.name = 'NegativeContributionError';
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
export class NegativeWithdrawalError extends Error {
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
Object.setPrototypeOf(this, NegativeWithdrawalError.prototype);
|
|
19
|
+
this.name = 'NegativeWithdrawalError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -31,3 +31,4 @@ export type ContributionSchedule = {
|
|
|
31
31
|
export type InstrumentsContributionSchedule = Record<string, ContributionSchedule>;
|
|
32
32
|
export type InstrumentBalances = Record<string, number>;
|
|
33
33
|
export type InstrumentYTDs = Record<string, number>;
|
|
34
|
+
//# sourceMappingURL=contributionTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contributionTypes.d.ts","sourceRoot":"","sources":["../../../../src/lib/investment/contributionTypes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,kBAAkB,EAAE,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AAEnF,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC"}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* This file containts functions for computing detailed information on contributing to investments
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
|
-
import type { Instrument } from '
|
|
7
|
-
import { ContributionRecord, InstrumentsContributionSchedule } from '
|
|
6
|
+
import type { Instrument } from '@/lib/investment/instrument';
|
|
7
|
+
import { ContributionRecord, InstrumentsContributionSchedule } from '@/lib/investment/contributionTypes';
|
|
8
8
|
/**
|
|
9
9
|
*
|
|
10
10
|
* @param {IInstrument[]} instruments The instruments to allocate maximum contributions
|
|
@@ -50,3 +50,4 @@ export declare function amortizeContributions(instrument: Instrument, initialBal
|
|
|
50
50
|
* @returns {InstrumentsContributionSchedule} The amortized contributions for all instruments
|
|
51
51
|
*/
|
|
52
52
|
export declare function contributeInstruments(instruments: Instrument[], contribution: number, numContributions: number, accrueBeforeContribution?: boolean): InstrumentsContributionSchedule;
|
|
53
|
+
//# sourceMappingURL=contributions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contributions.d.ts","sourceRoot":"","sources":["../../../../src/lib/investment/contributions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EACL,kBAAkB,EAClB,+BAA+B,EAGhC,MAAM,oCAAoC,CAAC;AAE5C;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,UAAU,EAAE,EACzB,YAAY,EAAE,MAAM,GACnB,MAAM,CAMR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,WAAW,GAAE,MAAU,EACvB,wBAAwB,GAAE,OAAc,GACvC,kBAAkB,CAgBpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,WAAW,GAAE,MAAU,EACvB,wBAAwB,GAAE,OAAc,GACvC,kBAAkB,EAAE,CAkBtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,UAAU,EAAE,EACzB,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,wBAAwB,GAAE,OAAc,GACvC,+BAA+B,CA6FjC"}
|
|
@@ -13,6 +13,7 @@ export function determineExtraContribution(instruments, contribution) {
|
|
|
13
13
|
const totalMaxPayment = instruments.reduce((accumulator, instrument) => accumulator + instrument.periodicContribution(), 0);
|
|
14
14
|
return Math.max(contribution - totalMaxPayment, 0);
|
|
15
15
|
}
|
|
16
|
+
;
|
|
16
17
|
/**
|
|
17
18
|
*
|
|
18
19
|
* @param {Instrument} instrument The Instrument to contribute to
|
|
@@ -42,6 +43,7 @@ export function amortizeContribution(instrument, currentBalance, contribution, s
|
|
|
42
43
|
currentBalance,
|
|
43
44
|
};
|
|
44
45
|
}
|
|
46
|
+
;
|
|
45
47
|
/**
|
|
46
48
|
*
|
|
47
49
|
* Calculates the amortization schedule for an instrument with a contribution
|
|
@@ -81,6 +83,7 @@ export function amortizeContributions(instrument, initialBalance, contribution,
|
|
|
81
83
|
* @returns {InstrumentsContributionSchedule} The amortized contributions for all instruments
|
|
82
84
|
*/
|
|
83
85
|
export function contributeInstruments(instruments, contribution, numContributions, accrueBeforeContribution = true) {
|
|
86
|
+
// state setup
|
|
84
87
|
const contributionSchedules = {};
|
|
85
88
|
const instrumentBalances = {};
|
|
86
89
|
const instrumentYTDs = {};
|
|
@@ -96,11 +99,11 @@ export function contributeInstruments(instruments, contribution, numContribution
|
|
|
96
99
|
instrumentBalances[instrument.id] = instrument.currentBalance;
|
|
97
100
|
instrumentYTDs[instrument.id] = 0;
|
|
98
101
|
});
|
|
99
|
-
// algorithm
|
|
102
|
+
// algorithm to build contributionSchedules
|
|
100
103
|
for (let period = 0; period < numContributions; period++) {
|
|
101
104
|
let periodicContribution = contribution;
|
|
102
105
|
for (const instrument of instruments) {
|
|
103
|
-
if (period %
|
|
106
|
+
if (period % instrument.periodsPerYear == 1) {
|
|
104
107
|
instrumentYTDs[instrument.id] = 0;
|
|
105
108
|
}
|
|
106
109
|
const validContribution = instrument.validateContribution(Math.min(periodicContribution, instrument.periodicContribution()), instrumentYTDs[instrument.id]);
|
|
@@ -145,3 +148,4 @@ export function contributeInstruments(instruments, contribution, numContribution
|
|
|
145
148
|
};
|
|
146
149
|
return contributionSchedules;
|
|
147
150
|
}
|
|
151
|
+
;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a financial instrument for investments and drawdowns.
|
|
3
|
+
*/
|
|
4
|
+
import { HasRateAndBalance } from '@/lib/shared/sorting';
|
|
5
|
+
export interface IInstrument extends HasRateAndBalance {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
currentBalance: number;
|
|
9
|
+
annualRate: number;
|
|
10
|
+
periodsPerYear: number;
|
|
11
|
+
periodicRate: number;
|
|
12
|
+
annualLimit: number;
|
|
13
|
+
}
|
|
14
|
+
export declare class Instrument implements IInstrument {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
currentBalance: number;
|
|
18
|
+
annualRate: number;
|
|
19
|
+
periodsPerYear: number;
|
|
20
|
+
periodicRate: number;
|
|
21
|
+
annualLimit: number;
|
|
22
|
+
/**
|
|
23
|
+
* @constructor
|
|
24
|
+
* @param {number} currentBalance - Initial balance of the instrument.
|
|
25
|
+
* @param {number} annualRate - The yearly expected return or interest rate.
|
|
26
|
+
* @param {number} periodsPerYear - Number of accrual periods per year.
|
|
27
|
+
* @param {string} name - Name of the investment instrument.
|
|
28
|
+
* @param {number} [annualLimit=0] - Maximum allowable contribution per year.
|
|
29
|
+
*/
|
|
30
|
+
constructor(currentBalance: number, annualRate: number, periodsPerYear: number, name: string, annualLimit?: number);
|
|
31
|
+
/**
|
|
32
|
+
* Validates a contribution against limits and negative values.
|
|
33
|
+
*
|
|
34
|
+
* @param {number} contribution - Amount to contribute.
|
|
35
|
+
* @param {number} yearToDateContribution - Current contributions for the calendar year.
|
|
36
|
+
* @throws {errors.NegativeContributionError} If contribution is less than zero.
|
|
37
|
+
* @returns {number} The allowed contribution amount.
|
|
38
|
+
*/
|
|
39
|
+
validateContribution(contribution: number, yearToDateContribution: number): number;
|
|
40
|
+
/**
|
|
41
|
+
* Determines the number of periods remaining until the balance reaches zero during drawdown.
|
|
42
|
+
*
|
|
43
|
+
* @param {number} periodicWithdrawalAmount - The amount withdrawn each period.
|
|
44
|
+
* @param {number} [targetBalance=this.currentBalance] - The balance to draw from.
|
|
45
|
+
* @returns {number} Number of periods to depletion.
|
|
46
|
+
*/
|
|
47
|
+
numWithdrawalsToZero(periodicWithdrawalAmount: number, targetBalance?: number): number;
|
|
48
|
+
/**
|
|
49
|
+
* Calculates the maximum sustainable periodic withdrawal for a set duration.
|
|
50
|
+
*
|
|
51
|
+
* @param {number} totalDurationInPeriods - The number of periods the balance must last.
|
|
52
|
+
* @param {number} [targetBalance=this.currentBalance] - The starting balance.
|
|
53
|
+
* @returns {number} The calculated periodic withdrawal amount.
|
|
54
|
+
*/
|
|
55
|
+
calculateMaxWithdrawal(totalDurationInPeriods: number, targetBalance?: number): number;
|
|
56
|
+
/**
|
|
57
|
+
* Helper to calculate the maximum periodic contribution allowed by the annual limit.
|
|
58
|
+
*
|
|
59
|
+
* @returns {number} The amortized periodic limit.
|
|
60
|
+
*/
|
|
61
|
+
periodicContribution(): number;
|
|
62
|
+
/**
|
|
63
|
+
* Calculates the growth/interest accrued in one period.
|
|
64
|
+
*
|
|
65
|
+
* @param {number} [targetBalance=this.currentBalance] - The balance to calculate growth on.
|
|
66
|
+
* @returns {number} The growth amount.
|
|
67
|
+
*/
|
|
68
|
+
accrueInterest(targetBalance?: number): number;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=instrument.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrument.d.ts","sourceRoot":"","sources":["../../../../src/lib/investment/instrument.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGzD,MAAM,WAAW,WAAY,SAAQ,iBAAiB;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,UAAW,YAAW,WAAW;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;;;OAOG;gBAED,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,WAAW,GAAE,MAAU;IAWzB;;;;;;;OAOG;IACH,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,GAAG,MAAM;IAmBlF;;;;;;OAMG;IACH,oBAAoB,CAClB,wBAAwB,EAAE,MAAM,EAChC,aAAa,GAAE,MAA4B,GAC1C,MAAM;IAQT;;;;;;OAMG;IACH,sBAAsB,CACpB,sBAAsB,EAAE,MAAM,EAC9B,aAAa,GAAE,MAA4B,GAC1C,MAAM;IAQT;;;;OAIG;IACH,oBAAoB,IAAI,MAAM;IAI9B;;;;;OAKG;IACH,cAAc,CAAC,aAAa,GAAE,MAA4B,GAAG,MAAM;CAGpE"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a financial instrument for investments and drawdowns.
|
|
3
|
+
*/
|
|
4
|
+
import * as errors from '@/lib/errors';
|
|
5
|
+
import * as primitives from '@/lib/shared/primitives';
|
|
6
|
+
export class Instrument {
|
|
7
|
+
/**
|
|
8
|
+
* @constructor
|
|
9
|
+
* @param {number} currentBalance - Initial balance of the instrument.
|
|
10
|
+
* @param {number} annualRate - The yearly expected return or interest rate.
|
|
11
|
+
* @param {number} periodsPerYear - Number of accrual periods per year.
|
|
12
|
+
* @param {string} name - Name of the investment instrument.
|
|
13
|
+
* @param {number} [annualLimit=0] - Maximum allowable contribution per year.
|
|
14
|
+
*/
|
|
15
|
+
constructor(currentBalance, annualRate, periodsPerYear, name, annualLimit = 0) {
|
|
16
|
+
this.id = String(Math.floor(Math.random() * Date.now()));
|
|
17
|
+
this.name = name;
|
|
18
|
+
this.currentBalance = currentBalance;
|
|
19
|
+
this.annualRate = annualRate;
|
|
20
|
+
this.periodsPerYear = periodsPerYear;
|
|
21
|
+
this.periodicRate = this.annualRate / this.periodsPerYear;
|
|
22
|
+
this.annualLimit = annualLimit;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validates a contribution against limits and negative values.
|
|
26
|
+
*
|
|
27
|
+
* @param {number} contribution - Amount to contribute.
|
|
28
|
+
* @param {number} yearToDateContribution - Current contributions for the calendar year.
|
|
29
|
+
* @throws {errors.NegativeContributionError} If contribution is less than zero.
|
|
30
|
+
* @returns {number} The allowed contribution amount.
|
|
31
|
+
*/
|
|
32
|
+
validateContribution(contribution, yearToDateContribution) {
|
|
33
|
+
if (contribution < 0) {
|
|
34
|
+
throw new errors.NegativeContributionError(`contribution of ${contribution} must be greater than/equal to zero`);
|
|
35
|
+
}
|
|
36
|
+
if (this.annualLimit > 0) {
|
|
37
|
+
const remainingAnnualCapacity = Math.max(this.annualLimit - yearToDateContribution, 0);
|
|
38
|
+
return Math.min(remainingAnnualCapacity, contribution, this.periodicContribution());
|
|
39
|
+
}
|
|
40
|
+
return contribution;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Determines the number of periods remaining until the balance reaches zero during drawdown.
|
|
44
|
+
*
|
|
45
|
+
* @param {number} periodicWithdrawalAmount - The amount withdrawn each period.
|
|
46
|
+
* @param {number} [targetBalance=this.currentBalance] - The balance to draw from.
|
|
47
|
+
* @returns {number} Number of periods to depletion.
|
|
48
|
+
*/
|
|
49
|
+
numWithdrawalsToZero(periodicWithdrawalAmount, targetBalance = this.currentBalance) {
|
|
50
|
+
return primitives.calculatePeriodsToZero(targetBalance, periodicWithdrawalAmount, this.periodicRate);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Calculates the maximum sustainable periodic withdrawal for a set duration.
|
|
54
|
+
*
|
|
55
|
+
* @param {number} totalDurationInPeriods - The number of periods the balance must last.
|
|
56
|
+
* @param {number} [targetBalance=this.currentBalance] - The starting balance.
|
|
57
|
+
* @returns {number} The calculated periodic withdrawal amount.
|
|
58
|
+
*/
|
|
59
|
+
calculateMaxWithdrawal(totalDurationInPeriods, targetBalance = this.currentBalance) {
|
|
60
|
+
return primitives.calculatePeriodicAmount(targetBalance, this.periodicRate, totalDurationInPeriods);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Helper to calculate the maximum periodic contribution allowed by the annual limit.
|
|
64
|
+
*
|
|
65
|
+
* @returns {number} The amortized periodic limit.
|
|
66
|
+
*/
|
|
67
|
+
periodicContribution() {
|
|
68
|
+
return this.annualLimit > 0 ? this.annualLimit / this.periodsPerYear : 0;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Calculates the growth/interest accrued in one period.
|
|
72
|
+
*
|
|
73
|
+
* @param {number} [targetBalance=this.currentBalance] - The balance to calculate growth on.
|
|
74
|
+
* @returns {number} The growth amount.
|
|
75
|
+
*/
|
|
76
|
+
accrueInterest(targetBalance = this.currentBalance) {
|
|
77
|
+
return targetBalance * this.periodicRate;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file contains high-level drawdown strategies for investment portfolios.
|
|
3
|
+
*/
|
|
4
|
+
import { Instrument } from '@/lib/investment/instrument';
|
|
5
|
+
import { InstrumentsWithdrawalSchedule } from '@/lib/investment/withdrawalTypes';
|
|
6
|
+
/**
|
|
7
|
+
* Executes a 'Waterfall' drawdown strategy.
|
|
8
|
+
* Funds are pulled from instruments in the order they appear in the array.
|
|
9
|
+
* The next instrument is only touched if the previous one cannot fulfill the
|
|
10
|
+
* remaining target net income.
|
|
11
|
+
*
|
|
12
|
+
* @param {Instrument[]} financialInstruments - Ordered list of accounts (e.g., Taxable -> Tax-Deferred).
|
|
13
|
+
* @param {number} targetNetPeriodicIncome - The take-home cash required for the period.
|
|
14
|
+
* @param {number} totalPeriodsToSimulate - Duration of the simulation.
|
|
15
|
+
* @param {number} [effectiveTaxRate=0] - The tax rate used to gross up withdrawals.
|
|
16
|
+
* @returns {InstrumentsWithdrawalSchedule} The full simulation results.
|
|
17
|
+
*/
|
|
18
|
+
export declare function performWaterfallDrawdown(financialInstruments: Instrument[], targetNetPeriodicIncome: number, totalPeriodsToSimulate: number, effectiveTaxRate?: number): InstrumentsWithdrawalSchedule;
|
|
19
|
+
//# sourceMappingURL=strategies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategies.d.ts","sourceRoot":"","sources":["../../../../src/lib/investment/strategies.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,OAAO,EACL,6BAA6B,EAE9B,MAAM,kCAAkC,CAAC;AAG1C;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,oBAAoB,EAAE,UAAU,EAAE,EAClC,uBAAuB,EAAE,MAAM,EAC/B,sBAAsB,EAAE,MAAM,EAC9B,gBAAgB,GAAE,MAAU,GAC3B,6BAA6B,CAsE/B"}
|