Skip to content

Commit

Permalink
Merge pull request #31 from mancubus77/adjust-contrib-30
Browse files Browse the repository at this point in the history
Resolves Add annual adjustments for amountPerAnnum #30
  • Loading branch information
JDIZM authored Aug 18, 2024
2 parents 4e86c03 + 30fb6e9 commit dd3ad10
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 4 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ For example, if you invest $1,000 today at a 7% annual interest rate, how much w
#### Compound Interest

- [x] 1. calculate compound interest of a lump sum over time
- [x] 2. calculate compound interest with additional contributions
- [x] 2. calculate compound interest with additional contributions and annual contribution adjustments
- [x] 3. calculate compound interest with interest only payments towards the principal borrowed
- [x] 4. calculate compound interest with repayments towards the principal

Expand Down Expand Up @@ -74,14 +74,15 @@ const lumpSum = compoundInterestPerPeriod({
paymentsPerAnnum: 12 // displays monthly interest balance
});

// calculate a lump sum over 2 years with additional contributions of 500 per month
// calculate a lump sum over 2 years with additional contributions of 500 per month with 2% adjustment every year
const additionalContributions = compoundInterestPerPeriod({
type: "contribution",
principal: 500,
rate: 3.4,
years: 2,
paymentsPerAnnum: 12,
amountPerAnnum: 6_000,
contributionPerAnnumChange: 2,
accrualOfPaymentsPerAnnum: true
});

Expand Down Expand Up @@ -126,7 +127,8 @@ const repayment = compoundInterestPerPeriod({
###### Contribution Options

- `amountPerAnnum: number` The amount of contributions per annum (eg 6_000 for 500 per month)
- `accrualOfPaymentsPerAnnum: number` If provided payments accrue interest per annum; Otherwise interest is only accrued on the principal payment.
- `accrualOfPaymentsPerAnnum: boolean` If provided payments accrue interest per annum; Otherwise interest is only accrued on the principal payment.
- `contributionPerAnnumChange: number` Changes of annual contribution in percents (to adjust contribution according inflation rates, good for long investments)

###### Debt Repayment Options

Expand Down
26 changes: 26 additions & 0 deletions calc/compoundInterest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -592,4 +592,30 @@ describe("compoundInterestPerPeriod", () => {
});
});
});

describe("contributionPerAnnumChange", () => {
it("when contributionPerAnnumChange is supplied it increases annual additional contribution amountPerAnnum", () => {
const options: IOptions = {
type: "contribution",
principal: 250_000,
rate: 7.8,
years: 25,
paymentsPerAnnum: 1,
amountPerAnnum: 12_000,
contributionPerAnnumChange: 3,
currentPositionInYears: 1,
accrualOfPaymentsPerAnnum: true
};
const result = compoundInterestPerPeriod(options);
expect(result).toMatchObject(
expect.objectContaining({
currentBalance: 282436,
totalInterest: 2144895.2679852117,
endBalance: 2832406.46,
accrualOfPaymentsPerAnnum: true,
investmentType: "contribution"
})
);
});
});
});
31 changes: 30 additions & 1 deletion calc/compoundInterest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,15 @@ export const calcTotalInvestment = (options: IOptions, investmentType: Investmen
const { principal, years, paymentsPerAnnum = 1 } = options;

if (investmentType === "contribution" && "amountPerAnnum" in options) {
const { amountPerAnnum = 0 } = options;
const { amountPerAnnum = 0, contributionPerAnnumChange = 0 } = options;
// Adjust annual contributions if contributionPerAnnumChange rate provided
if (contributionPerAnnumChange > 0) {
let repaymentWithAnnualChange = amountPerAnnum;
for (let i = 1; i < years; i++) {
repaymentWithAnnualChange += (repaymentWithAnnualChange * contributionPerAnnumChange) / 100 + amountPerAnnum;
}
return principal * years + repaymentWithAnnualChange;
}
return principal + amountPerAnnum * years;
}

Expand Down Expand Up @@ -94,6 +102,18 @@ export const calcInterestPayments = (principal: number, interestRate: number, pa
* amountPerAnnum: 6_000,
* accrualOfPaymentsPerAnnum: true
* });
* @example
* // calculate a lump sum over 2 years with additional contributions of 500 per month with 2% adjustment every year
* const additionalContributions = compoundInterestPerPeriod({
* type: "contribution",
* principal: 500,
* rate: 3.4,
* years: 2,
* paymentsPerAnnum: 12,
* amountPerAnnum: 6_000,
* contributionPerAnnumChange: 2,
* accrualOfPaymentsPerAnnum: true
* });
*
* @example
* // example interest only payment that compounds at 4% per annum
Expand All @@ -115,6 +135,7 @@ export const compoundInterestPerPeriod = (options: IOptions): CompoundInterestRe
const { type: investmentType, principal, years, paymentsPerAnnum = 1, currentPositionInYears } = options;

let amountPerAnnum = 0;
let contributionPerAnnumChange;
let accrualOfPaymentsPerAnnum = false;

if ("amountPerAnnum" in options && options.amountPerAnnum && options.amountPerAnnum > 0) {
Expand All @@ -125,6 +146,10 @@ export const compoundInterestPerPeriod = (options: IOptions): CompoundInterestRe
accrualOfPaymentsPerAnnum = options.accrualOfPaymentsPerAnnum;
}

if ("contributionPerAnnumChange" in options && options.contributionPerAnnumChange !== undefined) {
contributionPerAnnumChange = options.contributionPerAnnumChange;
}

// if rate is provided as a percentage, convert to decimal
if (rate >= 1) {
rate = rate / 100;
Expand Down Expand Up @@ -170,6 +195,10 @@ export const compoundInterestPerPeriod = (options: IOptions): CompoundInterestRe

for (let p = 0; p < paymentsPerAnnum; p++) {
if (accrualOfPaymentsPerAnnum) {
// Adjust contributions only from the 2nd year
if (i >= 1 && contributionPerAnnumChange) {
amountPerAnnum = amountPerAnnum * (1 + contributionPerAnnumChange / 100);
}
const newBalanceWithAccrual = prevBalance + amountPerAnnum / paymentsPerAnnum;
const interest = newBalanceWithAccrual * ratePerPeriod;
prevBalance = prevBalance + interest + amountPerAnnum / paymentsPerAnnum;
Expand Down
1 change: 1 addition & 0 deletions types/calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export type ContributionOptions = {
type: "contribution";
paymentsPerAnnum?: number;
amountPerAnnum?: number;
contributionPerAnnumChange?: number;
accrualOfPaymentsPerAnnum?: boolean;
};

Expand Down

0 comments on commit dd3ad10

Please sign in to comment.