Classic Computer Magazine Archive CREATIVE COMPUTING VOL. 9, NO. 2 / FEBRUARY 1983 / PAGE 188

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.