Deployn

Net Present Value Calculator

Two net present value calculators created using JavaScript. One offers the possibility to enter the cash flow to the day.

Net Present Value Calculator-heroimage

CAUTION

Please note that this blog post was originally written in German and has been translated for your convenience. Although every effort has been made to ensure accuracy, there may be translation errors. I apologize for any discrepancies or misunderstandings that may result from the translation and I am grateful for any corrections in the comments or via mail.

For a task, I wanted to calculate an investment’s net present value (NPV) and the internal rate of return as the next step. Instead of typing the numbers into my calculator, I wanted to create a calculator with JavaScript, especially since I haven’t done anything with pure JavaScript in a while. I was also interested in how I could calculate an investment if deposits and withdrawals are not made in regular intervals.

First I will show a rather common net present value calculator, which also tries to calculate the internal rate of return. This is followed further down by a net present value calculator with variable payment flows.

I do not, of course, accept any liability for the calculation.

Update: In the meantime, the two calculators have moved and are based on React.

To the capital value calculator

Nevertheless, here is the explanation and the Javascript code.

1. Normal Investment Calculator

As soon as you have entered the figures and clicked on the “Calculate” button, you will be shown how high the capital value of the investment is at time 0. Furthermore, the internal rate of return is calculated to an accuracy of 0.1 %. The calculator assumes an investment at time 0, followed by constant investments at any number of points in time. Finally, a positive or negative residual value remains at the end of the term.

Evaluation

What can you calculate with this? Example: Let’s assume there is an opportunity for a three-year investment that initially requires €10,000 and subsequently incurs €1,000 in additional costs each year. Each year, the investment generates a return of €5,000. However, the money could also be invested elsewhere for 8 % interest.

Example normal investment](@assets/images/blog/kapitalwertrechner/images/normalinvestition.png)

The calculator says that the cash value is €308. The positive net present value shows that the investment is worthwhile with a calculation interest rate of 8 %. The internal interest rate is between 9.7 % and 9.8 %. This means that with a calculation interest rate of approx. 9.7 %, the cash value would amount to approx. €0. The investment, therefore, yields a return of approx. 9.7 %.

Code

Perhaps someone is interested in the original JavaScript code, although it has not yet been cleaned up:

function initInvest() {
	return document.getElementById("inputInitInvest").value;
}

function deposit() {
	return document.getElementById("inputDeposit").value;
}

function payout() {
	return document.getElementById("inputPayout").value;
}

function interest() {
	return document.getElementById("inputInterest").value;
}

function termVal() {
	return document.getElementById("inputTermVal").value;
}
function discount(value, interest, time) {
	return value * (1 / (1 + interest / 100) ** time);
}

function annuity() {
	let yearCount = 0;
	let annuity = 0;
	while (yearCount < duration()) {
		yearCount++;
		annuity += discount(payout() - deposit(), interest(), yearCount);
	}
	return annuity;
}

function annuityTest(newInterest) {
	let yearCount = 0;
	let annuity = 0;
	while (yearCount < duration()) {
		yearCount++;
		annuity += discount(payout() - deposit(), newInterest, yearCount);
	}
	return annuity;
}

function duration() {
	return document.getElementById("inputDuration").value;
}

function calc() {
	document.getElementById("solution").innerHTML =
		"The total net present value of the investment is " +
		(-initInvest() + annuity() + discount(termVal(), interest(), duration())).toLocaleString("de-DE") +
		".";
	return -initInvest() + annuity() + discount(termVal(), interest(), duration());
}

function calcTest(newInterest) {
	return -initInvest() + annuityTest(newInterest) + discount(termVal(), newInterest, duration());
}

function calcInt() {
	calc();
	let int = Number(interest());
	if (calcTest(int) == 0) {
		return calcIntHtml(int, "ok");
	} else if (calcTest(int) > 0) {
		while (calcTest(int) > 0) {
			int += 0.1;
			if (int > 100) {
				return calcIntHtml("error", "error");
			}
		}
		return calcIntHtml(int, "up");
	} else if (calcTest(int) < 0) {
		while (calcTest(int) < 0) {
			int -= 0.1;
			if (int < -100) {
				return calcIntHtml("error", "error");
			}
		}
		return calcIntHtml(int, "down");
	}
}

