Paste: Financial functions

Author: Loryn Jenkins
Mode: factor
Date: Fri, 5 Apr 2013 18:05:17
Plain Text |
! 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
    ;

Annotation: Unit test (fails!)

Author: Loryn Jenkins
Mode: factor
Date: Fri, 5 Apr 2013 18:25:48
Plain Text |
! Copyright (C) 2013 Loryn Jenkins.
! See http://factorcode.org/license.txt for BSD license.
USING: tools.test financial-functions ;
IN: financial-functions.tests


[ 4 ] [    7000.00
           H{
              { 1 4000.00 }
              { 2 400.00 }
              { 3 3000.00 }
              { 4 2000.00 }
              { 5 1000.00 }
           } >hashtable
           payback
      ] unit-test

Annotation: Unit tests (succeeds)

Author: Loryn Jenkins
Mode: factor
Date: Fri, 5 Apr 2013 18:46:26
Plain Text |
! Copyright (C) 2013 Loryn Jenkins.
! See http://factorcode.org/license.txt for BSD license.
USING: tools.test financial-functions hashtables math math.functions ;
IN: financial-functions.tests


[ 3 ] [    7000.00
           H{
              { 1 4000.00 }
              { 2 400.00 }
              { 3 3000.00 }
              { 4 2000.00 }
              { 5 1000.00 }
           } >hashtable
           payback
      ] unit-test
 
[ 4 ] [
    0.09
    7000.00
    H{
      { 1 4000.00 }
      { 2 400.00 }
      { 3 3000.00 }
      { 4 2000.00 }
      { 5 1000.00 }
    } >hashtable
    discounted-payback ] unit-test

    
[ 138973.0 ]  [   
    0.09
    7000.00
    H{
      { 1 4000.00 }
      { 2 400.00 }
      { 3 3000.00 }
      { 4 2000.00 }
      { 5 1000.00 }
    } >hashtable
    npv 2 10^ * round ] unit-test

    
[ 1779.0 ]  [  
    0.09
    7000.00
    H{
      { 1 4000.00 }
      { 2 400.00 }
      { 3 3000.00 }
      { 4 2000.00 }
      { 5 1000.00 }
    } >hashtable
    irr 4 10^ * round ] unit-test

Annotation: Unit tests (refactored) (fails compilation)

Author: Loryn Jenkins
Mode: factor
Date: Fri, 5 Apr 2013 19:00:43
Plain Text |
! Copyright (C) 2013 Loryn Jenkins.
! See http://factorcode.org/license.txt for BSD license.
USING: tools.test financial-functions hashtables math math.functions ;
IN: financial-functions.tests


: cashflow1 ( -- hashtable )
   H{
      { 1 4000.00 }
      { 2 400.00 }
      { 3 3000.00 }
      { 4 2000.00 }
      { 5 1000.00 }
   } clone ;

[ 3 ] [ 7000.00 cashflow1 payback] unit-test

[ 4 ] [ 0.09 7000.00 cashflow1 discounted-payback ] unit-test   

[ 138973.0 ]  [ 0.09 7000.00 cashflow1 npv 2 10^ * round ] unit-test  

[ 1779.0 ]  [ 0.09 7000.00 cashflow1 irr 4 10^ * round ] unit-test

Annotation: Units tests (refactored) (succeeds)

Author: Loryn Jenkins
Mode: factor
Date: Fri, 5 Apr 2013 19:24:05
Plain Text |
! Copyright (C) 2013 Loryn Jenkins.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel tools.test financial-functions hashtables math math.functions ;
IN: financial-functions.tests


: cashflow1 ( -- hashtable )
   H{
      { 1 4000.00 }
      { 2 400.00 }
      { 3 3000.00 }
      { 4 2000.00 }
      { 5 1000.00 }
   } clone ;

[ 3 ] [ 7000.00 cashflow1 payback ] unit-test  

[ 4 ] [ 0.09 7000.00 cashflow1 discounted-payback ] unit-test   

[ 138973.0 ]  [ 0.09 7000.00 cashflow1 npv 2 10^ * round ] unit-test  

[ 1779.0 ]  [ 0.09 7000.00 cashflow1 irr 4 10^ * round ] unit-test

New Annotation

Summary:
Author:
Mode:
Body: