! Copyright (C) 2013 Loryn Jenkins. ! See http://factorcode.org/license.txt for BSD license. USING: kernel accessors locals combinators shuffle sequences assocs hashtables math math.order math.functions math.ranges arrays vectors math.constants fry tools.continuations prettyprint ; IN: financial-functions : summation ( seq -- newseq ) 0 [ + ] accumulate >vector swap suffix! ; :: pv ( rate period payment -- pv ) rate 1 + period ^ recip payment * ; : payback ( investment cashflows -- period ) swap '[ _ values summation [ _ >= ] find drop ] call ; :: discounted-payback ( rate investment cashflows -- period ) cashflows values [ :> ( pmt i ) rate i 1 + pmt pv ] map-index summation [ investment >= ] find drop ; :: npv ( rate investment cashflows -- npv ) cashflows values [ :> ( pmt i ) rate i 1 + pmt pv ] map-index sum investment - ; ! Newton-Raphson implementation of IRR convergence algorithm ! From: code.google.com/p/irr-newtonraphson-calculator/downloads/detail?name=NumericalMethods.rar ! This is an interesting, sophisticated, and non-functional (i.e. doesn't converge) algorithm. ! I'm reasonably sure it corresponds with the original C# code. CONSTANT: tolerance 0.00001 CONSTANT: max-iterations 5000 CONSTANT: estimated-rate-of-return-min -2147483648 CONSTANT: estimated-rate-of-return-max 2147483647 : within-bounds? ( est-rate -- ? ) dup f = not [ estimated-rate-of-return-min estimated-rate-of-return-max between? ] when ; : irr-polynomial-sum ( guess investment cashflows -- sum ) npv ; : converged? ( guess investment cashflows -- ? ) irr-polynomial-sum abs tolerance <= ; :: pv-deriv ( rate period payment -- deriv ) rate 1 + period ^ recip payment period * * ; :: irr-derivative-sum ( guess investment cashflows -- sum ) cashflows values [ :> ( pmt i ) guess i 1 + pmt pv-deriv ] map-index sum investment - ; :: newton-raphson ( iterations guess investment cashflows -- result ) guess within-bounds? [ guess investment cashflows irr-polynomial-sum guess investment cashflows irr-derivative-sum / guess - :> estimate estimate investment cashflows converged? [ estimate ] [ iterations max-iterations < [ iterations 1 + estimate investment cashflows newton-raphson ] [ f ] if ] if ] [ f ] if ; : irr-newton-raphson ( guess investment cashflows -- irr ) [ 0 ] 3dip [ 1 + neg ] 2dip newton-raphson ; ! Fixed point iteration method. Has the advantage of actually working. ! From: code.activestate.com/recipes/576686-npv-irr-payback-analysis ! NOTE: Original code failed to converge due to omitting abs in the function equivalent to fixed-point-pv-deriv. :: fixed-point-pv-deriv ( guess investment cashflows -- result ) guess investment cashflows npv investment / abs 1 swap - guess * ; :: irr-fixed-point ( guess investment cashflows -- results ) 100 [1,b] [ ] map guess 1 + [ drop investment cashflows fixed-point-pv-deriv ] accumulate drop ; : irr ( guess investment cashflows -- irr ) irr-fixed-point ; ! Testing : payback-tester ( -- periods ) 7000.00 H{ { 1 4000.00 } { 2 400.00 } { 3 3000.00 } { 4 2000.00 } { 5 1000.00 } } >hashtable payback ; : disc-tester ( -- periods ) 0.09 7000.00 H{ { 1 4000.00 } { 2 400.00 } { 3 3000.00 } { 4 2000.00 } { 5 1000.00 } } >hashtable discounted-payback ; : npv-tester ( -- periods ) 0.09 7000.00 H{ { 1 4000.00 } { 2 400.00 } { 3 3000.00 } { 4 2000.00 } { 5 1000.00 } } >hashtable npv ; : irr-tester ( -- periods ) 0.09 7000.00 H{ { 1 4000.00 } { 2 400.00 } { 3 3000.00 } { 4 2000.00 } { 5 1000.00 } } >hashtable irr ;