Stock Market Simulation

This file is part of and Timex Sinclair Public Domain Library Tape 1003. Download the collection to get this file.
Developer(s): Donald Burgio
Date: 198x
Type: Program
Platform(s): TS 1000

This program simulates a simple stock market where the player trades shares in five fictional companies (AAA through EEE) starting with $10,000 in capital. Each trading day the player enters buy or sell quantities for each stock, with a 1% brokerage fee applied to all transactions. Stock prices change each turn using a combination of a market-wide trend factor, random noise, and occasional “bull” or “bear” events that apply a ±4 point shock to a randomly selected stock. The program also simulates dividend payments and stock splits, and tracks a running exchange average similar to a market index.


Program Analysis

Program Structure

The program is divided into several logical sections:

  1. Initialization (lines 10–120): Sets up string arrays for stock ticker names, defines the price-formatting expression string A$, and jumps to the main setup block.
  2. Currency Formatter Subroutine (lines 130–220): Converts a numeric value in G into a formatted dollar string R$ with exactly two decimal places, returning the string length in L.
  3. Game Setup (lines 230–780): Initialises stock prices, asks for the player name, optionally shows instructions, and waits for the player to press S to start.
  4. Main Display Loop (lines 790–2000): Displays stock prices, portfolio value, handles player transactions, updates prices, and checks for special events (dividends, splits).
  5. Price Update Subroutine (lines 2010–2500): Called via GOSUB 2010 each turn; updates all five stock prices with random noise, a trend factor, and occasional bull/bear shocks.
  6. End Game (lines 2510–2800): Displays profit/loss summary and waits for the player to press S to return to BASIC.

Currency Formatting Subroutine (lines 130–220)

The subroutine at line 130 is the most algorithmically involved part of the program. It extracts integer and fractional parts of G using ABS, INT, and subtraction, then patches up the fractional portion to always produce two decimal digits. The logic at lines 170–200 handles three cases:

  • If the fractional part is zero, O$ is set to "00".
  • If the fractional part is non-zero, it multiplies by 100 and converts to a string.
  • If the resulting string has a decimal point in its second character (i.e., the value was less than 0.10), it multiplies by 1000 instead to recover a leading zero — a workaround for STR$ not zero-padding.

The formatted result is assembled as Z$+"."+O$ and its length stored in L for right-aligned TAB printing.

Stock Price Update Algorithm

The subroutine at line 2010 updates all five stock prices each day. It uses a market-wide factor A (a small positive or negative decimal, rerolled periodically by the sub-subroutine at line 2460) multiplied by the current price, plus a random component selected from four quantised levels (0, 0.25, 0.5, 0.75), plus an integer noise term INT(3-6*RND+.5) which ranges from −3 to +3.

Two “event” counters D1 and D2 track countdown timers for bull (BC=4) and bear (BC=-4) shocks. When a counter expires the shock is applied to one randomly chosen stock. The counters are initialised and reset via VAL A$, which evaluates the expression "INT(RND*4.99)+1" stored at line 50 to produce a random integer from 1 to 5.

Notable Techniques

  • VAL A$ as a reusable RNG expression: The string A$="INT (RND*4.99)+1" is evaluated with VAL wherever a random integer from 1–5 is needed. This is a compact way to reuse an expression without a subroutine and also saves token memory.
  • Right-aligned currency printing: Values are right-aligned using TAB (N-L) where L is the length of the formatted string returned by the formatter subroutine, giving a columnar appearance without fixed-width formatting.
  • Flicker-free title animation: Lines 390–410 alternate printing an inverse-video version and a normal version of the title banner in a loop of 20 iterations, creating a simple blinking effect.
  • POKE 16437,255: This pokes the ZX81 system variable FRAMES (low byte) to reset the frame counter, effectively preventing an unwanted BREAK or timeout after a PAUSE statement — a well-known ZX81 technique.
  • Random number truncation at line 1930: VAL ((STR$ RND)(1 TO 4)) takes the first four characters of the string representation of a random number, then evaluates it back to a float. This clips the value to at most three decimal places and is used to produce a scaled random value for dividend/split decisions.

Bugs and Anomalies

LineIssue
720LET S=(5)=115 is syntactically malformed. The intent is LET S(5)=115 (initialise the fifth stock price). As written, this evaluates (5)=115 as a boolean (false=0) and assigns the result to the scalar variable S, leaving S(5) at its default value of 0.
1980IF B>.93 should almost certainly be IF R>.93 (checking the random value for a stock split). B is not defined in this scope, so the condition likely always evaluates as false, meaning stock splits never trigger.
1990The stock split doubles P(I) (shares held) but does not halve S(I) (price per share). A real split should halve the price and double the shares to keep total value constant; as written the player’s portfolio value doubles on a split.
2110LET D2=D2-2 decrements D2 by 2 each day while D1 is decremented by 1. This means the bear-shock counter expires roughly twice as fast as the bull-shock counter, creating an asymmetric market bias.
1570The oversell check IF -T(I)<=P(I) is inverted. When T(I) is negative (a sell order), -T(I) is the number of shares being sold. The condition allows the sale if the number sold is ≤ shares held, which is correct, but the logic only reaches this line when T(I)<=0 (line 1530), so a zero-share “sell” of 0 passes through without issue.

