Cash Flow (IRR, MIRR, NPV)
hi all,
here a program to calculate Cash Flow operations with the Prime (IRR, MIRR, NPV).
The program is presented in two version: the first give three routines to calculate (Net Present Value, Internal Rate of Return and Modified Internal Rate of Return, like that in the HP 12C); the second will follow with a "Drawmenu" version with only a command, Cash_Flow that executes the same routines internally.
NPV included is the nice program by Eddie W. Shore ( here in the Forum).
I would like to thank who has helped me to do this program: Dale (DRD), Cyrille de Brébisson, Akmon, Didier Lachiese, kharpster, who has transformed the program into "menu-ized" version...)
Warning: both version use list L1 or matrix M1 to store data, so, if you have important data in there, please, first save them otherwhere...
I advice to use the list for series of cash flow with few data to treat or edit {CF0, CF1, CF2, ... CFj...}, and a matrix when there are more data with frequency repeated (i.e [CF0, 1], [CF1, 2], [CF2, 1], [CF3, 8], ...,[CFj],... [CF last, 1]).
You can store data into list (or matrix) first of use the program, or inside the program, editing them.
Enjoy!
Salvo Micciché (salvomic)
Version with commands separately exported
Code:
EXPORT IRR()
// Credits: Cyrille de Brébisson, Akmon, Dale (DrD), salvomic (Salvo Micciché),
// Eddie W. Shore, Didier Lachiese, kharpster
// Interal Rate of Return. Cash flows in {L1} list or M1 (matrix with frequencies)
// by Salvo Micciché
BEGIN
local ch, irr;
CHOOSE(ch,"Flows List or Matrix w/ freq","Cash Flows List","CF Matrix whit frequencies");
CASE
IF ch==1 THEN
EDITLIST(L1, "Internal Rate of Return");
END;
IF ch==2 THEN
EDITMAT(M1, "Internal Rate of Return");
LOCAL flows:={}, j, k, s;
s:=SIZE(M1);
FOR j FROM 1 TO s(1) DO
FOR k FROM 1 TO M1(j,2) DO
flows:= append(flows, M1(j,1));
END; END; // for 1, 2
L1:= flows;
END;
DEFAULT
MSGBOX("IRR() with {list} or [matrix with frequencies]");
RETURN;
END; // case
irr:= solve(ΣLIST(MAKELIST((L1(I)/X^(I-1)),I,1,SIZE(L1))),X)-1;
IF (irr(1)>=1 OR irr(1)<=-1) THEN irr:=tail(irr); END;
// formula by akmon, Cyrille, Dale
PRINT;
PRINT("Internal Rate of Return
IRR = ");
PRINT(EVAL(ROUND(100*irr,4)) + "%");
RETURN irr;
END;
EXPORT MIRR()
// Calc Modified Internal Return Rate
// Salvo Micciché 2015
BEGIN
LOCAL sr, rr, flpos:={}, flneg:={}, sz ;
LOCAL sz1, sz2, npvp, npvn, n ;
LOCAL ch, fvp, ppyr, mirrvalue;
CHOOSE(ch,"Flows List or Matrix w/ freq","Cash Flows List","CF Matrix whit frequencies");
CASE
IF ch==1 THEN
EDITLIST(L1, "Modified Internal Rate of Return");
END;
IF ch==2 THEN
EDITMAT(M1, "Internal Rate of Return");
LOCAL flows:={}, j, k, s;
s:=SIZE(M1);
FOR j FROM 1 TO s(1) DO
FOR k FROM 1 TO M1(j,2) DO
flows:= append(flows, M1(j,1));
END; END; // for 1, 2
L1:= flows;
END;
DEFAULT
MSGBOX("MIRR() with {list} or [matrix with frequencies]");
KILL;
END; // case
INPUT ({sr, rr, ppyr},"Safe and risk rate", {"sr", "rr", "ppyr"},
{"Safe rate CF-", "Risk (reinvestment) Rate CF+", "n Payments for year"}, {0,0, 12},{0,0, 12});
// sr and rr yearly rates (es. 6%, 10%), ppyr number of payments in a year
sz:= SIZE(L1);
sr:=sr/ppyr; rr:=rr/ppyr;
n:=sz-1;
flneg:=MIN(L1,0); flpos:=MAX(L1,0); // one list -> two list, tnx Didier
sz1:= SIZE(flpos); sz2:= SIZE(flneg);
npvp:= NPV(rr, flpos);
npvp:=-npvp;
fvp:=Finance.CalcFV(n,rr*ppyr,npvp,0,ppyr,12,0);
npvn:= NPV(sr, flneg);
// RETURN 100*((fvp/-npvn)^(1/n)-1 ); HP 12C formula (equal to the next)
mirrvalue:= Finance.CalcIPYR(n,npvn,0,fvp,ppyr,12,0)/ppyr;
PRINT;
PRINT ("Modified Internal Rate of Return
Safe rate " + EVAL(ROUND(sr*ppyr,3)) + "% - Risk (reinvestment) rate " + EVAL(ROUND(rr*ppyr,3)) + "%
with " + STRING(ppyr) + " n. payments per year.
NPV negative flows " + STRING(ROUND(npvn,3)) + "
NPV positve flows " + STRING(ROUND(npvp,3)) + "
FV of posive flows NPV " + STRING(ROUND(fvp,3)) + "
MIRR monthly rate " + STRING(ROUND(mirrvalue,3)) + "%
MIRR yearly rate " + EVAL(ROUND(mirrvalue*ppyr,3)) + "%"
);
RETURN {mirrvalue, ppyr*mirrvalue}; // return monthly and yearly MIRR
END;
EXPORT NPV(r, flows)
// routine by Eddie W. Shore
BEGIN
LOCAL t:=0, k, s;
r:=1+0.01*r;
CASE
// list
IF TYPE(flows)==6 THEN
s:=SIZE(flows);
FOR k FROM 1 TO s DO
t:=t+flows(k)/(r^(k-1));
END;
END;
// matrix
IF TYPE(flows)==4 THEN
LOCAL j, n;
s:=SIZE(flows);
k:=0;
FOR j FROM 1 TO s(1) DO
FOR n FROM 1 TO flows(j,2) DO
t:=flows(j,1)/(r^k)+t;
k:=k+1;
END; // for
END; // for 2
END; // if
DEFAULT
MSGBOX("NPV(rate, list) or NPV(rate, [flow, freq])");
KILL;
END; // Case
RETURN t;
END;
recall_npv()
BEGIN
local ch, r;
INPUT (r, "Rate", "rate%", "Rate for Net Present Value", 0, 10);
CHOOSE(ch,"Flows List or Matrix w/ freq","Cash Flows List","CF Matrix whit frequencies");
CASE
IF ch==1 THEN
EDITLIST(L1, "Internal Rate of Return");
END;
IF ch==2 THEN
EDITMAT(M1, "Internal Rate of Return");
LOCAL flows:={}, j, k, s;
s:=SIZE(M1);
FOR j FROM 1 TO s(1) DO
FOR k FROM 1 TO M1(j,2) DO
flows:= append(flows, M1(j,1));
END; END; // for 1, 2
L1:= flows;
END;
DEFAULT
MSGBOX("IRR() with {list} or [matrix with frequencies]");
KILL;
END; // case
NPV(r, L1);
END;
EXPORT about()
BEGIN
PRINT;
PRINT ("Program created by by Salvo Micciché (salvomic).
Credits: Cyrille de Brébisson, Akmon, Dale (DrD), Eddie W. Shore, Didier Lachiese, kharpster");
RETURN;
END;
Here Cash_Flows, the version with Drawmenu, every functions inside the program...
This version exports variables in CF_IRR, CF_MIRR, CF_NPV inside Vars->User->Cash_Flow
Code:
export CF_IRR:=0;
export CF_MIRR:={0,0};
export CF_NPV:=0;
// Initialize procedures used in project (by khapster)
EVENTHANDLER();
PUTMENU();
GETMENU();
IRR();
MIRR();
NPV();
recall_npv();
about();
// Initialize variables used globally in project
mSEL;
eTYP;
kP;
m;
m1;
EXPORT Cash_Flow()
BEGIN
// Initialize local variables used within this procedure
LOCAL mx,my,mTXT,EXITPGM;
// Set the menu text (this is softcoded and determines if a menu item is valid)
mTXT := {"NPV","IRR","MIRR","About","","Quit"};
// MAIN CODE - Loop until ESC is pressed, then exit the program
EXITPGM := 0;
WHILE EXITPGM == 0 DO
// Clear the screen and draw the menu
RECT_P();
TEXTOUT_P("Cash Flow Utility", 100, 10, 5, RGB(255,0,0));
TEXTOUT_P("NPV Net Present Value", 25, 50);
TEXTOUT_P("IRR Internal Rate of Return", 25, 70);
TEXTOUT_P("MIRR Modified Internal Rate of Return", 25, 90);
TEXTOUT_P("by Salvo Micciché, 2015", 25, 120);
TEXTOUT_P("Credits: Cyrille de Brébisson, Akmon", 25, 150);
TEXTOUT_P("Dale (DrD), Eddie W. Shore", 25, 170);
TEXTOUT_P("Didier Lachiese, kharpster", 25, 190);
PUTMENU(mTXT);
// Flush the mouse buffer
WHILE MOUSE(1) ≥ 0 DO END;
// Loop until we have a keyboard or mouse event
REPEAT
EVENTHANDLER();
UNTIL eTYP <> "";
CASE
// If the event type was a keyboard action then process it
IF eTYP == "K" THEN
// If the ESC key was pressed set the program to end
IF kP == 4 THEN
EXITPGM := 1;
ELSE
// ESC was not pressed do what you want with the keypress, we are just going to do a TEXTOUT
END;
END;
// If the event type was mouse action then process it
IF eTYP == "M" THEN
// Convert mouse coordinates to decimal
mx := B→R(m1(1));
my := B→R(m1(2));
// Determine if mouse coordinates are inside of a valid menu item otherwise return a zero
GETMENU(mx,my,mTXT);
// If a valid menu item was selected, do something, we are just going to do a TEXTOUT
IF mSEL > 0 THEN
CASE
// If menu item 1 was selected display a choose box for the user to select from
IF mSEL == 1 THEN
recall_npv();
END;
IF mSEL == 2 THEN
IRR();
END;
IF mSEL == 3 THEN
MIRR();
END;
IF mSEL == 4 THEN
about();
END;
IF mSEL == 6 THEN
EXITPGM := 1;
END;
DEFAULT
// This is the default action for the menu selection and will only run if no case statement is satisfied
END;
ELSE
// Mouse not in menu, do something if needed
END;
END;
END;
END;
END;
// -------------------------------------------------------------------
// Detect keyboard or mouse input (keyboard has priority)
// -------------------------------------------------------------------
EVENTHANDLER()
BEGIN
eTYP := "";
kP := GETKEY;
IF kP <> -1 THEN
eTYP := "K";
ELSE
m := MOUSE;
m1 := m(1);
IF SIZE(m1) > 0 THEN
eTYP := "M";
END;
END;
END;
// ----------------------------------------------
// Draw the menu using the list passed in
// ----------------------------------------------
PUTMENU(mTXT)
BEGIN
DRAWMENU(mTXT(1),mTXT(2),mTXT(3),mTXT(4),mTXT(5),mTXT(6));
END;
// ------------------------------------------------------------------------------------------
// Get the number of the menu item selected (1-6) by checking mouse position
// Menu items with empty/blank text will return a zero
// ------------------------------------------------------------------------------------------
GETMENU(mx,my,mTXT)
BEGIN
mSEL := 0;
IF my≥220 AND my≤239 THEN
CASE
IF mx≥0 AND mx≤51 AND mTXT(1)>"" THEN
mSEL := 1;
END;
IF mx≥53 AND mx≤104 AND mTXT(2)>"" THEN
mSEL := 2;
END;
IF mx≥106 AND mx≤157 AND mTXT(3)>"" THEN
mSEL := 3;
END;
IF mx≥159 AND mx≤210AND mTXT(4)>"" THEN
mSEL := 4;
END;
IF mx≥212 AND mx≤263 AND mTXT(5)>"" THEN
mSEL := 5;
END;
IF mx≥265 AND mx≤319 AND mTXT(6)>"" THEN
mSEL := 6;
END;
END;
END;
END;
// ------------------------------------------------------------------------------------------
// Cash Flow application Code
// ------------------------------------------------------------------------------------------
IRR()
// Credits: Cyrille de Brébisson, Akmon, Dale (DrD), salvomic (Salvo Micciché),
// Eddie W. Shore, Didier Lachiese, kharpster
// Interal Rate of Return. Cash flows in {L1} list or M1 (matrix with frequencies)
// by Salvo Micciché
BEGIN
local ch, irr;
CHOOSE(ch,"Flows List or Matrix w/ freq","Cash Flows List","CF Matrix whit frequencies");
CASE
IF ch==1 THEN
EDITLIST(L1, "Internal Rate of Return");
END;
IF ch==2 THEN
EDITMAT(M1, "Internal Rate of Return");
LOCAL flows:={}, j, k, s;
s:=SIZE(M1);
FOR j FROM 1 TO s(1) DO
FOR k FROM 1 TO M1(j,2) DO
flows:= append(flows, M1(j,1));
END; END; // for 1, 2
L1:= flows;
END;
DEFAULT
TEXTOUT_P("Use: IRR() with {list} or [matrix with frequencies]", 5, 30);
WAIT;
RETURN;
END; // case
irr:= solve(ΣLIST(MAKELIST((L1(I)/X^(I-1)),I,1,SIZE(L1))),X)-1;
IF (irr(1)>=1 OR irr(1)<=-1) THEN irr:=tail(irr); END;
// formula by akmon, Cyrille, Dale
sto(irr, CF_IRR);
RECT_P(0,0,319,219);
TEXTOUT_P("IRR Internal Rate of Return", 0, 10);
TEXTOUT_P(EVAL(ROUND(100*irr, 3))+ "%", 0, 30, 0, RGB(255,0,0));
WAIT;
RETURN irr;
END;
MIRR()
// Calc Modified Internal Return Rate
// Salvo Micciché 2015
BEGIN
LOCAL sr, rr, flpos:={}, flneg:={}, sz ;
LOCAL sz1, sz2, npvp, npvn, n ;
LOCAL ch, fvp, ppyr, mirrvalue;
CHOOSE(ch,"Flows List or Matrix w/ freq","Cash Flows List","CF Matrix whit frequencies");
CASE
IF ch==1 THEN
EDITLIST(L1, "Modified Internal Rate of Return");
END;
IF ch==2 THEN
EDITMAT(M1, "Internal Rate of Return");
LOCAL flows:={}, j, k, s;
s:=SIZE(M1);
FOR j FROM 1 TO s(1) DO
FOR k FROM 1 TO M1(j,2) DO
flows:= append(flows, M1(j,1));
END; END; // for 1, 2
L1:= flows;
END;
DEFAULT
TEXTOUT_P("Use: MIRR() with {list} or [matrix with frequencies]", 0, 30);
END; // case
INPUT ({sr, rr, ppyr},"Safe and risk rate", {"sr", "rr", "ppyr"},
{"Safe rate -", "Risk Rate +", "n Pmt for year"}, {0,0, 12},{0,0, 12});
// sr and rr yearly rates (es. 6%, 10%), ppyr number of payments in a year
sz:= SIZE(L1);
sr:=sr/ppyr; rr:=rr/ppyr;
n:=sz-1;
flneg:=MIN(L1,0); flpos:=MAX(L1,0); // one list -> two list, tnx Didier
sz1:= SIZE(flpos); sz2:= SIZE(flneg);
npvp:= NPV(rr, flpos);
npvp:=-npvp;
fvp:=Finance.CalcFV(n,rr*ppyr,npvp,0,ppyr,12,0);
npvn:= NPV(sr, flneg);
// RETURN 100*((fvp/-npvn)^(1/n)-1 ); HP 12C formula (equal to the next)
mirrvalue:= Finance.CalcIPYR(n,npvn,0,fvp,ppyr,12,0)/ppyr;
sto({mirrvalue, ppyr*mirrvalue}, CF_MIRR);
RECT_P(0,0,319,219);
TEXTOUT_P("Modified Internal Rate of Return", 0, 10);
TEXTOUT_P("Safe rate " + EVAL(ROUND(sr*ppyr, 3)) + "%", 0, 30);
TEXTOUT_P("Risk rate " + EVAL(ROUND(rr*ppyr, 3)) + "%", 0, 50);
TEXTOUT_P("with " + STRING(ppyr) + " payments per year", 0, 70);
TEXTOUT_P("NPV negative flows " + STRING(ROUND(npvn,3)), 0, 90);
TEXTOUT_P("FV of posive flows NPV " + STRING(ROUND(fvp,3)), 0, 110);
TEXTOUT_P("MIRR monthly rate " + STRING(ROUND(mirrvalue,3)) + "%", 0, 130, 0, RGB(255,0,0));
TEXTOUT_P("MIRR yearly rate " + EVAL(ROUND(mirrvalue*ppyr, 3)) + "%", 0, 150, 0, RGB(255,0,0));
WAIT;
RETURN {mirrvalue, ppyr*mirrvalue}; // return monthly and yearly MIRR
END;
NPV(r, flows)
// routine by Eddie W. Shore
BEGIN
LOCAL t:=0, k, s;
r:=1+0.01*r;
CASE
// list
IF TYPE(flows)==6 THEN
s:=SIZE(flows);
FOR k FROM 1 TO s DO
t:=t+flows(k)/(r^(k-1));
END;
END;
// matrix
IF TYPE(flows)==4 THEN
LOCAL j, n;
s:=SIZE(flows);
k:=0;
FOR j FROM 1 TO s(1) DO
FOR n FROM 1 TO flows(j,2) DO
t:=flows(j,1)/(r^k)+t;
k:=k+1;
END; // for
END; // for 2
END; // if
DEFAULT
TEXTOUT_P("Use: NPV(rate, list) or NPV(rate, [flow, freq])", 0, 30);
END; // Case
sto(t, CF_NPV);
RECT_P(0,0,319,219);
TEXTOUT_P("NPV Net Present Value: " + EVAL(t), 0, 50, 0, RGB(255,0,0) );
RETURN t;
END;
recall_npv()
BEGIN
local ch, r;
INPUT (r, "Rate", "rate%", "Rate for Net Present Value", 0, 10);
CHOOSE(ch,"Flows List or Matrix w/ freq","Cash Flows List","CF Matrix whit frequencies");
CASE
IF ch==1 THEN
EDITLIST(L1, "Internal Rate of Return");
END;
IF ch==2 THEN
EDITMAT(M1, "Internal Rate of Return");
LOCAL flows:={}, j, k, s;
s:=SIZE(M1);
FOR j FROM 1 TO s(1) DO
FOR k FROM 1 TO M1(j,2) DO
flows:= append(flows, M1(j,1));
END; END; // for 1, 2
L1:= flows;
END;
DEFAULT
TEXTOUT_P("IRR() with {list} or [matrix with frequencies]", 0, 30);
END; // case
NPV(r, L1);
WAIT;
END;
about()
BEGIN
RECT_P(0,0,319,219);
TEXTOUT_P("Program created by by Salvo Micciché (salvomic)", 5, 10);
TEXTOUT_P("Credits", 5, 40, 0, RGB(0,255,0));
TEXTOUT_P("Cyrille de Brébisson, Akmon, Dale (DrD)", 5, 60);
TEXTOUT_P("Eddie W. Shore, Didier Lachiese, kharpster", 5, 80);
WAIT;
RETURN;
END;
∫aL√0mic (IT9CLU) :: HP Prime 50g 41CX 71b 42s 39s 35s 12C 15C - DM42, DM41X - WP34s Prime Soft. Lib
|