Leader

Wednesday 8 April 2015

Alternative function: Net present value of a cash flow

See also the time value of money for other related Matlab functions.

Download
npvFlow.m

Introduction
The net present value (NPV) of a cash flow is how much a flow of cash is worth right now. The "net" part refers to the fact that the cash flow isn't necessarily fixed, and may even be negative at certain points in time. Matlab has two functions in the financial toolbox for calculating NPV for fixed and variable cash flows (pvfix and pvvar respectively), npvFlow.m is designed to emulate the basic function of both these functions and works for fixed and variable cash flows.

For example, consider a cash flow of £200 per year for the next 4 years, with an annual interest rate of 4%. What is the value of this cash flow right now, at this point in time? It's not £800, it must be less. To work it out, we need to calculate the present value of each individual chunk of cash. The NPV is simply the sum of these.

This is done with the PV calculation (pvLump,m) of each lump sum, which is

PV = FV / (1+r)^n,

where r = interest rate and n = number of time periods.

So,
End of period 1: £200 received = PV1 = 200/(1+0.04)^1 = 192
End of period 2: £200 received = PV2 = 200/(1+0.04)^2 = 185
End of period 3: £200 received = PV3 = 200/(1+0.04)^3 = 178
End of period 4: £200 received = PV4 = 200/(1+0.04)^4 = 171

The sum of PV1-4 = NPV = 192 + 185 + 178 + 171 = £725.



The NPV is lower than the sum of the cash flow (£200x4=£800) because of the interest rate. Receiving the cash flow at certain points in the future is of less value than receiving £800 right now because we lose out on the opportunity to earn interest; if you had £800 immediately and could invest it at 4%, its future value (FV) in 4 years would be:

FV = 800 * (1+0.04)^4 = £936.

We can also compare the the value of this cash flow to simply receiving a lump sum of £800 in 4 years time. This should be worth LESS than the cash flow is worth, because more interest is lost overall. When receiving £800 in 4 years, we lose out on 4 years of interest on the whole amount. In the cash flow, we lose out on interest on £800 in the first year, on £600 in the second year, on £400 in the third year and on £200 in the last year (remember interest is received at the end of the period).

PV (of £800 in 4 years) = 800 / (1+0.04)^4 = £684,

which is less than the NPV of the cash flow, as expected.

In summary, with an annual interest rate of 4%, £800 now is worth £936 4 years in the future, a cash flow of £800 over 4 years is worth £725 now, and £800 in 4 years is worth £684 now.

Using pvFlow, the above example can be calculated with the following code:

npvFlow(200,0.04,4)

Variable payments
Payments in a cash flow can vary in amount and time when they are received. For example, consider a cash flow of £100 in year 1, £-50 in year 2, and £100 in year 4. The annual interest rate is again 4%.

End of period 1: £100 received = PV1 = 100/(1+0.04)^1 = 96
End of period 2: £-50 received (£50 lost) = PV2 = -50/(1+0.04)^2 = -46
End of period 3: £0 received = PV3 = 0/(1+0.04)^0 = 0/1 = 0
End of period 4: £100 received = PV4 = 100/(1+0.04)^4 = 85

NPV = 96 + -46 + 0 + 85 = £135.

pvFlow accepts vectors of payments and periods and can return the overall NPV and the PV of each period.

[npv, pvs] = npvFlow([100 -5 100],0.04, [1 2 4])

npv =
  135.4065

pvs =
    1.0000   96.1538
    2.0000  -46.2278
    4.0000   85.4804

Code run-through
function [npv, pvAtPeriod]= npvFlow(payments, rate, periods)

npvFlow takes 3 inputs: payments should be a scaler for consistent payments, or a vector of payments for each period (which can vary), the interest rate (rate), and periods, which should contain a scaler indicating the number of periods, or a vector of periods. It returns npv which is the NPV, and pvAtPeriod, which shows the individual PV values at each period, the sum of which is equal to the NPV.

if isscalar(periods)
    % Regular periods assumed
    t = 1:periods;
else
    % Vector of periods provided - should be same length of vector of
    % payments already supplied/defined
    t = periods;
end

First the function checks if periods has been input as a scaler or a vector using the isscalar function, which returns true if the input is scaler (surprisingly). If it's a scaler (eg. 3) it should be the number of periods, so it creates a vector of 1:number of periods (eg. [1, 2, 3]). If periods is already a vector then nothing is changed (it's just copied in to another variable, t, to reduce typing in the rest of the function).

if isscalar(payments)
    % Payment is constant for each period, create vector
    c = zeros(1,length(t));
    c = c+payments;
else 
    % Vector of payments input
    c = payments;
end

Next the input payments is checked. If payments a scaler, the payment is assumed to be the same at each time period, and a vector is created with the payment for each time period (eg, if payments = 20 and periods = [1,2,3], then c = [20, 20, 20]). If payments is already a vector, it's copied to c. Again, this is technically a bit inefficient, but reduces typing and makes the equations a bit easier to read.

if numel(c)~=numel(t)
    disp('Error: Payment or period missing.')
    return
end
r=rate;

At this point there's a check to make sure t and c are both the same length. They should be vectors of the same length at this point (or both scalers if there's only one period). If they aren't the same length an error is displayed indicating that there was an error with the inputs supplied to the function, The return command then exits the function and returns control to the command window (or the calling function, if applicable).

pvPeriod = c./(1+r).^t;
npv = sum(pvPeriod);

pvAtPeriod = [t', pvPeriod'];

Finally the actual calculation is done. Notice there's no for loop - the equation is vectorised. Remember that at this point, c and t are vectors whereas r is a scaler. We want to perform the calculation in an "element wise" fashion, which is what the . before the divide and power operators indicates. Intuitively this works in the same way as a for loop where each iteration steps along the vectors t and c (and uses the same value of r in each iteration, The equivalent for loop - which would take longer to run than the vectorised operation - would be something like:

pvPeriod=NaN(1,length(t))
for ii = 1:length(t)
    pvPeriod(ii) = c(ii)/(1+r)^t(ii);
end
pvAtPeriod = [t', pvPeriod'];

No comments:

AdSense