Variable Summary

VariablePurpose
A$Expression string for random integer 1–5, evaluated with VAL
I$(5,3)Ticker symbols for the five stocks
S(5)Current share prices
P(5)Shares held in portfolio
T(5)Transaction quantities entered by player
C(5)Daily price change per stock
CCash balance
AMarket trend multiplier (signed small decimal)
D1, D2Countdown timers for bull/bear shock events
GInput value to currency formatter subroutine
R$, LFormatted string and its length, returned by formatter
DYDay counter
FFlag: 0 on first pass, 1 after first trading day
EAExchange average (mean of five prices)

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

  10 REM STOCK MARKET SIMULATION
  20 REM BY DONALD A. BURGIO
  25 CLS 
  30 DIM I$(5,3)
  40 DIM O$(2)
  50 LET A$="INT (RND*4.99)+1"
  60 LET I$(1)="AAA"
  70 LET I$(2)="BBB"
  80 LET I$(3)="CCC"
  90 LET I$(4)="DDD"
 100 LET I$(5)="EEE"
 110 RAND 
 120 GOTO 230
 130 LET X=ABS G
 140 LET B=INT X
 150 LET E=X-B
 160 LET Z$=STR$ B
 170 IF E=0 THEN LET O$="00"
 180 IF E<>0 THEN LET O$=STR$ (100*E)
 190 IF O$(2)="." THEN LET O$=STR$ ((1000*E)+.01)
 200 LET R$=Z$+"."+O$
 210 LET L=LEN R$
 220 RETURN 
 230 LET A=INT ((RND/10)*100+.5)/100
 240 DIM S(5)
 250 DIM P(5)
 260 DIM T(5)
 270 DIM C(5)
 280 LET TT=0
 290 LET F=0
 300 LET D1=0
 310 LET D2=0
 320 LET P=0
 330 LET P2=0
 340 LET DY=0
 350 LET EA=0
 360 SLOW 
 370 CLS 
 380 FOR I=1 TO 20
 390 PRINT AT 0,0;"% % % % % % %T%H%E% %Z%X% %S%T%O%C%K% %E%X%C%H%A%N%G%E% % % % % "
 400 PRINT AT 0,0;"% % % % % % THE ZX STOCK EXCHANGE% % % % % "
 410 NEXT I
 420 PRINT AT 3,0;"WHAT IS YOUR NAME?"
 430 INPUT N$
 440 PRINT AT 3,0;"DO YOU WANT INSTRUCTIONS?  (Y/N)"
 450 INPUT Z$
 460 IF Z$="N" THEN PRINT AT 3,0;"                                "
 470 IF Z$="N" THEN GOTO 680
 480 CLS 
 490 PRINT "WELCOME TO THE ZX STOCK EXCHANGE"
 500 PRINT TAB ((32-LEN N$)/2);N$+"."
 510 PRINT "YOUR ACCOUNT CURRENTLY CONTAINS"
 520 PRINT "$10,000.  YOU MAY BUY OR SELL"
 530 PRINT "STOCKS.  A TABLE OF AVAILABLE "
 540 PRINT "STOCK, THEIR PRICES, AND THE"
 550 PRINT "NUMBER OF SHARES IN YOUR PORT-"
 560 PRINT "FOLIO WILL BE PRINTED.  FOLLOW-"
 570 PRINT "ING THIS THE INITIALS OF EACH"
 580 PRINT "STOCK WILL BE PRINTED.  HERE YOU"
 590 PRINT "INDICATE A TRANSACTION.  TO BUY"
 600 PRINT "A STOCK TYPE XXX, WHERE XXX IS"
 610 PRINT "THE NUMBER OF SHARES YOU WISH TO"
 620 PRINT "BUY.  TO SELL TYPE -XXX, WHERE"
 630 PRINT "-XXX IS THE NUMBER OF SHARES YOU"
 640 PRINT "WISH TO SELL.  A 1 PERCENT BRO-"
 650 PRINT "KERAGE FEE WILL AUTOMATICALLY"
 660 PRINT "BE CHARGED TO YOUR ACCOUNT."
 670 PRINT TAB 11;"GOOD LUCK"
 680 LET S(1)=130
 690 LET S(2)=90
 700 LET S(3)=120
 710 LET S(4)=85
 720 LET S=(5)=115
 730 LET TR=VAL A$
 740 PRINT AT 21,7;"PRESS S TO START."
 750 IF INKEY$="S" THEN GOTO 790
 760 PRINT AT 0,0;"%W%E%L%C%O%M%E% %T%O% %T%H%E% %Z%X% %S%T%O%C%K% %E%X%C%H%A%N%G%E"
 770 PRINT AT 0,0;"WELCOME TO THE ZX STOCK EXCHANGE"
 780 GOTO 750
 790 IF RND>.5 THEN GOTO 810
 800 LET A=-A
 810 CLS 
 820 GOSUB 2010
 830 LET C=10000
 840 PRINT 
 850 PRINT "STOCK              INT.  $/SHARE"
 860 PRINT "--------------------------------"
 870 LET G=S(1)
 880 GOSUB 130
 890 PRINT "A AND A ASSOCIATES AAA ";TAB (32-L);R$
 900 LET G=S(2)
 910 GOSUB 130
 920 PRINT "B AND B BUYERS     BBB ";TAB (32-L);R$
 930 LET G=S(3)
 940 GOSUB 130
 950 PRINT "C AND C COAL CO.   CCC ";TAB (32-L);R$
 960 LET G=S(4)
 970 GOSUB 130
 980 PRINT "D AND D DEVELOPERS DDD ";TAB (32-L);R$
 990 LET G=S(5)
 1000 GOSUB 130
 1010 PRINT "E AND E ENERGY     EEE ";TAB (32-L);R$
 1020 LET TA=EA
 1030 LET EA=0
 1040 LET SA=0
 1050 FOR I=1 TO 5
 1060 LET EA=EA+S(I)
 1070 LET SA=SA+S(I)*P(I)
 1080 NEXT I
 1090 LET EA=INT (100*(EA/5)+.5)/100
 1100 LET NC=INT ((EA-TA)*100+.5)/100
 1110 LET D=SA+C
 1120 IF F THEN GOTO 1160
 1130 PRINT 
 1140 PRINT "ZX STOCK EXCHANGE AVER.:";EA
 1150 GOTO 1190
 1160 PRINT 
 1170 PRINT "ZX STOCK EXCHANGE AVER.:";EA
 1180 PRINT "NET CHANGE:";NC
 1190 PRINT 
 1200 PRINT N$;":"
 1210 LET SA=INT (100*SA+.5)/100
 1220 LET G=SA
 1230 GOSUB 130
 1240 PRINT "STOCK ASSETS=$";TAB (24-L);R$
 1250 LET C=INT (100*C+.5)/100
 1260 LET G=C
 1270 GOSUB 130
 1280 PRINT "CASH ASSETS= $";TAB (24-L);R$
 1290 LET D=INT (100*D+.5)/100
 1300 LET G=D
 1310 GOSUB 130
 1320 PRINT "TOTAL ASSETS=$";TAB (24-L);R$
 1330 PRINT 
 1340 IF NOT F THEN PAUSE 225
 1350 IF NOT F THEN POKE 16437,255
 1360 IF NOT F THEN GOTO 1400
 1370 PRINT "DO YOU WISH TO CONTINUE? (Y/N)"
 1380 INPUT C$
 1390 IF C$="N" THEN GOTO 2510
 1400 FOR I=10 TO 21
 1410 PRINT AT I,0;"                               "
 1420 NEXT I
 1430 PRINT AT 11,0;"WHAT IS YOUR TRANSACTION IN:"
 1440 FOR I=1 TO 5
 1450 PRINT AT 12,0;I$(I);"?"
 1460 INPUT T(I)
 1470 NEXT I
 1480 PRINT AT 20,0;"PLEASE WAIT..."
 1490 LET DP=0
 1500 LET DS=0
 1510 FOR I=1 TO 5
 1520 LET T(I)=INT (T(I)+.5)
 1530 IF T(I)<=0 THEN GOTO 1560
 1540 LET DP=DP+T(I)*S(I)
 1550 GOTO 1620
 1560 LET DS=DS-T(I)*S(I)
 1570 IF -T(I)<=P(I) THEN GOTO 1620
 1580 PRINT AT 20,0;"YOU HAVE OVERSOLD A STOCK; TRY AGAIN.    "
 1590 PAUSE 300
 1600 POKE 16437,255
 1610 GOTO 1400
 1620 NEXT I
 1630 LET TT=DP+DS
 1640 LET BF=INT (.01*TT*100+.5)/100
 1650 LET CT=C-DP-BF+DS
 1660 IF CT>=0 THEN GOTO 1720
 1670 PRINT AT 19,0;"YOU HAVE TRIED TO SPEND "
 1680 PRINT "$";-CT;" MORE THAN YOU HAVE."
 1690 PAUSE 300
 1700 POKE 16437,255
 1710 GOTO 1400
 1720 LET C=CT
 1730 FOR I=1 TO 5
 1740 LET P(I)=P(I)+T(I)
 1750 NEXT I
 1760 CLS 
 1770 GOSUB 2010
 1780 LET DY=DY+1
 1790 PRINT "*** END OF TRADING:  DAY ";DY;" ***"
 1800 PRINT 
 1810 PRINT "STK. $/SHR. HDS. $ VALUE  CHANGE"
 1820 PRINT "................................"
 1830 FOR I=1 TO 5
 1840 LET G=S(I)
 1850 GOSUB 130
 1860 PRINT AT 3+I,0;I$(I);AT 3+I,(11-L);R$;AT 3+I,13;P(I);
 1870 LET G=S(I)*P(I)
 1880 GOSUB 130
 1890 PRINT AT 3+I,(24-L);R$;AT 3+I,26;C(I)
 1900 NEXT I
 1910 LET F=1
 1920 PRINT 
 1930 LET R=VAL ((STR$ RND)(1 TO 4))
 1940 LET I=INT (RND*7)
 1945 IF I>5 THEN GOTO 1940
 1950 IF I=0 THEN GOTO 1940
 1960 IF R<.15 THEN PRINT I$(I);" DECLARES DIVIDENDS OF $";(R*4+.5);"/SHARE"
 1970 IF R<.15 THEN LET C=C+P(I)*(R*4+.5)
 1980 IF B>.93 THEN PRINT I$(I);" SPLITS STOCK"
 1990 IF R>.93 THEN LET P(I)=P(I)*2
 2000 GOTO 1020
 2010 FAST 
 2020 IF D1>0 THEN GOTO 2060
 2030 LET S=VAL A$
 2040 LET D1=VAL A$
 2050 LET P=1
 2060 IF D2>0 THEN GOTO 2100
 2070 LET S2=VAL A$
 2080 LET D2=VAL A$
 2090 LET P2=1
 2100 LET D1=D1-1
 2110 LET D2=D2-2
 2120 FOR I=1 TO 5
 2130 LET R=RND
 2140 IF R>.25 THEN GOTO 2170
 2150 LET R=.25
 2160 GOTO 2240
 2170 IF R>.5 THEN GOTO 2200
 2180 LET R=.5
 2190 GOTO 2240
 2200 IF R>.75 THEN GOTO 2230
 2210 LET R=.75
 2220 GOTO 2240
 2230 LET R=0
 2240 LET BC=0
 2250 IF P<1 THEN GOTO 2290
 2260 IF INT (S+.5)<>INT (I+.5) THEN GOTO 2290
 2270 LET BC=4
 2280 LET P=0
 2290 IF P2<1 THEN GOTO 2330
 2300 IF INT (S2+.5)<>INT (I+.5) THEN GOTO 2330
 2310 LET BC=-4
 2320 LET P2=0
 2330 LET C(I)=INT (A*S(I))+R+INT (3-6*RND+.5)+BC
 2340 LET C(I)=INT (100*C(I)+.5)/100
 2350 LET S(I)=S(I)+C(I)
 2360 IF S(I)>0 THEN GOTO 2400
 2370 LET C(I)=0
 2380 LET S(I)=0
 2390 GOTO 2410
 2400 LET S(I)=INT (100*S(I)+.5)/100
 2410 NEXT I
 2420 LET TR=TR-1
 2430 IF TR<1 THEN GOSUB 2460
 2440 SLOW 
 2450 RETURN 
 2460 LET TR=VAL A$
 2470 LET A=INT ((RND/10)*100+.5)/100
 2480 IF RND<=.5 THEN GOTO 2500
 2490 LET A=-A
 2500 RETURN 
 2510 CLS 
 2520 PRINT 
 2530 PRINT 
 2540 PRINT "AT THE END OF ";DY;" DAYS TRADING:"
 2550 IF D>=10000 THEN GOTO 2610
 2560 PRINT "YOU HAVE LOST $";
 2570 LET G=10000-D
 2580 GOSUB 130
 2590 PRINT R$
 2600 GOTO 2650
 2610 PRINT "YOU HAVE MADE $";
 2620 LET G=D-10000
 2630 GOSUB 130
 2640 PRINT R$
 2650 PRINT "ON THE ZX STOCK EXCHANGE."
 2660 PRINT 
 2670 PRINT "HOPE YOU HAD FUN, ";N$;"."
 2680 PRINT "COME BACK AGAIN."
 2690 PRINT AT 20,2;"PRESS S TO RETURN TO BASIC."
 2700 PRINT AT 0,0;"%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$"
 2710 PRINT AT 0,0;"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"
 2720 PRINT AT 21,0;"%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$%$"
 2730 IF INKEY$="S" THEN STOP 
 2740 PRINT AT 21,0;"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"
 2750 GOTO 2700
 2760 CLEAR 
 2770 STOP 
 2780 SAVE "1014%8"
 2800 RUN 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top