#!/usr/bin/env python
'''
A set of functions for quick financial analysis of an investment
opportunity and a series of projected cashflows.
For further details and pros/cons of each function please refer
to the respective wikipedia page:
payback_period
http://en.wikipedia.org/wiki/Payback_period
net present value
http://en.wikipedia.org/wiki/Net_present_value
internal rate of return
http://en.wikipedia.org/wiki/Internal_rate_of_return
'''
import sys, locale
def payback_of_investment(investment, cashflows):
"""The payback period refers to the length of time required
for an investment to have its initial cost recovered.
>>> payback_of_investment(200.0, [60.0, 60.0, 70.0, 90.0])
3.1111111111111112
"""
total, years, cumulative = 0.0, 0, []
if not cashflows or (sum(cashflows) < investment):
raise Exception("insufficient cashflows")
for cashflow in cashflows:
total += cashflow
if total < investment:
years += 1
cumulative.append(total)
A = years
B = investment - cumulative[years-1]
C = cumulative[years] - cumulative[years-1]
return A + (B/C)
def payback(cashflows):
"""The payback period refers to the length of time required
for an investment to have its initial cost recovered.
(This version accepts a list of cashflows)
>>> payback([-200.0, 60.0, 60.0, 70.0, 90.0])
3.1111111111111112
"""
investment, cashflows = cashflows[0], cashflows[1:]
if investment < 0 : investment = -investment
return payback_of_investment(investment, cashflows)
def npv(rate, cashflows):
"""The total present value of a time series of cash flows.
>>> npv(0.1, [-100.0, 60.0, 60.0, 60.0])
49.211119459053322
"""
total = 0.0
for i, cashflow in enumerate(cashflows):
total += cashflow / (1 + rate)**i
return total
def irr(cashflows, iterations=100):
"""The IRR or Internal Rate of Return is the annualized effective
compounded return rate which can be earned on the invested
capital, i.e., the yield on the investment.
>>> irr([-100.0, 60.0, 60.0, 60.0])
0.36309653947517645
"""
rate = 1.0
investment = cashflows[0]
for i in range(1, iterations+1):
rate *= (1 - npv(rate, cashflows) / investment)
return rate
# enable placing commas in thousands
locale.setlocale(locale.LC_ALL, "")
# convenience function to place commas in thousands
format = lambda x: locale.format('%d', x, True)
def investment_analysis(discount_rate, cashflows):
"""Provides summary investment analysis on a list of cashflows
and a discount_rate.
Assumes that the first element of the list (i.e. at period 0)
is the initial investment with a negative float value.
"""
_npv = npv(discount_rate, cashflows)
ts = [('year', 'cashflow')] + [(str(x), format(y)) for (x,y) in zip(
range(len(cashflows)), cashflows)]
print "-" * 70
for y,c in ts:
print y + (len(c) - len(y) + 1)*' ',
print
for y,c in ts:
print c + ' ',
print
print
print "Discount Rate: %.1f%%" % (discount_rate * 100)
print
print "Payback: %.2f years" % payback(cashflows)
print " IRR: %.2f%%" % (irr(cashflows) * 100)
print " NPV: %s" % format(_npv)
print
print "==> %s investment of %s" % (
("Approve" if _npv > 0 else "Do Not Approve"), format(-cashflows[0]))
print "-" * 70
def main(inputs):
"""commandline entry point
"""
usage = '''Provides analysis of an investment and a series of cashflows.
usage: invest discount_rate [cashflow0, cashflow1, ..., cashflowN]
where
discount_rate is the rate used to discount future cashflows
to their present values
cashflow0 is the investment amount (always a negative value)
cashflow1 .. cashflowN values can be positive (net inflows)
or
negative (net outflows)
for example:
invest 0.05 -10000 6000 6000 6000
'''
try:
rate, cashflows = inputs[0], inputs[1:]
investment_analysis(float(rate), [float(c) for c in cashflows])
except IndexError:
print usage
sys.exit()
if __name__ == '__main__':
debug = False
if debug:
import doctest
doctest.testmod()
else:
main(sys.argv[1:])