NPV
According to the Wikipedia formula:
Liquid present value
[...] is the mathematical-financial formula able to determine the present value of discounted future payments at an appropriate interest rate minus the cost of the investment.
Therefore, the calculation consists of adding the values of future payments (calculated at present) and subtracting the value of the initial investment.
A possible implementation of the VPL in Javascript:
/*
* Calcula o Valor Presente Líquido para
* uma variação de período constante
*
* @taxa => taxa de desconto
* @montantes => vetor com os valores com os recebimentos ou pagamentos
*
*/
function vpl(taxa, montantes)
{
var ret = montantes[0];
for (var i=1; i<montantes.length; i++)
ret += montantes[i] / Math.pow( (1.0 + taxa), i);
return ret;
}
TIR
According to Wikipedia:
Internal rate of return
[...] is a hypothetical discount rate that, when applied to a cash flow, causes the expense values, brought to present value, to be equal to the values of the returns of the investments, also brought to the value present.
The IRR is the interest rate that "zeroes" the NPV, that is, vpl(TIR, montantes) = 0
.
For the calculation of the IRR, it is necessary to find the root of the above equation.
There are several methods to find this root:
Algorithm to find root
Below is an example that uses the Bisection method. (which is one of the simplest to implement):
/*
* Calcula a Taxa Interna de Retorno (Método da Bisseção)
*
* @montantes => vetor com os valores
*/
function tir(montantes)
{
var ret = -1000000000.0;
var juros_inicial = -1.0;
var juros_medio = 0.0;
var juros_final = 1.0;
var vpl_inicial = 0.0;
var vpl_final = 0.0;
var vf = 0.0;
var erro = 1e-5; // Valor mínimo que determina que a raiz foi encontrada
// Procura um possível intervalo para a raiz
// O looping deve terminar antes de i chegar a 100!
for (var i=0; i<100; i++) {
vpl_inicial = vpl(juros_inicial, montantes);
vpl_final = vpl(juros_final, montantes);
if (sinal(vpl_inicial) != sinal(vpl_final))
break;
juros_inicial -= 1.0;
juros_final += 1.0;
};
// Contador que evita um looping infinito
var count = 0;
// Busca por Bisseção
for (;;) {
var juros_medio = (juros_inicial + juros_final) / 2.0;
var vpl_medio = vpl(juros_medio, montantes)
if (Math.abs(vpl_medio) <= erro) {
// Resultado foi encontrado
return juros_medio*100.0;
};
if (sinal(vpl_inicial) == sinal(vpl_medio)) {
juros_inicial = juros_medio;
vpl_inicial = vpl(juros_medio, montantes);
} else {
juros_final = juros_medio;
vpl_final = vpl(juros_medio, montantes);
};
// Evita um possível looping infinito
if (++count > 10000)
throw "looping inválido";
};
// O algoritmo nunca deve chegar aqui.
return ret;
};
See working in jsfiddle
Below is a link to a page that does these (and other) calculations in an interactive (more didactic) way:
Make the Account