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.