Stock Plot is a portfolio management and charting program that tracks up to 19 stocks, storing 26 weeks of price and volume data along with purchase price, number of shares, yearly high/low, and P/E ratio for each entry. The main menu offers eight functions: initial data entry, adding a stock in alphabetical order, correcting or deleting entries, updating current prices and volumes, plotting all or one stock graphically, listing statistics, and saving data. The plotting routine (lines 5000–5920) renders a price chart using CHR$ 128 (a block graphic) and detects cell content via PEEK of the display file address registers at 16398–16399 to overlay volume markers without overwriting price points. Statistics screens calculate portfolio cost, current value, profit/loss, and percent gain using VAL to convert string-stored numeric fields. Memory remaining can be checked via a PEEK-based calculation at line 9999.
Program Analysis
Program Structure
The program is organized around a numbered-menu dispatch system. The main menu at lines 10–90 reads a choice Q and jumps to Q*1000, routing options 1–8 to line blocks at 1000, 2000, 3000, 4000, 5000, 6000, 7000, and 8000 respectively. Each major functional block is largely self-contained, with shared subroutines in the 9000s range.
| Line Range | Function |
|---|---|
| 10–90 | Main menu and dispatch |
| 1000–1460 | Enter all stocks (initial data entry) |
| 2000–2115 | Add a stock in alphabetical order (insert with shift) |
| 3000–3030 | Correct or delete a stock |
| 4000–4155 | Enter current prices and volumes (weekly roll) |
| 5000–5920 | Plot all stocks graphically |
| 6000–6205 | Plot one stock (by symbol lookup) |
| 7000–7290 | List current statistics (two tables) |
| 8000 | Save data |
| 9000–9865 | Shared subroutines: error/correction menus, field re-entry, delete |
| 9990–9999 | SAVE routine and memory check |
Data Storage
All data for up to 19 stocks is held in parallel arrays. String arrays store fixed-width fields; numeric arrays hold the 26-week time series.
A$(19,5)— stock symbol (up to 5 characters)B$(19,4)— purchase price as a string (up to 4 characters)C$(19,5)— yearly high/low as a string (e.g., “50/30”)D$(19,2)— P/E ratio as a string (up to 2 characters)F$(19,4)— number of shares as a stringA(19,26)— 26-week price historyB(19,26)— 26-week volume historyD— current count of entered stocks
Numeric fields like purchase price, shares, and P/E are stored as strings and retrieved with VAL when arithmetic is needed. This avoids a separate numeric variable for each field but requires careful string-width discipline.
Weekly Data Roll
Option 4 (lines 4000–4155) implements a sliding window update. Before prompting for new data, it shifts all 26 weeks of prices and volumes one position earlier (A(I,N)=A(I,N+1) for N=1 to 25), then writes the new price and volume into position 26. This maintains a rolling 26-week history automatically.
Charting Routine
The price plot (lines 5100–5320) calculates the range around the purchase price L, determines the maximum excursion F (either upward O or downward M, whichever is greater), and derives a vertical scaling factor H=10/F. Prices are plotted using CHR$ 128 (the block graphic ▝) via PRINT AT. Horizontal axis labels show percentage values relative to purchase price at lines 0, 5, 10, 15, and 20.
The volume plot (lines 5400–5455) scales volumes against the maximum volume K across all 26 weeks. It uses a direct PEEK of the display file pointer registers at addresses 16398 and 16399 to read the character currently at the target screen position. If the cell already contains CHR$ 128 (a price point), it prints CHR$ 187 instead of “V”, allowing both price and volume to be visible at the same location.
Statistics Tables
Option 7 generates two sequential screens. The first (lines 7000–7095) lists each stock’s symbol, high/low, P/E, buy price, current price, and current/buy ratio. It also computes averages of buy price and current price across stocks, excluding index 1 (the loop starts at I=2), suggesting position 1 may be reserved for a benchmark or is intentionally skipped. The second table (lines 7200–7290) shows shares, cost basis, current value, profit/loss, and overall percentage gain for the portfolio.
Insert and Delete Operations
Adding a stock (option 2, lines 2000–2115) asks for the target index I, then shifts all arrays from D+1 down to I+1 one position upward using a FOR R=D+1 TO I+1 STEP -1 loop, making room for the new entry. Deletion (subroutine at line 9800) performs the reverse: it shifts entries from position I upward, overwriting the deleted entry, and decrements D.
Correction Subroutine
The correction menu at line 9300 presents nine options for re-entering individual fields. Input validation at line 9410 explicitly checks that Q$ is one of the digits “1”–”9″ before proceeding, looping back to INKEY$ at 9400 if not. Each field has its own re-entry subroutine in the 9500–9775 range.
Screen vs. Printer Output
The plot routines support both screen and printer output. At line 5000–5004, the user selects “S” or “P”, setting variable Z to either 6100 (screen pause) or 6200 (COPY to printer). The appropriate subroutine is then called via GOSUB Z after each chart is drawn — a clean use of a variable as a subroutine address.
Notable Bugs and Anomalies
- Lines 4110 and 4112 both read
FOR I=1 TO D; line 4110 is immediately superseded by line 4112, making the outer loop at 4110 redundant and effectively a no-op. - In the plotting loops at lines 5300–5325 and 5430–5455, the outer
FOR P=4 TO 4executes exactly once. This appears to be vestigial scaffolding from a design that intended multiple plot columns; as written,Pis always 4 andX=0+Pis always 4, soXserves no meaningful purpose. - Line 5300 uses
FOR P=4 TO 4but line 5320 incrementsNEXT P(afterNEXT Nat 5320,NEXT Pis at 5325) — the loop body is the innerNloop, so the structure is inverted from what the indentation implies. - Line 1425 calls
GOSUB 1250but line 1250 begins withLET D=D+1; using it as a subroutine entry point during the correction loop (option 1’s verify step) incrementsDspuriously each time a correction is made. - Line 9999 provides a memory check display but is only reachable by manually entering it as a
GO TOat runtime; it is not connected to any menu option. - The averages in the statistics table (lines 7041–7054 and 7231–7254) divide by
D-1, explicitly excluding the first stock entry. If only one stock is entered (D=1), this causes a division-by-zero error.
Memory Check Utility
Line 9999 computes free memory using 16384-(PEEK 16404+256*PEEK 16405-16283), reading the system variable that tracks the top of BASIC program space. This is a standard technique for reporting available RAM without calling FREE.
Content
Image Gallery
Source Code
10 PRINT AT 1,7;"STOCK PLOT: ""SP"""
15 PRINT AT 2,14;"BY"
20 PRINT AT 3,7;"KENDRIC C. SMITH"
25 PRINT AT 5,9;"%E%N%T%E%R% %N%U%M%B%E%R"
30 PRINT AT 7,1;"1 ENTER ALL STOCKS 1ST TIME IN ALPHABETICAL ORDER"
35 PRINT AT 9,1;"2 ADD A STOCK IN ALPHABETICAL ORDER"
40 PRINT AT 11,1;"3 CORRECT OR DELETE A STOCK"
45 PRINT AT 13,1;"4 ENTER CURRENT PRICES AND VOLUMES"
50 PRINT AT 15,1;"5 PLOT ALL STOCKS"
55 PRINT AT 17,1;"6 PLOT ONE STOCK"
60 PRINT AT 19,1;"7 LIST CURRENT STATISTICS"
65 PRINT AT 21,1;"8 SAVE STOCK DATA"
70 INPUT Q
75 CLS
80 IF Q<=8 THEN GOTO Q*1000
85 CLS
90 GOTO 10
1001 DIM A$(19,5)
1005 DIM B$(19,4)
1010 DIM C$(19,5)
1015 DIM D$(19,2)
1016 DIM F$(19,4)
1020 DIM A(19,26)
1025 DIM B(19,26)
1027 GOSUB 4145
1030 LET D=0
1035 FOR I=D+1 TO 19
1045 GOSUB 1100
1050 GOTO 1400
1100 PRINT AT 11,0;"ENTER STOCK SYMBOL: <= 5 LETTERS"
1105 INPUT A$(I)
1110 CLS
1111 PRINT AT 11,0;"ENTER NUMBER OF SHARES"
1112 INPUT F$(I)
1113 CLS
1115 PRINT AT 11,0;"ENTER PURCHASE PRICE:<= 4 SPACES"
1120 INPUT B$(I)
1125 CLS
1130 PRINT AT 11,0;"ENTER YEARLY HIGH AND LOW AS ""50/30"""
1135 INPUT C$(I)
1140 CLS
1145 PRINT AT 11,0;"ENTER %P%E RATIO (MAX 2 SPACES)"
1150 INPUT D$(I)
1155 CLS
1160 PRINT AT 11,0;"ENTER PRICES LAST 26 WEEKS"
1165 FOR N=1 TO 26
1170 INPUT A(I,N)
1175 NEXT N
1180 CLS
1185 PRINT AT 11,0;"ENTER VOLUMES? (Y/N)"
1190 INPUT Q$
1192 CLS
1195 IF Q$="N" THEN GOSUB 9100
1200 IF Q$="N" THEN GOTO 1245
1205 PRINT AT 11,0;"ENTER VOLUMES LAST 26 WEEKS"
1210 FOR N=1 TO 26
1215 INPUT B(I,N)
1220 NEXT N
1245 LET D=D+1
1250 CLS
1255 PRINT I;" ";A$(I);" ";F$(I);" ";B$(I);" ";C$(I);" ";D$(I)
1260 FOR N=1 TO 26
1265 PRINT A(I,N);" ";
1270 NEXT N
1272 PRINT
1275 FOR N=1 TO 26
1280 PRINT B(I,N);" ";
1285 NEXT N
1290 RETURN
1400 PRINT
1405 PRINT AT 10,0;"%A%L%L% %C%O%R%R%E%C%T%?% % %(%Y%/%N%)"
1410 INPUT Q$
1415 IF Q$="Y" THEN GOTO 1435
1417 PRINT AT 10,0;" "
1420 GOSUB 9300
1425 GOSUB 1250
1430 GOTO 1405
1435 CLS
1440 PRINT AT 6,0;"%A%N%Y% %M%O%R%E% %E%N%T%R%I%E%S%?% % %(%Y%/%N%)"
1445 INPUT Q$
1450 CLS
1455 IF Q$="Y" THEN NEXT I
1457 IF D+1=20 THEN GOTO 9000
1460 GOTO 85
2000 IF D+1=20 THEN GOTO 9000
2002 PRINT AT 11,0;"ENTER VALUE OF ""I"" WHERE NEW STOCK IS TO BE ENTERED"
2005 INPUT I
2010 CLS
2015 FOR R=D+1 TO I+1 STEP -1
2020 LET A$(R)=A$(R-1)
2025 LET B$(R)=B$(R-1)
2030 LET C$(R)=C$(R-1)
2035 LET D$(R)=D$(R-1)
2037 LET F$(R)=F$(R-1)
2040 FOR N=1 TO 26
2045 LET A(R,N)=A(R-1,N)
2065 LET B(R,N)=B(R-1,N)
2070 NEXT N
2075 NEXT R
2080 GOSUB 1100
2085 PRINT
2090 PRINT AT 10,0;"%A%L%L% %C%O%R%R%E%C%T%?% % %(%Y%/%N%)"
2095 INPUT Q$
2097 PRINT AT 10,0;" "
2100 IF Q$="Y" THEN GOTO 85
2105 GOSUB 9300
2110 GOSUB 1250
2115 GOTO 2085
3000 PRINT AT 11,0;"ENTER VALUE OF ""I"" OF LISTING TO BE CHANGED"
3005 INPUT I
3010 CLS
3015 GOSUB 1250
3020 GOSUB 9300
3025 GOSUB 1250
3030 GOTO 2085
4000 FOR I=1 TO D
4005 FOR N=1 TO 25
4010 LET A(I,N)=A(I,N+1)
4015 NEXT N
4020 NEXT I
4035 FOR I=1 TO D
4040 FOR N=1 TO 25
4045 LET B(I,N)=B(I,N+1)
4050 NEXT N
4055 NEXT I
4060 FOR I=1 TO D
4065 PRINT AT 11,0;"ENTER CURRENT PRICE OF: ";A$(I)
4070 INPUT A(I,26)
4075 CLS
4080 NEXT I
4085 CLS
4110 FOR I=1 TO D
4112 FOR I=1 TO D
4115 PRINT AT 11,0;"ENTER CURRENT VOLUME OF: ";A$(I)
4120 INPUT B(I,26)
4125 CLS
4130 NEXT I
4140 CLS
4142 GOSUB 4145
4143 GOTO 85
4145 PRINT AT 11,0;"ENTER THE DATE AS ""08/09/83"""
4150 INPUT E$
4155 RETURN
5000 PRINT AT 11,0;"PRINT TO SCREEN OR PRINTER?(S/P)"
5001 INPUT Q$
5002 CLS
5003 IF Q$="S" THEN LET Z=6100
5004 IF Q$="P" THEN LET Z=6200
5005 FOR I=1 TO D
5006 LET L=VAL B$(I)
5010 CLS
5100 LET J=5000
5105 LET K=0
5110 FOR N=1 TO 26
5115 LET X=A(I,N)
5120 IF X<=J THEN LET J=X
5125 IF X>=K THEN LET K=X
5130 NEXT N
5135 LET M=L-J
5140 LET O=K-L
5145 IF O>M THEN LET F=O
5150 IF M>O THEN LET F=M
5155 LET H=10/F
5160 PRINT AT 0,0;L+F;AT 5,0;L+(F/2);AT 10,0;L;AT 15,0;L-(F/2);AT 20,0;L-F
5165 LET W=10
5170 GOSUB 5900
5175 PRINT " ";"BUY"
5180 LET W=0
5185 GOSUB 5900
5190 PRINT " ";INT (((L+F)/L*100)+.5)
5195 LET W=5
5200 GOSUB 5900
5205 PRINT " ";INT (((L+(F/2))/L*100)+.5)
5210 LET W=15
5215 GOSUB 5900
5220 PRINT " ";INT (((L-(F/2))/L*100)+.5)
5225 LET W=20
5230 GOSUB 5900
5235 PRINT " ";INT (((L-F)/L*100)+.5)
5300 FOR P=4 TO 4
5305 FOR N=1 TO 26
5310 LET X=0+P
5315 PRINT AT ((A(I,N)-(L+F))*(-H)),X;CHR$ 128
5320 NEXT P
5325 NEXT N
5400 LET K=0
5405 FOR N=1 TO 26
5410 LET X=B(I,N)
5415 IF X>=K THEN LET K=X
5420 NEXT N
5425 LET H=K/20
5430 FOR P=4 TO 4
5435 FOR N=1 TO 26
5440 LET X=0+P
5442 IF B(I,N)=0 THEN GOTO 5800
5445 PRINT AT (B(I,N)-K)/(-H),X;
5446 IF PEEK (PEEK 16398+256*PEEK 16399)<>128 THEN PRINT "V"
5447 IF PEEK (PEEK 16398+256*PEEK 16399)=128 THEN PRINT CHR$ 187
5450 NEXT P
5455 NEXT N
5800 PRINT AT 0,13;A$(I)
5805 PRINT AT 20,11;E$
5810 IF Q$=A$(I) THEN GOTO 5825
5815 GOSUB Z
5820 NEXT I
5825 PRINT AT 21,0;"ENTER ""%C%O%N%T"" TO REGAIN 1ST MENU"
5830 STOP
5835 GOTO 85
5900 FOR N=5 TO 26
5905 LET X=0+N
5910 PRINT AT W,X;"-";
5915 NEXT N
5920 RETURN
6000 PRINT AT 21,14;"%E%N%T%E%R% %S%T%O%C%K% %S%Y%M%B%O%L"
6005 INPUT Q$
6010 FOR I=1 TO D
6015 IF Q$=A$(I) THEN GOTO 5006
6020 NEXT I
6025 GOTO 85
6100 PAUSE 400
6105 RETURN
6200 COPY
6205 RETURN
7000 CLS
7005 PRINT "%I% ";TAB 3;"%S%Y%M%B%L";" ";"%H%I%/%L%O";" ";"%P%E";" ";"%B%U%Y% ";" ";"% %C%P% ";" ";"%C%P%/%B"
7009 DIM C(19)
7010 FOR I=1 TO D
7012 LET C(I)=INT (((A(I,26)/VAL B$(I))*100)+.5)/100
7015 PRINT I;TAB 3;A$(I);TAB 9;C$(I);TAB 15;D$(I);TAB 18;VAL B$(I);TAB 23;A(I,26);TAB 28;C(I)
7020 NEXT I
7040 LET Z=0
7041 FOR I=2 TO D
7042 LET Z=Z+VAL B$(I)
7043 NEXT I
7044 LET G=INT ((Z/(D-1)*10)+.5)/10
7050 LET Z=0
7051 FOR I=2 TO D
7052 LET Z=Z+A(I,26)
7053 NEXT I
7054 LET S=INT ((Z/(D-1)*10)+.5)/10
7070 PRINT TAB 6;"AVERAGE:";TAB 18;G;TAB 23;S
7080 PRINT TAB 6;"%U%P%D%A%T%E%D% %O%N ";E$
7085 PRINT AT 1,18;" ";AT 1,28;" "
7090 PRINT AT 21,0;"KEY ""%C%O%N%T% %E%N%T%E%R"" FOR NEXT TABLE"
7095 STOP
7200 CLS
7201 DIM G(19)
7202 DIM H(19)
7203 DIM J(19)
7209 PRINT "%S%Y%M%B%L";TAB 6;"%S%H%R%S";TAB 11;"%C%O%S%T% ";TAB 17;"%V%A%L%U%E";TAB 23;"%P%R%O%F%.";TAB 29;"%O%/%O"
7210 FOR I=2 TO D
7211 LET G(I)=INT ((VAL F$(I)*VAL B$(I))+.5)
7212 LET H(I)=INT ((VAL F$(I)*A(I,26))+.5)
7213 LET J(I)=H(I)-G(I)
7215 PRINT A$(I);TAB 6;F$(I);TAB 11;G(I);TAB 17;H(I);TAB 23;J(I)
7220 NEXT I
7230 LET Z=0
7231 FOR I=2 TO D
7232 LET Z=Z+VAL F$(I)
7233 NEXT I
7234 LET E=Z
7240 LET Z=0
7241 FOR I=2 TO D
7242 LET Z=Z+G(I)
7243 NEXT I
7244 LET F=Z
7250 LET Z=0
7251 FOR I=2 TO D
7252 LET Z=Z+H(I)
7253 NEXT I
7254 LET S=Z
7260 LET Z=0
7261 FOR I=2 TO D
7262 LET Z=Z+J(I)
7263 NEXT I
7264 LET U=Z
7270 PRINT "TOTAL:";TAB 6;E;TAB 11;F;TAB 17;S;TAB 23;U;TAB 29;INT (((S/F)*100)+.5)
7280 PRINT TAB 6;"%U%P%D%A%T%E%D% %O%N ";E$
7290 GOTO 9005
8000 GOTO 9990
9000 PRINT AT 11,10;"%M%E%M%O%R%Y% %F%U%L%L"
9005 PRINT AT 21,0;"ENTER ""%C%O%N%T"" TO REGAIN 1ST MENU"
9010 STOP
9015 GOTO 85
9100 FOR N=1 TO 26
9105 LET B(I,N)=0
9110 NEXT N
9115 RETURN
9300 PRINT AT 11,6;"%W%H%A%T% %I%S% %I%N%C%O%R%R%E%C%T%?"
9305 PRINT TAB 9;"%E%N%T%E%R% %N%U%M%B%E%R"
9310 PRINT "1 STOCK SYMBOL"
9315 PRINT "2 PURCHASE PRICE"
9320 PRINT "3 YEARLY HI/LO"
9325 PRINT "4 PRICES LAST 26 WEEKS"
9330 PRINT "5 VOLUMES LAST 26 WEEKS"
9335 PRINT "6 PE RATIO"
9337 PRINT "7 NO. SHARES"
9340 PRINT "8 EVERYTHING, DELETE STOCK"
9345 PRINT "9 NOTHING, RETURN TO 1ST MENU"
9400 LET Q$=INKEY$
9405 INPUT Q$
9410 IF Q$<>"1" AND Q$<>"2" AND Q$<>"3" AND Q$<>"4" AND Q$<>"5" AND Q$<>"6" AND Q$<>"7" AND Q$<>"8" AND Q$<>"9" THEN GOTO 9400
9415 IF Q$="1" OR Q$="2" OR Q$="3" OR Q$="4" OR Q$="5" OR Q$="6" OR Q$="7" OR Q$="8" OR Q$="9" THEN CLS
9420 IF Q$="1" THEN GOSUB 9500
9425 IF Q$="2" THEN GOSUB 9550
9430 IF Q$="3" THEN GOSUB 9600
9435 IF Q$="4" THEN GOSUB 9650
9440 IF Q$="5" THEN GOSUB 9700
9445 IF Q$="6" THEN GOSUB 9750
9447 IF Q$="7" THEN GOSUB 9765
9450 IF Q$="8" THEN GOTO 9800
9455 IF Q$="9" THEN GOTO 85
9460 CLS
9465 RETURN
9500 PRINT AT 11,0;"ENTER CORRECT SYMBOL"
9505 INPUT A$(I)
9510 RETURN
9550 PRINT AT 11,0;"ENTER PURCHASE PRICE"
9555 INPUT B$(I)
9560 RETURN
9600 PRINT AT 11,0;"ENTER YEARLY HI/LO"
9605 INPUT C$(I)
9610 RETURN
9650 PRINT AT 11,0;"ENTER PRICES LAST 26 WEEKS"
9655 FOR N=1 TO 26
9660 INPUT A(I,N)
9665 NEXT N
9670 RETURN
9700 PRINT AT 11,0;"ENTER VOLUMES LAST 26 WEEKS"
9705 FOR N=1 TO 26
9710 INPUT B(I,N)
9715 NEXT N
9720 RETURN
9750 PRINT AT 11,0;"ENTER %P%E RATIO"
9755 INPUT D$(I)
9760 RETURN
9765 PRINT AT 11,0;"ENTER NO. OF SHARES"
9770 INPUT F$(I)
9775 RETURN
9800 FOR R=I TO D-1
9805 LET A$(R)=A$(R+1)
9810 LET B$(R)=B$(R+1)
9815 LET C$(R)=C$(R+1)
9816 LET D$(R)=D$(R+1)
9817 LET F$(R)=F$(R+1)
9820 FOR N=1 TO 26
9825 LET A(R,N)=A(R+1,N)
9845 LET B(R,N)=B(R+1,N)
9850 NEXT N
9855 NEXT R
9860 LET D=D-1
9865 GOTO 85
9990 SAVE "S%P"
9995 GOTO 10
9999 PRINT AT 11,4;"MEMORY LEFT: ";16384-(PEEK 16404+256*PEEK 16405-16283);" BYTES"
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.