function calcIntHtml(number, direction) {
	if (direction == "error") {
		document.getElementById("solutionInt").innerHTML = "The internal rate of return cannot be calculated.";
	}
	if (direction == "ok") {
		document.getElementById("solutionInt").innerHTML = "The internal rate of return may be " + number + "&nbsp;%";
	}
	if (direction == "up") {
		document.getElementById("solutionInt").innerHTML =
			"The internal rate of return is between " + (number - 0.1).toFixed(1) + "&nbsp;% and " + number.toFixed(1) + "&nbsp;%";
	}
	if (direction == "down") {
		document.getElementById("solutionInt").innerHTML =
			"The internal rate of return is between " + number.toFixed(1) + "&nbsp;% and " + (number + 0.1).toFixed(1) + "&nbsp;%";
	}
}

2. Extended Calculator

With this calculator it is possible to enter the cash flow to the day (I can’t really say whether it makes sense). However, the calculator assumes a constant interest rate. The internal rate of return is not calculated. Furthermore, this calculator can also be used as an interest calculator.

Code

The JavaScript code for the extended calculator:

let cnt = 0;

function addCashflow() {
	let div = document.createElement("DIV");
	div.innerHTML =
		'<input id="cfdate' +
		cnt +
		'" name="cashflow' +
		"" +
		'" type="date" />' +
		'<input id="cfvalue' +
		cnt +
		'" name="cashflow' +
		"" +
		'" type="number" />' +
		'<input id="Button' +
		cnt +
		'" type="button" ' +
		'value="X" onclick="deleteFile(this)" />';
	document.getElementById("cfControls").appendChild(div);
	cnt++;
	buttonText();
}

function deleteFile(div) {
	document.getElementById("cfControls").removeChild(div.parentNode);
	cnt--;
	buttonText();
}

function buttonText() {
	if (cnt > 0) {
		document.getElementById("add_button").value = "Add another payment";
	} else {
		document.getElementById("add_button").value = "Add payment";
	}
}

function calc() {
	let solutionText = document.getElementById("solution2");
	solutionText.innerText = "";
	let int = document.getElementById("inputInterest2").value;
	let npv = 0;
	if (cnt == 0) {
		return (solutionText.innerText = "There is no investment.");
	} else {
		npv += Number(document.getElementById("cfvalue0").value);
		let cfdateStart = new Date(document.getElementById("cfdate0").value);
		for (i = 1; i < cnt; i++) {
			let cfdate = new Date(document.getElementById("cfdate" + i).value);
			let cfvalue = document.getElementById("cfvalue" + i).value;
			npv += discount(cfvalue, int, cfdateStart, cfdate);
		}
		return (solutionText.innerText =
			"The net present value of the investment amounts to " +
			cfdateStart.toLocaleDateString() +
			" an amount of " +
			npv.toLocaleString() +
			(cnt > 1
				? ".\nAm " +
					new Date(document.getElementById("cfdate" + (cnt - 1)).value).toLocaleDateString() +
					" the net present value is " +
					discount(npv, int, new Date(document.getElementById("cfdate" + (cnt - 1)).value), cfdateStart).toLocaleString()
				: ""));
	}
}

function discount(cash, interest, dateStart, dateEnd) {
	let yearStart = dateStart.getFullYear();
	let yearStartLastDay = new Date(yearStart, 11, 31);
	let yearEnd = dateEnd.getFullYear();
	let yearEndFirstDay = new Date(yearEnd, 0, 1);

	if (yearStart == yearEnd) {
		return cash / (1 + interest / 100) ** (dayCount(dateStart, dateEnd) / (365 + (leapYear(yearStart) ? 1 : 0)));
	} else {
		let fullYears = yearEnd - yearStart - 1;
		return (
			cash /
			(1 + interest / 100) **
				((dayCount(dateStart, yearStartLastDay) + 1) / (365 + (leapYear(yearStart) ? 1 : 0)) +
					dayCount(yearEndFirstDay, dateEnd) / (365 + (leapYear(yearEnd) ? 1 : 0)) +
					fullYears)
		);
	}
}

function leapYear(year) {
	return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

function dayCount(start, end) {
	return Number(((end - start) / (1000 * 3600 * 24)).toFixed());
}

This website uses cookies. These are necessary for the functionality of the website. You can find more information in the privacy policy