Financial analysis for the Apple II. Skene Moody.
One of the primary uses for which I bought a microcomputer was to calculate the percentage rate of return on either actual or potential investments. I also wanted to be able to maintain modifiable disk records of the amounts and dates of such investments.
To satisfy these needs I needed a calendar-date-based database as well as a program which could perform Internal Rate of Return analysis on the data.
The Applesoft program Financial Analysis satisfies both objectives and does much more. The program is a menu-driven, user-oriented modular program with prompts. It offers a calendar-date-based modifiable financial database, and can READ/SAVE data from/to disk.
You can enter individual cash flows and have the computer generate a series of equal-amount flows by defining first and last dates, and the number of intervals (months, days, or years) between flows.
You can also modify dates or flows of individual data records, delete data by individual record number or dates, review all or part of the data on the screen, search for data record(s) by amount of cash flow, sort data by date, combine flows with same dates, and eliminate records with zero flows.
There is an efficient Newton routine to solve for Internal Rate of Return, and you can print a summary or detailed results (formatted) on an 80-column printer with page numbers and headers on each page.
The program also includes a short, transportable machine language routine which allows INPUT of strings with leading or imbedded commas, colons, or quotation marks and transportable sub-routines which calculate the day number from a given month, day of month, and year (useful for calculating the number of days between dates) and the month, day, and year from the day number.
Also included is a formatting sub-routine which allows you to specify dynamically the right-justified field width and the number of digits after the decimal. The routine inserts commas as appropriate to improve the appearance of the output.
Some applications for which I have used the program include calculating yields for common stocks considering both appreciation in per share price and dividends paid, calculating bond-yield-to-maturity, and calculating yields on Treasury bills.
I have also determined the yield (return) for my company stock purchase plan during the entire period I have participated and during the latest calendar year, calculated the true annual interest rate on my mortgage loan considering "points" and prepayment penalties, and found the true interest rate on my bank savings account and credit union share accounts.
Examples Let's consider a very simple example: A $100 investment on January 1, 1981
and a return of $100 one year later. When
you run the program, after a brief delay while the program initializes variables and POKEs the machine language routine, you will see a menu with 11 choices.
Choose option 2 (INPUT DATA FROM KEYBOARD OR DISK). AND YOU WILL SEE THE DATA ENTRY SUB-MENU. Select option 2 of the sub-menu (INPUT SINGLE CASH FLOW DATA), and a data format window will be displayed on the screen.
Enter the following data: 1, 1, 81, -100 1, 1, 82, 110
Note that I use the convention that cash outflows are negative and inflows are positive. You may want to use the opposite convention--the only program constraint is that outflows have the opposite sign from inflows.
Next, type E to end single-flow data entry. Now type 4 (RETURN TO MAIN MENU), since you are finished with all data entry. Type 8 (CALCULATE INTERNAL INTERNAL RATE OF RETURN), and after the data are sorted (they are not needed in this case, but the program has no way of knowing this) answer the question DO YOU WANT TO ANALYZE (A)LL OR (S)OME OF THE DATA? with A.
Next, you will see the various interest rates the program tries while solving for the correct interest rate, and then the final result will again appear on the screen. These results include the first and last dates included in the analysis, the effective annual interest rate (10.007%), the sum of positive flows (110.00), the sum of negative flows (100.00), the sum of all stock flows (10.00), the daily interest rate (2.6115759E-04) and the number of iterations (4) the program needed to solve for the interest rate.
You are probably wondering why the interest rate determined by the program was 10.007% rather that the expected 10.000%. I have chosen this example to show the one approximation the program uses. The effective interest rate calculated by the program is for a 365.25-day year. This is the average number of days in a year and results in increasingly accurate interest rates as study durations increase.
In this particular case, since 1981 is not a leap year, the conventional answer can be calculated from the daily interest rate by the following formula:
((1 + 2.6115759E-4)[upper arrow] 365-1) x 100 = 10.000%
This relationship is defined as FNA(X) in line 11080 of the program except that 365.25 is used instead of 365. Yield on Common Stock
Let's look at an example which evaluates the yield on a common stock. Suppose the stock sold for $25.75 at the end of 1978 and paid a $0.62 dividend at the end of January, April, and July of 1979; a $0.68 dividend at the end of October, 1979 and also at the end of January, April, and July of 1980; and $0.74 at the end of October, 1980. Finally, assume the stock was quoted at $25.62 at the end of 1980.
The data to be entered are:
12, 31, 78, -25.75 1, 31, 79, .62 4, 30, 79, .62 7, 31, 79, .62 7, 31, 79, .62 10, 30, 79, .68 1, 31, 80, .68 4, 30, 80, .68 7, 31, 80, .68 10, 30, 80, 25.62
Finanical Analysis, continued...
When the results are calculated, we see that the effective rate of return is 10.637%. Although this is not a spectacular yield at today's high inflation rates, the example does point out that a positive return can be earned on a stock even though the sale price of the stock is lower than its purchase price and that dividends must be considered when calculating stock yields.
The example also reminds me to mention that the "Internal" in "Internal Rate of Return" implies that the method assumes no reinvestment of dividends or other cash returns. If the dividends had been reinvested, the owner would have more than one share of the stock to sell at the end of 1980, the $25.62 flow would be increased, and the analysis would result in a higher yield. True Interest Rate
Finally, let's evaluate the true interest rate of a loan. Assume a lender agrees to lend you $6000 for three years at 17% interest on December 31, 1980 and tells you (correctly) that you will have monthly payments of $213.92 at the end of each month from January 31, 1981 through November 30, 1983 plus a final payment of $213.76 on December 31, 1983 (total of 36 payments).
To enter the data, use the INPUT SINGLE CASH FLOW DATA option (2) of the DATA ENTRY SUB-MENU to enter the initial (+) amount of the loan and the final (-) payment.
Use the INPUT SERIES OF CASH FLOW DATA option (3) of the sub-menu to enter the parameters needed for the program to generate the other (-) payments. If you REVIEW the data (main menu 5) you will note that the program automatically calculates the correct end dates of each month (28, 30, or 31 days).
After you return to the main menu and type 8 to branch to the CALCULATE INTERNAL RATE OF RETURN subroutine, the program will calculate the interest rate as 18.434%. This is very close to the theoretical answer which is obtained from the following calculation:
((1 + .17/12) =upper arrow+ 12-1.0) x 100 = 18.389%
The calculated interest rate is higher than the quoted interest rate of 17% since the loan is compounded monthly. The slight difference between the theoretical interest rate and the rate calculated by the program is because the program considers the actual number of days between payments and also because of the 365.25-day convention discussed earlier. System Notes
The program was written for an Apple II Plus (Applesoft in ROM) system with 48K RAM and one disk drive. If all REMs are removed, line 12030 is replaced with return, lines 12040 through 12270 are deleted and N in line 11030 is changed to 500, the program should run on a 32K system with a disk and Applesoft in ROM. Printer Notes
The program was written to support a Microtek MT-80P 80-column printer interfaced with an Apple Centronics Parallel Interface Card in slot 1. The user may have to modify lines 5680 and 5720 to suit his particular printer.
Also, the CHR$(12) in lines 5590 and 5720 causes a form feed (top-of-form) to be executed on my printer. The CHR$(28) in lines 5490 and 5610 causes my printer to print wide (five characters/inch) letters and the CHR$(29) in lines 5490 and 5620 causes my printer to output "normal" (10 characters/inch) letters. Credits
The Speeding in Applesoft routine which appears as part of lines 4030, 4240, 4260, 7060, 7220, and 11050 is from an article by Roger Wagner in the September 1979 issue of Call-A.P.L.E. Temporarily altering the "beginning" of an Applesoft program can reduce execution time since Applesoft searches for "destination" line numbers from GOTOS, IF ... THENs, etc., from the "beginning" of the program.
Line 11050 places the pointers to the original beginning of the program into the variables P1 and P2. Lines 4030 and 7060 temporarily substitute the location of the current statement into the locations for the beginning of the program. Lines 4240, 4260, and 7220 restore the original program start addresses before the subroutine is exited.
The Input Anything routine which involves lines 1290, 3330, 5370, 9040, 10040, 11030, and 11110-11170 is from an article by Val J. Golding in the July-August, 1980 issue of Call-A.P.P.L.E.
The machine language routine in lines 11110-11170 uses the first defined string in an Applesoft program (in this case IN$) as a temporary buffer. The routine allows the user to input strings containing leading or imbedded commas, colons, or quotation marks. Syntax is as follows: CALL 768:A$ = MID$(IN$, 1). A$ is the variable in which the string is to be INPUT. Program Description Line Number Description
10-60 Remarks.
100-360 Displays Main Memu on the screen and
asks for user to select option.
1000-1110 Data entry sub-menu. 1120-1240 display data format window on screen. 1250-1440 Subroutine to input month, day, year, and
cash flows.
1450-1490 Routine to enter single cash flows. 1500-1630 Subroutine to enter the required data for
the program to generate a series of constant-amount cash flows.
1640-1670 Subroutine which generates a series of
constant-amount cash flows which have an interval between flows which is a multiple of one day.
1680-1770 Subroutine which generates a series of cash
flows which have an interval between flows which is a multiple of one month.
1780-1840 Subroutine which generates flows with an
interval between flows which is a multiple of one year.
2000-2050 Subroutine which allows the user to modify
individual date and flow records given the number of the record. The number of a record can be found by "Reviewing" the data (option 5 on the main menu).
3000-3100 Sub-menu to delete data. 3110-3160 Subroutine which asks user to enter the
first and last (if more than one) record number to be deleted. If only one record is to be deleted the program displays the data and asks the user to confirm that the correct record was located.
3170 deletes a range of records. 3180-3190 Search for the record to be deleted and if it
is found, go to line 3200 where it is deleted.
3200 Does the actual deleting of one record. 3210-3240 Sort data by date if they are not already
sorted and request inputs from the user to Define the date(s) of data records which are to be deleted.
3250-3280 Delete all records within a range of dates. 3290-3330 Delete the single data record which contains
the user-specified date and ask whether other single-date records are to the deleted.
3340-3410 Search for and display all data records
which contain cash flows within one cent of a user-specified flow.
4000-4030 Applesoft speedup routine (see Credits). 4050-4080 Review routine--asks whether user wants
to review all or some of the data and if the latter, asks user to input beginning and ending dates.
4090-4110 Print column headers and "window" the
headers.
4120-42 Display the range of data specified. Displayed
data include record number, date, amount of flow, cumulative flow and an asterisk (*) if there is a reversal in sign of the cumulative cash flow at the displayed flow
4260 Applesoft speedup routine. 5000-5100 determine whether all or some of the data
are to be included when calculating Internal Rate of Return. If the latter, ask user to input the first and last dates to be included and find the appropriate beginning and ending record number.
5110-5140 Main calculation routine. This iterative
Routine uses Newton's method to determine to the last-tried interes rate (IR) to obtain the next trial interest rate. Note that if There is more than one reversal in the sign of the cumulative cash flows (sorted data), more than one interest rate is mathematically correct. While this program may find one of the solutions, it is not able to find or indicate other possibilities.
5150-5260 Print results on screen. Ask whether user
desires results to be printed on printer.
5270-5290 If printer results are requested, ask whether
Summary (same as screen) or detailed (also prints all dates and flows) Results are desired.
5300-5330 Print summary results on printer. 5340-5580 Print detailed results on printer after asking
user to enter the (maximum of 40 characher) title which will be printed at the top of each page.
5590 Prints page number at top of each page 5600-5620 Print title at top of each page. 5630-5640 Print column headers at top of page. 5650-5680 Turn printer on (see Printer Notes). 5690-5720 Turn printer off. 6000-6130 Format rountine. The routine is entered with
the number to be formatted (XX), the width of the right-justified field (W%), and the number of digits after the decimal (X%). The routine zero-fills after the decimal if needed, adds commas as appropriate, and outputs the resultant string (A$). If the number is too large for the field, asterisks are printed.
7000-7130 Sort routine. The routine uses the insertion
sort which is generally regarded as slow. However, it is the fastest routine for data which is in near-sorted form. Since I generally enter data in data-order or add only a few items to a previously sorted array, this method was selected. Line 7060 is part of the Applesoft speedup routine. Lines 7070 and 7080 place the day number relative to the date of the first data record into D% (I,0 to use as the sort key. This is done since the day number is a six-digit number and an integer variable can only hold values as large as 32,767 (approximately 89.7 years). Thus, a program limitation is that all dates must be no more than 89.7 years away from the date of the first data record.
7140-7250 Combine flows with same dates and eliminate
records with zero flows.
8000-8040 Calculate six-digit day number from
month, day-of-month, and last two digits of year. To minimzie the amount of keyboard board data entry I decided to write the program to require entry of only the last two digit of the year. Naturally, this limits its the range of dates which the program can handle to a span of 100 years. Limitations in the largest number which can be held in an integer variable effectively reduce this range to less than 90 years. The 45 in line 8030 positions the partition--the number 45 will be interpreted as 1945 and the number 44 will be interpreted as 2044.
8200-8300 Calculate month, day-of-month, and last
two digits of year from six-digit day number.
9000-9100 Read data from disk. Note that data from
several data files can reside in the program simultaneously.
10000-10100 Save data to disk. 11000-11090 Initialize variables. IN$ must be the first
string variable defined in the program--it is used as a temporary buffer for the Input Anything Routine. N in line 11080 dimensions
the date and flow arrays and can be
modified to suit individual system requirements. Each
100 change in N changes
RAM requiriements by 1500 bytes.
11100-11180 Machine language to implement the
Input Anything Routine.
12000-12270 Brief program description.
Variables A Numeric variable used for input Statements. A$ String vairable used for input statements. Also used as the output string in the Format (6000 series) subroutine. Al Numerical input vairable containing the number of periods between equal-value flows in the Data Entry (1000 series) subroutine. Al$ String input used in the Review Data (400 series) subroutine. Also holds the title which is printed on each page of the detailed printer output (5000 series).
Al$(I) Holds the words Days, Months, or
Years for I==1 to 3 respectively which are used in the prompt in line 1600. AS$ Holds either blanks or blanks plus an asterisk (*) as appropriate to indicate a reversal in the sign of the cumulative cash flows. B% Temporary variable used in the Format subroutine.
C and C$ Temporary variables used in Format
subroutine.
Cl and C2 Hold either cumulative sum of cash flows,
present value of cash flows, or sum of positive and negative cash flows as appropriated in the Review Data (4000 series) or Calculate Results (5000 series) subroutines. D Temporary variable holding the day of the month in the Data Entry subroutine between lines 1540 and 1820. D$ Apple Disk Operating System (DOS) deferred-execution Control character. Defined as Return + CTRL-D in line 1140.
D%(I,J) Date array, I==record number (1 to NS). J
can have values from 0 to 3: D%(I,0 holds the day number relavtive to the day number of the first data record. D%(I,1) holds the month (1 to 12); D%(I,2) holds the day of the month; and D%(I,3) holds
the lasft two digits of the year (e.G., 80 for
1980). Dl Holds either a six-digit day number designating the first date in a range of dates or the first record number in a range of record numbers. These ranges appear in Data Entry (1000 series), Modify (2000 series), Delete (3000 series), Review (4000 series), and Calcuate Results (5000 series). D2 Holds the last date or record number in a Range of dates (see Dl).
D3 and D4 Temporary first and last dates used in Calculate
Results (5000 series) subroutine. DE Flag used in the Data Input subroutine (lines 1260-1440) to indicate (if DE==1) that the routine was entered from the Delete subroutine. Dl Contains the value by which the last daily interest rate (IR) should be changed to obtain the next interest rate when solving for Internal Rate of Return (lines 5110 to 5140). DK Used in lines 9100 and 10030 to indicate (if DK==1) that data have been read from the disk. DN Contains the six-digit day number calculated in lines 8030 and 8040 from the month, day-of month, and year. DX Six-digit day number calculated in line 7070 from the date of the first data record. F Temporary variable holding the cash flow to be used when generating a series of flows in lines 1540, 1670, and 1810. Also used to hold the cash flow being searched for in line 3400.
FL(I) Contains the individual cash flows for each
data record. I General subscript and loop variable. Note, however, that the subscript I must be used to enter the subroutine which calculates the day number from the month, day-of-month, and year in lines 8030 and 8040. IN$ General string input variable used by the Input Anything Routine (see Credits). IR Latest estimate of the daily interest rate in the Calculate Financial Results subroutine (5000 series). J Temporary subscript or loop index. K Temporary subscript. K$ Temporary input string in line 4250. Kl 36525 (100 * Average number of days in a year). K2 365.25 (Average number of days in a year). K3 367 (used in calculating the month, day and year from a given day number--lines 8230 to 8300). K4 4 (used in calculating the day number from a given month, day, and year in line 8040). K5 9 (used in line 8040). K6 12 (used in lines 8040 and 8260). K7 7 (used in line 8040). K8 27 (used in line 8040). K9 122.1 (used in line 8230). L1 30.6001 (used in lines 8230 and 8240). L2 1900 (used in lines 8030 and 8270). L3 temporary variable (lines 8030 and 8040). LN Line number of screen or printer output. M Temporary variable. Contains the number of the month (1-12). M1 Temporary variable used in line 1710. MX Maximum number of iterations (line 5110) allowed to calculate the Internal Rate of Return. N Temporary variable. NR Number of active records. NS Total number of data records, active + inactive. NX Temporary, 9000 series.
P1 and P2 Low and high bytes of the pointer to the
original beginning of the program. Used in Applesoft speedup routine. P3 Temporary beginning of program used in lines 4030 and 7060 as part of the Applesoft speedup routine. PG Page number. Used when printing detailed output to the printer. Q$ Temporary input string (line 3310).
R%(I) Integer array which contains the sorted or
unsorted (before sort routine is called) order
of the data records. For example if
R%(.) contains the value 3, this means that the ninth-in-order record is record number 3. RV Reversal counter. Counts the number of reversals in sign of the cumulative cash flow. SR Sort flag. If SR==1 then the data is in date-sorted order. T$ Contains the name of the last-read disk data file. TB Tab value for print statemtns. TB==0 (line 5150) for screen results and TB==20 (line 5330) for summary results on printer. TE Temporary subscript. TL Tolerance for change in daily interest rate. If the calculated change in interest rate (DI) is less than TL, then the Internal Rate of Return is considered to have been solved to sufficient accuracy. TM Temporary subscript W% Width of output field in Format (6000 series) subroutine. X Temporary variable in 5000 series of line numbers. Dummy variable in defining FNA(x) (line 1180). X% Number of places after the decimal point in Format (6000 series) subroutine. XX Variable used to hold the number to be formatted in the Format (6000) series) subroutine.
Y and YY Temporary storage of the number of the
year, Y holds the last two digits only; YY holds the four-digit value.