--- title: "Portfolio Analysis" id: 51756 type: "computer_media" slug: "portfolio-analysis" url: "http://localhost/computer_media/portfolio-analysis/" markdown_url: "http://localhost/computer_media/portfolio-analysis.md" published_at: "2023-08-13T23:14:30+00:00" modified_at: "2026-04-04T20:18:03+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2023/08/SCR-20260404-egtl.png" excerpt: "Enter beta and risk figures for up to 10 securities and this program computes the minimum non-market-risk portfolio and plots the efficient frontier." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "Timex Computer Corporation" slug: "timex-computer-corporation" taxonomy: "post_tag" url: "http://localhost/tag/timex-computer-corporation/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Finance" slug: "finance" taxonomy: "genre" url: "http://localhost/type/finance/" - name: "Stocks" slug: "stocks" taxonomy: "genre" url: "http://localhost/type/stocks/" media_type: "Cassette" download_url: "https://archive.org/download/timex-sinclair-software-archive/Portfolio Analysis (1982)(Timex)(US)(TS1000)(Cassette).zip" mediadate: "1982" producer_company: - id: 11401 title: "Timex Computer Corporation" type: "company" url: "http://localhost/company/timex-computer-corporation/" images: - url: "http://localhost/wp-content/uploads/2023/08/SCR-20260404-egtl.png" - url: "http://localhost/wp-content/uploads/2023/08/SCR-20260404-egre.png" related_products: - id: 13613 title: "Portfolio Analysis" type: "product" url: "http://localhost/product/portfolio-analysis/" media_type_tags: "Finance, Stocks" --- This program implements a securities portfolio analysis and optimization tool based on the Capital Asset Pricing Model (CAPM), allowing users to enter beta values and non-market risk figures for up to 10 securities. The core algorithm iterates through critical lambda values to find the minimum non-market risk portfolio for a desired beta level, using the efficient frontier computation technique. A graphical scatter plot of the efficient frontier is generated using the pixel PLOT command, with axes labeled and scaled dynamically to fit the data range. The program uses two 300-element arrays (W and Z) to store computed beta and risk coordinates for plotting, with separate subroutines handling menu display, data entry, portfolio computation, and chart rendering. *** ## Program Analysis ### Program Structure The program is organized as a menu-driven application with a master menu at line 110 dispatching to five functional areas via `INKEY$` polling. The main sections are: 1. **Initialization and splash screens** (lines 12–99, subroutines at 9160 and 9282) 2. **Master menu** (lines 100–277) 3. **Beta plot / efficient frontier** (lines 280–940, chart subroutines 3030–7050) 4. **Portfolio computation** (lines 1050–1430) 5. **Data entry** (lines 2440–2614) 6. **Help screen** (lines 8005–8160) 7. **Shared math subroutines** (lines 1460–1990, 8200–9150) ### Data Structures The program maintains parallel arrays for up to 10 securities: `B(10)` for beta values, `R(10)` for non-market risk, `C(10)` and `D(10)` for portfolio weight calculation intermediates, and `S(10)` as a binary in/out flag array for each security. Two large 300-element arrays, `W(300)` and `Z(300)`, store the computed efficient frontier points (beta and risk coordinates), with `I(300)` and `O(300)` holding the normalized versions for plotting. ### Portfolio Optimization Algorithm The optimization follows a critical-line algorithm for mean-variance portfolio selection. The subroutine at line 1470 seeds the process by finding the security with the highest beta and making it the initial single-asset portfolio. The subroutine at 1610 finds the next critical lambda value (stored in `L7`) by scanning securities not yet in the active set, computing a threshold based on the ratio of the aggregate sum `S4` to the beta difference from the current corner portfolio’s weighted beta `S3`. The subroutine at 1710 recomputes portfolio weights using: - `F1 = L9 / (2 * R(I)^2)` — the lambda-scaled contribution - `F2 = S4 / (2 * R(I)^2)` — the normalization term - `X9 = F1 * (B(I) - S3) + F2` — the weight for security I The subroutine at 1890 computes the weighted sums `S1`–`S4` used throughout, where `S3 = S1/S2` acts as the current weighted-average beta and `S4 = 1/S2` is its reciprocal variance. ### Efficient Frontier Plotting The plot section (lines 280–940 and 8200–8390) accumulates frontier points in `W` and `Z`, then at line 8200 normalizes them via subroutine 9000 into `I` and `O` arrays. Axes are drawn by iterating `PLOT` commands (lines 3040–3090) and labeled with `PRINT AT`. The scale factors `SX` and `SY` at lines 8310–8320 map the data range onto a 51×33 pixel display area offset from the axis origin at pixel (12, 10). Tick marks on the Y-axis use the block graphic character `▝` (`\ '`) for a clean visual indicator. ### Menu Input Handling The master menu uses a three-phase `INKEY$` pattern: line 222 busy-waits until any key is pressed, lines 230–262 test for valid digits 1–5 and branch accordingly, and lines 263–277 handle invalid input by displaying the erroneous key and prompting to continue. This means the `INKEY$` at line 264 (assigning to `A$`) may capture a different key than the one that triggered the fall-through, since the key may have been released — a minor timing artifact common in polling-based input loops. ### Data Entry Logic Data entry (lines 2440–2614) enforces a 10-security limit via `M=10`. A local counter `L4` is incremented each entry; when `L4=4`, a special branch at line 2603 re-checks for a 0,0 terminator and jumps to the menu on valid data at line 2606 instead of looping. This appears intended to force a screen clear every 4 entries to avoid scrolling off the screen, though the `CLS` at line 2520 only fires at the start of the entry block, not mid-loop — the logic at lines 2587–2606 is somewhat convoluted and the `L4` reset is missing, so `L4` never resets to 0 during a data entry session. ### Interpolation Between Corner Portfolios When a specific beta target `V7` is requested, subroutine 1990 interpolates linearly between the previous corner portfolio beta `V6` and the current `B9`, computing blending coefficients `R1` and `R2`. The final security weights are then `X9 = R1*D(I) + R2*C(I)`, a convex combination of the two adjacent corner portfolios’ weight vectors. ### Notable Techniques and Anomalies - The sentinel values `1E38` and `4E-39` are used as practical infinity and near-zero initializers for min/max scans throughout, a common idiom given the floating-point range available. - The `**` operator (lines 1330, 1340, 1800, 1810, 1920) is used for exponentiation alongside the more common `^` — both are accepted. - The comment at line 885 — `REM LET KK=KK+1` — is commented out, with the actual increment moved to line 910, making the frontier point only stored when it falls within the plotted axis range. Points outside the range are computed but discarded. - Line 6151 contains the no-op `IF Y0=0 THEN LET Y0=0`, which has no effect. - Arrays `I(300)` and `O(300)` shadow the loop variable `I` used elsewhere; while legal in this BASIC dialect, this can cause confusion when reading the code. - The `SLOW` and `FAST` commands are used strategically: `FAST` is engaged before computationally intensive plotting and optimization loops, and `SLOW` is restored before interactive prompts. - Lines 9400–9410 provide a `SAVE` followed by `RUN`, implementing a self-restarting save routine at the end of the program listing. ## Source Code ``` 12 DIM W(300) 14 DIM Z(300) 20 LET M=10 22 REM 24 GOSUB 9160 26 GOSUB 9282 45 DIM B(10) 50 DIM C(10) 55 DIM D(10) 60 DIM R(10) 61 DIM I(300) 62 DIM O(300) 65 DIM S(10) 70 REM S(10),N,P1,P2,P3 = INTEGER 71 LET K=0 72 LET N=0 73 LET KK=1 88 LET H1=.05 90 REM INITIALIZING 93 FOR E=1 TO 10 94 LET B(E)=0 95 LET C(E)=0 96 LET D(E)=0 97 LET R(E)=0 98 LET S(E)=0 99 NEXT E 100 PRINT 104 REM 105 REM PRINT MASTER MENUE 106 SLOW 110 CLS 115 PRINT "SECURITIES PORTFOLIO ANALYSIS AND DETERMINATION" 120 PRINT 125 PRINT 130 PRINT " SELECTION OPTION" 135 PRINT " ================" 140 PRINT 150 PRINT " 1==ENTER DATA" 160 PRINT " 2==PLOT BETA" 170 PRINT " 3==COMPUTE PORTFOLIO" 180 PRINT " 4==HELP" 185 PRINT " 5==END OF PROGRAM" 190 PRINT 195 PRINT 199 PRINT " ENTER SELECTION CODE" 200 PRINT " --------------------" 222 IF INKEY$="" THEN GOTO 222 230 IF INKEY$="1" THEN GOTO 2440 240 IF INKEY$="2" THEN GOTO 280 250 IF INKEY$="3" THEN GOTO 1060 260 IF INKEY$="4" THEN GOTO 8005 262 IF INKEY$="5" THEN GOTO 3000 263 PRINT 264 LET A$=INKEY$ 270 PRINT "SELECTION CODE MUST NOT BE ";A$ 271 PRINT " =" 272 PRINT 273 PRINT 274 PRINT "(PRESS KEY C TO CONTINUE)" 275 IF INKEY$="" THEN GOTO 275 277 GOTO 110 280 REM FIND LOW AND HIGH X AND Y 281 CLS 282 IF N=0 THEN GOTO 7500 290 LET X0=1E38 292 LET Y0=1E38 294 LET X8=4E-39 296 LET Y8=4E-39 310 LET I3=0 320 FOR I=1 TO N 330 IF X0>B(I) THEN LET X0=B(I) 340 IF Y0>R(I) THEN LET Y0=R(I) 350 IF X8=H2 AND B9<=H2 THEN GOTO 810 800 GOTO 730 810 LET V7=H2 820 GOSUB 1990 830 LET B3=0 832 LET R3=0 840 FOR I=1 TO N 850 LET X9=R1*D(I)+R2*C(I) 860 LET B3=B3+X9*B(I) 870 LET R3=R3+X9*X9*R(I)*R(I) 880 NEXT I 882 LET W(KK)=B3 884 LET Z(KK)=SQR (R3) 885 REM LET KK=KK+1 890 IF B3X8 THEN GOTO 920 900 IF SQR (R3)Y8 THEN GOTO 920 910 LET KK=KK+1 920 LET H2=H2-H1 930 GOTO 790 940 GOTO 8200 1050 REM COMPUTE PORFOLIO 1060 PRINT 1062 IF N=0 THEN GOTO 7500 1065 REM ENTER LEVEL OF BETA 1070 LET I3=0 1080 PRINT "DESIRED LEVEL OF BETA ?" 1090 INPUT V7 1091 PRINT V7 1092 CLS 1093 FAST 1095 PRINT "DESIRED LEVEL OF BETA = ";V7 1096 PRINT 1100 GOSUB 1470 1110 GOSUB 1890 1120 GOSUB 1610 1130 IF L7>-1E37 THEN GOTO 1170 1140 LET R1=1 1150 LET R2=0 1160 GOTO 1240 1170 REM VARIABLE IS I9,LAMDA IS L7 1180 LET S(I9)=1-S(I9) 1190 LET L9=L7 1200 GOSUB 1710 1210 IF B9>=V7 THEN GOTO 1110 1220 REM PRINT PORTFOLIO 1230 GOSUB 1990 1240 LET B3=0 1245 LET R3=0 1260 PRINT "MINIMUM NON MARKET RISK" 1270 PRINT " PORTFOLIO" 1280 PRINT "SECURITY PERCENT" 1290 PRINT "-------- -------" 1300 FOR I=1 TO N 1310 LET X9=R1*D(I)+R2*C(I) 1320 LET B3=B3+X9*B(I) 1330 LET R3=R3+X9**2*R(I)**2 1340 IF X9<.00001 THEN GOTO 1370 1350 PRINT " ";I;" ";INT (100*X9*100)/100 1370 NEXT I 1380 PRINT 1390 PRINT "BETA= ";B3 1410 PRINT "RELATIVE NON-MARKET RISK = ";INT (SQR (R3)*100)/100 1412 PRINT 1414 PRINT 1416 SLOW 1420 PRINT "(PRESS KEY C TO CONTINUE)" 1425 IF INKEY$="" THEN GOTO 1425 1430 GOTO 110 1460 REM FIND FIRST PORTFOLIO 1470 LET B9=1E-39 1480 FOR I=1 TO N 1490 IF B(I)<=B9 THEN GOTO 1520 1500 LET B9=B(I) 1510 LET I9=I 1520 NEXT I 1530 FOR I=1 TO N 1540 LET S(I)=0 1545 LET D(I)=0 1550 NEXT I 1560 LET S(I9)=1 1565 LET D(I9)=1 1570 LET L9=1E38 1575 LET V6=B(I9) 1580 LET H2=1+H1*INT ((V6-1)/H1) 1590 RETURN 1600 REM FIND NEXT CRITICAL VALUE OF LAMDA 1610 LET L7=-1E38 1620 LET I8=I9 1630 FOR I=1 TO N 1640 IF I=I8 OR B(I)=S3 THEN GOTO 1680 1650 LET L8=-(S4/(B(I)-S3)) 1660 IF L8>=L9 OR L8=M THEN GOTO 2495 2565 PRINT 2570 PRINT " ";N+1;" - BETA AND RISK ?" 2580 INPUT B(N+1) 2582 PRINT " BETA = ";B(N+1) 2584 INPUT R(N+1) 2586 PRINT " RISK = ";R(N+1) 2587 LET L4=L4+1 2588 IF L4=4 THEN GOTO 2603 2590 IF B(N+1)<>0 AND R(N+1)<>0 THEN GOTO 2612 2592 LET L=0 2600 CLS 2602 GOTO 110 2603 IF B(N+1)=0 OR R(N+1)=0 THEN GOTO 110 2604 LET N=N+1 2606 GOTO 2520 2612 LET N=N+1 2614 GOTO 2560 3000 CLS 3010 PRINT AT 11,2;"**** END OF PROGRAM ****" 3020 STOP 3030 REM DRAW X-AXIS 3032 CLS 3040 FOR I=12 TO 63 3050 PLOT I,10 3060 NEXT I 3061 REM LABEL X-AXIS 3062 PRINT AT 19,15;"BETA" 3065 REM DRAW Y-AXIS 3070 FOR I=10 TO 43 3080 PLOT 12,I 3090 NEXT I 4040 REM LABEL Y-AXIS 4042 PRINT AT 8,0;"R" 4043 PRINT AT 9,0;"I" 4044 PRINT AT 10,0;"S" 4045 PRINT AT 11,0;"K" 6140 REM 6150 LET L=16 6151 IF Y0=0 THEN LET Y0=0 6153 PRINT AT L,1;Y0 6155 LET VY=(Y9-Y1)/4 6157 LET V=VY 6160 FOR I=1 TO 4 6165 LET L=L-4 6175 LET V=(VY*I)+Y1 6177 IF I=4 THEN GOTO 6200 6180 PRINT AT L,1;INT (V*100)/100 6190 PRINT AT L,5;" '" 6200 NEXT I 6990 REM 7000 LET C=6 7002 LET VX=(X10-X1)/5 7003 PRINT AT 18,C;X1 7004 LET V=VX 7005 FOR I=1 TO 5 7010 LET C=C+5 7015 LET V=(VX*I)+X1 7017 IF I=5 THEN GOTO 7040 7020 PRINT AT 18,C;INT (V*100)/100;AT 17,C;" '" 7040 NEXT I 7050 RETURN 7500 REM N0 DATA 7505 CLS 7510 REM CONTROL GOES BACK TO MASTER MENUE 7515 PRINT 7520 PRINT AT 10,6;"*** NO DATA ***" 7521 PRINT 7522 PRINT " YOU MUST ENTER DATA FIRST" 7530 PRINT 7532 PRINT 7535 PRINT "( PRESS KEY C TO CONTINUE )" 7536 IF INKEY$="" THEN GOTO 7536 7540 GOTO 110 8000 STOP 8005 CLS 8010 PRINT " HELP" 8020 PRINT " ====" 8030 PRINT 8040 PRINT "BETA = MARKET SENSITIVITY" 8050 PRINT "RISK = RISK FOR SECURITY" 8060 PRINT 8070 PRINT 8080 PRINT "TO ENTER A NEW SET OF DATA YOU MUST EXIT AND THEN RUN THE " 8082 PRINT "PROGRAM AGAIN ." 8085 PRINT 8090 PRINT "TO ADD DATA TO YOUR LIST YOU MUST SELECT CODE (1) IN THE MENU" 8100 PRINT 8102 PRINT 8104 PRINT 8110 PRINT "( PRESS KEY C TO CONTINUE )" 8150 IF INKEY$="" THEN GOTO 8150 8160 GOTO 110 8200 REM FIND HIGH,LOW OF W,Z 8210 REM X1=LOW,X10=HIGH 8220 REM Y1=LOW,Y9=HIGH 8230 LET X1=1E38 8234 LET Y1=1E38 8236 LET X10=4E-39 8240 LET Y9=4E-39 8250 FOR I=1 TO KK-1 8260 IF X1>W(I) THEN LET X1=W(I) 8270 IF Y1>Z(I) THEN LET Y1=Z(I) 8280 IF X10I(I) THEN LET X2=I(I) 9110 IF Y2>O(I) THEN LET Y2=O(I) 9120 IF X11