FlexSoft 7172 Regional Street, #276 Dublin, CA 94568 Voice/FAX 510-829-9733 BBS 510-829-2293 This document and all accompanying written and disk based notes and specifications are copyrighted by FlexSoft. October 17, 1993 Page ii Table of Contents Table of Contents Table of Contents i Preface 1 Introduction 2 TAS Features 2 System Requirements 4 Hardware 4 Software 4 Data 4 Support and Upgrades 6 Support 6 Updates to TAS (Upgrades) 6 Redistribution of TAS 7 Registration Code Secrecy 7 Other FlexSoft Products 7 PDL (Prodigy Down Loader) 8 PTT (Personal Ticker Tape) 8 Credits 9 Disclaimers 9 Technical Analysis References 9 Installing TAS 11 Quick Start Installation 11 Creating and Running a Sample Selection 13 Setup TAS 14 Data Directories 14 ASCII Format Historical Data Files 16 Program Options 17 Include Ticker Period 17 Fullname In Selections 18 Symbol Table Size 18 Quotes Per Symbol 18 Use EMS Arrays 19 Editor Command 19 Chart Command 19 List Command 20 File Directories 20 Script Directory 20 Selection Directory 20 Profit Test Directory 20 Ticker List Directory 21 Output Files 21 ASCII I/O Directory 21 Historical Data Directory 21 Chart Program Directory 21 Printer Setup 21 Printer Type 21 Printer Port 22 Resolution 22 Orientation 22 Page Size 22 Page i Reverse 22 Register Program 22 Save Configuration 23 Running TAS 24 Starting TAS from DOS 24 TAS Main Menu 25 Activities 25 Activity File Submenu 26 Run 26 Edit 27 New 27 List 27 Delete 28 Rename 28 Copy 28 Prompt for a File Name 28 Quit 29 Error Processing 29 Special Keys within TAS 31 Activity Editors 32 Scripts - Editing TAS Scripts 32 Editor Function Keys 33 Editor Control Keys 33 Selections - Scan and Report 34 Formulas for the Selection 35 Conditions for the Selection 35 Titles for the Selection Output Report 35 Selection Run Options 35 Index Ticker 35 Maximum Quotes 36 Minimum Quotes 36 Start Date 36 End Date 36 Running Your Selection 36 Sorting on Selected Columns 37 Printing Your Selection Report 37 Creating a Ticker List 37 Errors In Selection Formulas 37 Profit Tests - Test a system 38 Profit Test Formulas 38 Profit Test Conditions 38 Profit Test Options 39 Profit Test Option Settings 39 Initial Cash 39 Test Type 40 Commissions 40 Share Purchases 40 Price Slippage 41 Output File Name 42 Report Detail 42 Maximum Quotes 42 Index Ticker 42 Page ii Table of Contents Reinvest Profits 42 Start Date 42 End Date 42 Running the Profit Test 43 Errors In Profit Test Formulas 43 Ticker Lists - Group Securities 44 Utilities 46 DOS Shell 46 Run Chart Program 46 View A File 47 TAS Script Processing 48 TAS Script Language 49 Syntax 49 Building Blocks 50 Variables 50 Assignment Statement 50 Arithmetic Operators 50 Functions 50 IF statement 50 WHILE statement 50 FOR statement 51 BEGIN-END Blocks 51 Logical AND 51 Logical OR 51 Relational Operators 52 Special Relational Operator for Arrays 52 Comments 52 Variables 52 Creation of Variables 53 TAS Variable Types 53 "String" Variables 53 "Numeric" Variables 53 "Numeric Array" Variables 54 Assignment Statement 57 Arithmetic Operators 58 Functions 58 IF Statement 58 WHILE Statement 59 FOR Statement 59 FOR EACH POINT Statement 60 BREAK Statement 60 BEGIN..END Statement 60 GOTO Statement and LABELS 61 GOSUB statement 62 RETURN statement 63 STOP Statement 64 PROLOG statement 64 EPILOG statement 64 Logical Operators 64 Relational Operators 65 Crossed Above/Below Operator 65 Comments 65 Page iii Pre-Defined Variables 67 Pre-Defined DATA Arrays 68 Pre-defined Functions 71 Technical Indicators available in Metastock 71 ad Accumulation/Distribution 71 adx Average Directional Movement 72 adxrAverage Directional Movement Rating72 add Add two arrays 72 cci Commodity Channel Index Array 72 co Chaikin's Oscillator 73 cos Trigonometric cosine 73 cum Cumulative Sum of Array "a" 73 div Divide two arrays 74 dmi Directional Movement Index 74 exp Exponential Function 74 hhv Highest High Value 74 llv Lowest Low Value 75 log Natural Logarithm 75 macdMACD indicator 75 mdi Minus Directional Movement (-DI) 75 mfi Money Flow Index 75 mo Momentum Array 76 mov Moving Average 76 mul Multiply two arrays 78 neg Negative of Array "a" 78 nvi Negative Volume Indicator 78 obv On Balance Volume 78 oscpPrice Oscillator 79 oscvVolume Oscillator 79 pdi Positive Directional Movement (+DI)79 per Performance Indicator 80 pvi Positive Volume Indicator 80 ref Reference function 80 rsi Wilder's Relative Strength 81 roc Rate Of Change Array 81 sar Wilder's Parabolic 81 sin Trigonometric sine 82 sqrtSquare root 82 std Statistical Standard Deviation. 82 stoch Stochastic Oscillator 82 sub Subtract one array from another 82 sum Sum array over period 82 tan Trigonometric tangent 83 trixTRIX Function 83 tsf Time Series Forecast 83 var Statistical Variance 83 vhf Vertical/Horizontal Filter 84 vol Volatility Indicator. 84 wc Weighted Close 84 willa William's A/D 84 willr William's %R 85 zig Zig Zag Function 85 Page iv Table of Contents TAS Functions 86 addto Add number to array 86 angle Angle of a line 86 alpha Alpha function 86 avgprc Average Price 86 bbandt Top Bollinger Band 87 bbandb Bottom Bollinger Band 87 beta"Beta" function 87 compress Date Compression 87 const Constant Array 88 corrcoef Correlation Coefficient 88 datestr Create a formatted date 88 daymon Day of Month function 88 daywk Day of Week function 88 defined Check if variable exists 88 divby Divide array by number 89 DOS Execute a DOS command 89 Dump_Array Dump Array Contents 89 ema Exponential Moving Average 90 expand Expand formatted string 90 findfst Find first value 90 findlst Find last value 90 findstr Find substring 90 future Future array element 91 ifdnOne if Down 91 ifupOne if Up 91 int Create Integer 91 isect Find array intersection 92 linreg Linear Regression 92 linreg2 2 Way Linear Regression 92 loadLoad a data array 93 macdx MACD Extended 93 max Maximum value of a pair 93 maxPair Maximum value of two arrays 93 maxVal Maximum value in array 93 maxQuotes Set Maximum Data Points 94 memleft Show remaining memory 94 min Minimum value of a pair 94 minPair Minimum value of two arrays 94 minVal Minimum value in array 94 month Month function 95 mulby Multiply by number 95 now Current date 95 outputFile Specify listing file 95 overOver function 95 pause Wait for keyboard input 95 peakFind Peak in Array 95 per1Performance using Array 98 redoRerun profit test 98 redo_count Profit Test Reruns 98 set Set Array to Value 98 signSign of array entries 98 Page v slope Slope of Line 99 sma Simple Moving Average 99 strlen String Length 99 strrep String Replace 99 subfrom Subtract number from array 100 substr Substring function 100 tma Triangular Moving Average 100 trendline Create a Trendline 100 trendpar Parallel Trendline 100 trough Find Trough in Array 100 tr Wilder's True Range 101 trimTrim blanks from a string 101 yearYear function 101 zeroZero Array 101 Input/Output Functions 102 WRITE and WRITELN Functions 102 CWRITE and CWRITELN Functions 103 FORMAT Function 103 Format Specifiers 103 SORT Functions 104 SORTOUT 104 SORTON 105 SORTGET 105 SORTPRINT 106 Column Headings 107 ASCII File Functions 107 AOpen Open ASCII file 107 AClose Close ASCII file 108 APutPut Line to ASCII file 108 AGetGet Line from ASCII file 108 ASeek Locate Line in ASCII file 109 User Input Function 109 Ask Get User Input 109 VMenu Vertical Menu 110 Profit Test Statements 111 PLOT statement: Define Technical Indicators 111 BUY WHEN - Define BUY Conditions 112 SELL WHEN - Define SELL Conditions 112 STOP (LONG or SHORT) Condition 113 TAS Profit Tester Functions 114 Profit Test Phases - Advanced Use Only114 GRAPH Functions 116 OPENGRAPH 116 SIZEGRAPH 116 GRAPH 117 DRAWLINE 117 CLOSEGRAPH 119 PRINTGRAPH 119 Graphics Text Control Functions 119 Graph Color Values 120 Graph Text Alignment Values 120 Annotate 120 Page vi Table of Contents HLine 120 VLine 120 LineColors 120 BGColor 121 TextColor 121 TextAt 121 TextDir 121 TextFont 121 TextAlign 121 TextSize 121 GRAPH EXAMPLES 122 TAS "POUND" (#) Commands 126 OUTPUT_FILE Command 126 Appending to Output File 126 Suppressing TAS Report Heading 127 MAX_QUOTES Command 127 SCAN_DATE Command 127 PROFIT_TEST Command 128 INDEX Command 129 INCLUDE Command 129 TITLE Command 130 COMPRESSCommand 130 TAS Script Examples 131 Putting Them Together 131 New High/New Low Example 132 Script Contents 133 Script Output 133 TICKER Symbol Processing 134 Script Contents 134 Directional Movement Example 135 Script Contents 135 Script Output 136 Modified "Binary Wave" 136 Profit Test Example Using RSI(14) 136 Script Contents (RSIPT.TAS) 136 Script Output 137 TAS Error Message 140 Error Messages 140 Diagnostic Actions 155 Supported Graph Output Devices 157 Graphics Device Names 157 Drawing Colors and Output Support 160 Index 161 Page vii Preface Preface TAS grew out of a personal requirement. Thanks to the recent explosive growth in the availability of relatively inexpensive daily quote services, I was able to gather daily price and volume data on potentially thousands of stocks and indices each day. Unfortunately, I did not have time to examine this data regularly before it had already changed. I needed some way to scan my data to find the opportunities I might be missing otherwise. As a user of technical analysis, I had to be able to use classic technical indicator functions that would provide more than just price or volume information. I also needed a system that would allow me to test my strategies with historical data on many securities. Finally, I needed a system flexible enough to allow me to test and scan for any system that might be conceived. As both a professional programmer and a technical analyst, I felt that the best way to fill these needs was to write my own program. While I was researching the project and discussing it with others, many of my friends and acquaintances as well as professional contacts asked me to make the program available to them. Since then the interest has continued to spread widely. I wish to thank all TAS users for your support and especially your suggestions and ideas on how to make TAS a better product. Martin Moore Dublin, CA 1993 Page 1 Introduction Technical Analysis Scanner (TAS) is a computer program that lets you scan and analyze your stock, commodity, mutual fund or market index (collectively termed "securities" in this manual) data base using the power of your computer. You may base your own analysis on popular strategies, or you may modify them or develop your own strategies. Thus you have at your fingertips a powerful tool which can be of help when you make deci- sions about your securities portfolio. TAS Features TAS includes numerous special features that make scanning and analysis of your securities database easier than ever: " Complete Control - TAS is a generalized technical analysis "tool box". It is not a "black box" system where you have no knowledge of the rules or control over its decision making process. With TAS, you have complete control over the indicators chosen, their interpretation, and the output formatting of your reports. " High-Level Analysis - With TAS, you can combine over 60 built-in technical indicators, compare their values against other indicators or values, make decisions based on the result of those comparisons, and ultimately, create a report which shows you what you want to see. The TAS "scripting language" can use English words to express the relationships between indicators or price/volume values. " Massive Power - TAS is designed to enable you to go beyond the simpler analytical power available with other charting or scanning programs. TAS lets you apply your simple or complex trading system to all, or any part of, the data in your historical price/volume Data Base. If you have a trading strat- egy that relies on technical indicators or price action, but you do not have the time to chart all of your stocks everyday, then TAS is the tool you need. " Custom Reports - TAS can also be used to create custom reports on your stocks. For example, you can use it to notify you when a particular stock has reached a certain price, volume or technical Page 2 Introduction indicator value. " Profit Testing - With the Profit Tester feature, you can confirm the profitability of your trading system. TAS goes back through your historical data, a day at a time, applying your trading rules to the indicators and conditions you specify. It keeps track of the days you bought, sold or were stopped out of positions, tabulating the results on a daily basis, or in a summary report which tells you how your system performed. The rest of this book tells you how to take advantage of the TAS features listed above. Page 3 System Requirements In order to use TAS, you should have the following software and hardware configuration. Hardware Any IBM PC processor type (8088, 8086, 80x86) A CGA, EGA, or VGA Monitor (EGA or VGA required for Charts) Hard Disk (optional) Microsoft or Logitech Mouse (optional) 512K minimum memory (640K better) Expanded Memory (XMS) will be used on 286/386/486 class machines if there is an Expanded Memory System (EMS) driver or actual LIM 4.0 EMS memory installed. Software DOS 2.1 or later Data Historical Price/Volume Data in any of the following formats: . "Computrac" Format historical data files used by Metastock, Investograph Plus, and Computrac, among others . ChartPro or MegaTech data files Page 4 System Requirements . Commodity Systems Incorporated (CSI) format . AIQ data format . Technical Tools data format . Generalized ASCII format (*.PRN) files Page 5 Support and Upgrades Support You can get support for TAS problems or questions by contacting FlexSoft at its mailing address below: FlexSoft 7172 Regional St, #276 Dublin, CA 94568 or by telephone or fax at 510-829-9733 or by Email on the following services: OnLine Service Userid GEnie M.MOORE41 Prodigy JBMD65A FlexSoft BBS (510-829-2293) SYSOP Compuserve 76447,2367 Updates to TAS (Upgrades) New releases of TAS may be defined as "upgrade releases". An Upgrade Release will require a new Registration Code and an Upgrade Registration Fee. When a major feature is added to TAS, there will be a "Feature Upgrade" cost as well. Page 6 Support and Upgrades Update versions of TAS are available , on the FlexSoft BBS at 510-829-2293. The FlexSoft BBS has an online order system which you can use to purchase your new TAS update. You will need a VISA , Mastercard, or American Express credit card number to order your update to TAS when using the online order system. Once your order is confirmed, you will be notified of your new Registration Code. You can also obtain updates to TAS by U.S. Mail. If you need an update by U.S. Mail, please send $10 for shipping and handling in addition to the Update and/or Upgrade Registration Fee. Methods of payment are by check, money order, or VISA, Mastercard, or American Express credit card number (include expiration date). Redistribution of TAS You may re-distribute TAS to BBS systems or other public locations as long as you distribute the entire package (either .ZIP or self- extracting .EXE file format). Registration Code Secrecy You may not divulge or redistribute your registration code , nor may you transfer it to anyone else. If you divulge or publish your registration code to an unregistered party, or parties, that registration code will be invalidated and your code will not work for future upgrades to TAS or any other FlexSoft product until a new code is obtained at the full price for the product whose code was compromised. Other FlexSoft Products FlexSoft also has two companion products for users who wish to order them. The first product is called PTT (Personal Ticker Tape), and the second is called PDL. With the combination of TAS, PTT and PDL, you have "end to end" access to your stock market data. PDL Page 7 downloads the quotes, PTT updates the database, and TAS allows you to search, analyze, report, and chart the data. PTT and PDL are described below. Each of these programs can be ordered from FlexSoft or downloaded from GEnie or Compuserve. PDL (Prodigy Down Loader) PDL is a program that downloads, or captures, daily quote data and market indices from the Prodigy Information Service. PDL can download up to 4,000 daily quotes in a single run. If you need to download more quotes, then you can run PDL several times. It uses the Quote Track and/or Market Close features of Prodigy to obtain the quotes, so there is no need to go into Prodigy and enter the quotes by hand, as some systems require you do. The creation of the ticker list of quotes to download can be done with a simple TAS script. PDL also has a "vacation mode" that will enable you to go on vacation or leave town for extended periods and still gather daily quote data. PTT (Personal Ticker Tape) PTT converts quotes from GEnie, DowJones, Prodigy and Compuserve into MetaStock data files and an ASCII format for input to spreadsheets. PTT produces summary reports on all your Metastock files whether you update the files with PTT or not. Colors are used to highlight those stocks which exceed either PRICE or VOLUME limits you set in the installation procedure. PTT also creates a Summary Report file. PTT can also be used to download closing quotes directly from either Compuserve, GEnie, or Dow Jones News data services. Page 8 Support and Upgrades Credits MetaStock Professional is a stock charting program from Equis Inc. ChartPro and MegaTech are stock charting programs written by David Rettger. GEnie is a trademark of General Electric Co. Prodigy is a trademark of Prodigy Services Co. Disclaimers In no event will FlexSoft (or any of its employees or owners) be liable to you for any damages, including any lost profits, lost savings, or other incidental or consequential damages arising out of the use of, or inability to use the program. This product is distributed "as is" with no warranty expressed or implied. FlexSoft reserves the right to make modifications at any time. Prices are subject to change without notice. Technical Analysis References The Encyclopedia of Technical Market Indicators, Colby & Meyers, Dow Jones Irwin Press, 1988, ISBN 1-55623 -4 -049 New Concepts in Technical Trading Systems, J. Welles Wilder Page Jr., 9 Trend Research, 1978, ISBN 0-89459 -8 -027 The New Commodity Trading Systems and Methods, Perry J. Kaufman, John Wiley and Sons 1987, ISBN 0-471-87879-0 Metastock Professional Users Guide, Equis International Page 10 Installing TAS Installing TAS TAS is distributed as an "LHA" compressed collection of files. The name of the file will be based on the version and release level of TAS. For version 5, release 00, the name will be 'TAS500.EXE', and in general, the name will be 'TASvrr.EXE' where 'v' is the Version and 'r' is the Release. Quick Start Installation The following "quick start" documentation shows how to get TAS up and running on your system initially. The file name for the TAS file is referred to as "TASvrr.EXE". If you received TAS on a floppy disk, follow the installation instructions that came with the disk. You should place the diskette in the appropriate floppy drive, "log" to that drive (e.g., type A:), then type INSTALL. Otherwise, if you have received TAS by downloading it from a Bulletin Board System (BBS) or some other means, you should perform the following steps: 1. Create a directory to contain TAS software. It can be any name you choose. The following instructions assume the subdirectory name is "\TAS". To create a directory named \TAS on your C: drive, type "MD C:\TAS" 2. You should copy TASvrr.EXE into directory \TAS by typing COPY TASvrr.EXE C:\TAS 3. CD \TAS 4. Type TASvrr, e.g, if the file is TAS500.EXE, type 'TAS500'. This will start a file extraction procedure that sets up the files necessary for running TAS. You should reply "Y" to the prompt tha tinitially appears. Once the files are installed in the TAS subdirectory. 1. Type TAS and press ENTER. 2. You will be presented with an initial screen which tells you that you have not run TAS before. Hit the ESC key after reading the message. You will see another message indicating you have a trial version of TAS. Once again, hit the ESC key to move to the next screen. Page 11 3. You will now be placed in the Main Menu screen of TAS. Choose Setup to go to the program setup menu. 4. Now choose File Directories to set your default historical data directory DOS path. For example, if your data is in Metastock format, you can set the Historical Data Path setting to the "top" part of your DOS path. For example, suppose all your data directories are under the major directory E:\MS\DATA in directories A_E, F_P, and Q_Z, by entering the directory E:\MS\DATA, you will not have to repeat that part of the path when you fill in the list of data directories in the next step. Similarly, if you have Technical Tools data, the path to those directories can also be specified here. Specify your top path and hit Enter, then hit F10 to save the results. 5. Now choose Data Directories from the Setup menu. You will see a list of 5 groups of 10 directories you can specify. Choose Data Directories 1-10 first. Enter each data directory name (without the top part entered in the previous step). Move over to the Historical Data Format box and type the first letter of the type (e.g, M for Metastock). Then hit Enter and move to the next row. When done, hit the F3 key to save this list. 6. Repeat the previous step for each 10 data directories. 7. Finally, if you have registered TAS, it is now time to enter your registration code and name. Choose the Register Program menu option from the Setup menu. Enter your name using upper and lower case as a proper name should be entered, and then enter your registration code as given to you on your FlexSoft invoice or by other means. This code need not be all upper case. After you enter the registration code, hit the ENTER key and then hit the F10 key to save your settings. Now leave the program to make the registration procedure take effect. The next time you enter TAS, it should indicate you are registered at the bottom of the screen. TAS is now installed . The following section shows how to do a build and run a simple selection that will perform the same function as the Metastock Utility Rank feature. Page 12 Installing TAS Creating and Running a Sample Selection 1. Go to the Activities Menu item. Select Ticker List by moving the cursor bar down to that selection and pressing ENTER. If you have a mouse, you can click on the menu item itself. 2. Select New from the Files prompt. 3. You will see a prompt box asking for the name of the new file. Enter the name "MYTICKS" . This will be the name of a ticker list for testing. 4. After a moment, TAS will present you with a list of all the tickers it found in the Data Directories you defined in the Data Directories screen. Move the cursor to each ticker symbol you want to run a script against. Hit the SPACE bar on the symbol. It should highlight (indicating it is selected). Hit F3 when all desired symbols are selected. This will save the ticker list you just created. 5. At the Main Menu, select Activities, then Selections. 6. Select Edit from the Files Menu 7. Type MSURANK and hit ENTER. 8. Hit the F4 function key to RUN the MSURANK selection. TAS will now display a screen containing all the ticker lists available to use. You will be asked which ticker list you wish to use when you run this script. 9. Pick the ticker list you just created "MYTICKS.TCK" by moving the cursor or mouse to the file name and pressing ENTER or clicking on the filename. This particular selection will create a report like the one Metastock Utility (MSU) creates when you select "Rank" using a 26 day Rate of Change and a 10 day Moving Average. 10. Now TAS runs the script with the ticker symbols you put in the ticker list. As each ticker is processed, you will see a line in the "run" window. Once all tickers are processed, the report will be presented on the screen, sorted by ticker. 11. Hit F1 now to see the choices you have. By hitting F1, you can read the help and see what you can do from here. You can sort your tickers on the value of any column shown, either ascending or descending order. To sort on the values in the second column, press the key sequence Alt-2 (hold the ALT key and hit the number 2 at the same time). 12. To exit from the report screen, hit the ESC key. The documentation for the system is in the online help file available by hitting the F1 key at any time. Page 13 Setup TAS The Setup Menu is used to tell TAS the location of your Data Directory(ies), your specific program options, and where TAS is to look for each activity file type. Up to fifty directories can be de- fined on the Configuration Menu. Data Directories The Data Directory menu choice presents a panel that appears as shown below: Page 14 Setup TAS You should fill in the names of your Historical Data Directories, one per line. Next to each directory name, choose the directory format type from the pick list that appears when you tab or move over to the field to the right of the name. If all your historical data directories are subdirectories of a common higher leveled directory, you can use the Setup/File Directories/Historical Data (page 21) setup option to save yourself some work. Go to that menu item first, fill in the full path name to the higher level directory, and then save that setting. Then, when you enter the directory names in this panel, you need not specify the path up to the point of your subdirectory. For example, if you have the directories D:\MS\DATA1 D:\MS\DATA2 D:\MS\DATA3 you would place "D:\MS" in your Setup/File Directories/Historical Data setting. Then, in this panel, you would only need to enter DATA1 DATA2 DATA3 If you do not use the procedure above, be sure to include the full path name, including the first backslash character and the drive identification if necessary for each directory you enter in this panel. If you have more than one directory of data files, you can enter the other directory names on the second thru fifteenth lines. Next to the data directory name, choose the historical data format for the data. Press the first letter of the data format choice and then hit the Enter key to select it. The Data Format choices are: Page 15 Format Description File Choice Types MSP Metastock/Computrac *.DAT format files PRO ChartPro/MegaTech *.PRO files CSI Commodity Systems Inc *.DTA files TT Technical Tools Data *.TTD AIQ AIQ Stock *.DTA Expert/Trading Expert files ASC ASCII format *.PRN *.PRN files ASCII Format Historical Data Files ASC format data directories must contain readable ASCII text files with historical data for each ticker symbol in each file. The file names must be .PRN where symbol symbol is the ticker symbol. All files in the directory must have the same field order within the ASCII data files. The order of data fields on each line of the ASCII *.PRN files must be specified in a file located in the data directory. This file is named ASCII.FMT. It should contain a single line with a Format Description String describing the ASCII field format. The Format Description String defines the format of a comma separated quote by using single letters to describe each field in the quote. The code letters for each field are: Format Code Data Field S Ticker Symbol D Date H High L Low Page 16 Setup TAS C Close V Volume O Open I Open Interest X Skip this field For example, if your quote file contains quotes with the following format: date,symbol,high,low,close,open,open int,other,volume where "other" is some other data value, then your format specification string would be: DSHLCOIXV Program Options The Program Options menu item opens a new menu which can be used to modify settings used within TAS. . Include Ticker Period Page 17 If you only have one type of data file (Daily or Weekly or Monthly), you should leave this value set at "No". Otherwise, this parameter should be set to "Yes" if you have multiple tickers with the same ticker symbol but different "periods". For example, if you have a DAILY and a WEEKLY file for the symbol AAPL, you will need to set this value to "Yes" in order to distinguish between the daily and weekly ticker files. If you have TICKER LISTS created with this value set to "Yes", they will not work if you change this value to "No" (and vice versa). You will have to re-select the tickers again. TAS is distributed with this value unset (which means "No"). Note also, that if you have this value set to "Yes", you must include the ticker file period in every reference to a ticker name, including references on the #INDEX command. Fullname In Selections This setting will control whether the ticker symbol or the "full" symbol name is displayed in the Selection screen output. Some European customers, in particular, do not have meaningful ticker symbol abbreviations, and must use the full name for reporting purposes. If you set this field to "Yes", then you also lose a calculated formula column when you create a Selection. Symbol Table Size The Symbol Table Size parameter is a "tuning" value which determines the size of the internal tables for TAS. You may need to increase the value if you write a particularly long or complex selection script. It is recommended that you set this value at from 32000 to 64000. The default value is 32000. If you want to see the amount of SYMBOL TABLE your TAS scripts are using, you can type the ALT-M key to display the memory usage of TAS. One of the values shown is the maximum Symbol Table Size used so far. Quotes Per Symbol The QUOTES PER SYMBOL parameter specifies how many quotes you want TAS to read into memory when performing the selection. The higher this number, the longer the selection will take. Page 18 Setup TAS See the section below under Use EMS Arrays for the effect of this setting on the usage of EMS memory and processing time. This parameter has a very significant impact on the processing time that TAS uses for each symbol. It should be set to as low a value as possible (based on the time periods you use in your indicators) so that the TAS processing is minimized. Use EMS Arrays If you have EMS (Expanded Memory) or XMS (eXtended Memory) installed with suitable driver software1, you can set this value to Yes to take advantage of the extra memory you have above the 640K DOS limit. TAS will automatically determine if you have EMS memory installed, and if so, it will always use that memory for a "swapping area", reducing the amount of disk reads required to run the program. In addition, if you set this parameter to Yes, and you have re- quested more arrays or set Quotes per Symbol high enough so that product of all the array sizes times the number of arrays needed is greater than the amount of memory available in the DOS 640K region, TAS will swap arrays into and out of EMS memory. This swapping of arrays can slow TAS processing somewhat, but it allows you to set Quotes per Symbol to a maximum value. Editor Command If you have your own preferred ASCII editor that you would rather use than the TAS editor, you can use it instead for editing script files. To inform TAS that you have your own editor, specify the editor's file name in this item. For example, if your editor is MYEDIT.EXE, you would specify that full name in the Editor Command entry. Now, it is important that the editor program directory be in the DOS PATH variable so that it can be found by TAS. Chart Command If you want to use your own Charting program, such as Metastock, from within TAS, you can define the program name in this entry. For MetaStock, you would say "MS.EXE". 1Most systems today do not actually have EMS memory., but instead have Extended Memory (XMS), the kind that is built-in to new 386 and 486 systems. The term EMS actually refers to a software/hardware standard that is emulated by driver programs from various vendors, such as QuarterDeck Office Systems (QEMM QEMM QEMM and DesqView/386) DesqView/386) DesqView/386) as well as Microsoft's EMM386 EMM386 EMM386 program. Page 19 Because some charting programs require that they be invoked from their own directory, you might need to set the Chart Program Directory in the File Directories menu (see page 21) List Command The "List command" setting is used to specify your own file browser to be used when you want to view the output of a running script via the alt-V (View) command. TAS is distributed with the command file SHOW.EXE, which is satisfactory for most users. If you have an alternate viewer command, enter the command in this field. The command must be accessible via the DOS PATH setting. File Directories The File Directories menu enables you to set default directory locations for the various types of files that TAS will access. This is not required, but you might find it neater to separate your scripts from you selections from profit tests, etc. In addition, by using the Historical Data Directory, you can define a top level directory for your data files without re-entering the directory names into the Data Directory section of the Setup Menu. Script Directory This is the directory that will be accessed when you specify a script name without a directory qualifier. Selection Directory This is the directory that will be accessed when you specify a selection without a directory qualifier. Profit Test Directory This is the directory that will be accessed when you specify a profit test without a directory qualifier. Page 20 Setup TAS Ticker List Directory This is the directory that will be accessed when you specify a ticker list without a directory qualifier. Output Files This is the directory in which your listing files will be placed in the absence of a directory name on the #OUTPUT_FILE specifier. ASCII I/O Directory This is the directory where the AOpen (ASCII File Open) function looks for the file being opened. Historical Data Directory This is the "top level" directory for your historical data files. For example, if your data files are subdirectories of "D:\MS", you could specify "D:\MS" here and then only specify the subdirectory name in the Data Directory Setup screen. Chart Program Directory The Chart Program directory is used to tell TAS the drive and directory where your charting program is located. This is used in conjunction with the Chart Command setting (page 19). Printer Setup In order to use the PrintGraph function or the "P" key while displaying a graph to print a graph with TAS, you need to prepare TAS with the Printer Setup screen. The values you need to set are described below. For additional information on Printer Device Support, see page 157. Each of the fields on the Printer Setup menu are toggled by hitting the SPACE or ENTER key to select the next option available. Once all options have been set correctly, hit the F10 key to save the settings. Printer Type The Printer Type field describes the printer or printer capture file to which you want to send your PrintGraph output. The choices are shown in the table beginning on page 157. Page 21 Printer Port Choose the printer port to which your printer is attached. If you intend to create PCX or EPS files rather than printing directly to your printer, set this field to None. Resolution Choose a resolution from Low to High. Orientation The orientation choice is either Portrait or Landscape. Portrait orientation will print the graph with the shorter side of the paper at the top of the graph. Landscape is usually better for graph printing. Page Size Specify Quarter, Half, or Full. TAS prints as many graphs per page as you specify in this setting. If you specify Quarter, TAS will print four graphs on a single page. Reverse The Reverse setting is either Yes or No. Unless you wish to print most of the graph in black, you should choose No. If your printer type is set to PCXxxxx, you should specify Yes for this setting to get a white background. Register Program When you register TAS , you will receive a Registration Code based on your Name. Whatever name you include in the file REGISTER.DOC will be used to form an encrypted code. Use the same name as sent in the REGISTER.DOC file. Place the Registration Code sent to you in the appropriate field. If you received an invoice with your TAS order, your name as it is expected to be entered, is shown on the invoice. You must use the same upper and lower case settings as shown on the invoice for your name to match the coded registration code. Page 22 Setup TAS Save Configuration Use this command (or the F10 key) to save any changes you have made to your configuration when in the Setup menu. Page 23 Running TAS Starting TAS from DOS In general, you can start TAS with the following format command: TAS [switches] [scriptName] [tickerListName] [@parameters] The options in brackets are optional and need not be specified. You can start TAS in "MENU MODE" by simply typing "TAS" by itself. TAS has switches available which you can specify on the command line. They are: -c Eliminate CGA "snow" -b Use BIOS to write to video screen. This may be necessary on some systems which are not 100% compatible. -m Use Monochrome color scheme If you are a registered user of TAS, you can also start TAS in "batch mode" by specifying the name of a SCRIPT, the scriptName, and the Ticker List, the tickerName, on the command line. So, if you had a TAS script named "SELECT.TAS" and a Ticker List named "MYSTOCK.TCK", you could run the SELECT script against the stocks in the list MYSTOCK by typing: TAS SELECT MYSTOCK If you wanted TAS to process all of the stock symbols (Tickers) in your data base, you can omit the Ticker List name. You can also specify initial script statements to be executed at the beginning of the script by specifying parameters on the command line, preceded by the "@" sign. Each statement should be terminated by a semi-colon, just as it would be if it were inserted at the beginning of the script. See the section titled "Syntax" beginning on page 49 for a description of script statements. Page 24 Running TAS TAS Main Menu The TAS Main Menu is the starting point when you work with TAS. It contains a horizontal menu with four items, Activities, Setup, Utilities, and Quit. When you first use TAS, you should go immediately to the Setup menu item and prepare the program for use. See the Installation section (page 11) for a discussion of TAS Installation and Setup. Activities The Activities menu item contains a pulldown menu that shows you the "activities" which you can perform while using TAS. The activities are . General Scripts . Selections . Profit Tests . Ticker List Page 25 Activity File Submenu Once you select a particular activity, you are presented with a File menu that lists the actions that can be applied to the activity of your choice.The options available for each activity are: . List all files matching the activity type . Edit or modify an existing activity file using the activity editor . Create a new activity file . Run or execute a specific activity file . Delete a specific activity file . Rename a specific activity file . Copy a specific activity file Run If you have an existing activity you want to run, you can use the Run file item to tell TAS to run the file. Once you enter the name Page 26 Running TAS of the file to be run, you will be asked which ticker list you want to use for this run. Edit The Edit file item will bring up the activity-specific editor for the particular file you are working with. See the section describing Activity Editors (page 32 ) for a description of the operation of each of these editors. For example, if you are in the Ticker List activity, you will be shown a ticker list screen where you can add and delete items from your ticker list. New The New file item can be used to create a new activity file. Once you type in the new name (without the file extension, please), the Activity Editor is brought up for you to complete the creation of the file. List The List menu item allows you to see a list of all the files available for the particular activity you have previously chosen to work with (by selecting from the Activity menu prior to this menu). When you select List, an extended File Selection Screen will appear which contains the names of all the files in the file directory ending with the file extension of the type of file you have chosen. (e.g., ".TAS" for script files). Next to each file's name is a title description for the file. This title is obtained from the #TITLE command at the beginning of the file (if there is one), or *Untitled* if no title line is found in the file2. 2 Because it is necessary to open and read the first line of each matching file in your directory, you may have to wait a few moments for the extended list to display. Page 27 You can modify the file's title by using the Alt-T key combination while the cursor is positioned on the file name whose title is to be modified. If you are viewing Script files, while presented with this list, and if you have defined your user editor, the Alt-E will invoke your own editor with this file as input. To use the TAS built-in editor, move the cursor or mouse over to the file name you choose and press Enter (or double-click with the mouse). Once you do this, you will be placed in the Edit mode for the activity file. To avoid re-reading each file and extracting the title information from it when you request this list, TAS creates the list one time and creates a special file containing the titles from each file. If you add or delete a file, you should refresh this list by using the alt-R (refresh) key combination while the list is displayed. Delete You can use the Delete file item to delete a file. Type in the file name (without the extension always) and hit ENTER. The file will be deleted. Rename You can rename a file by choosing this item. You will first be prompted for the name of the existing file. After entering that name, you will be asked for the new name of the file. Copy Choose this item to copy a file. You will first be prompted for the name of the existing file. After entering that name, you will be asked for the new name of the file to which it is to be copied. Prompt for a File Name For all menu choices in the File menu (except the List item), if you don't recall the name of the file, you can hit ENTER at the prompt, and the List screen will appear. Move the cursor or the mouse over to the file you want to choose and hit ENTER. The List screen will close and your file name will appear in the prompt box. Just hit ENTER at this point to perform the action you choose. Page 28 Running TAS Quit This option will exit from TAS. If you want to go to DOS and return to what you were doing within TAS, use the ALT-X key. Error Processing When an error is detected in a TAS script, selection, or profit test, TAS will attempt to isolate the cause of the error and display an error message as well as an information screen that describes the cause of the error and a recommendation for fixing the error. The script line number and column where the error was detected is also given to you to further isolate the problem. Below is an example of an error detected in a Selection Script. Note the error message next to the line in error and the explanation at the bottom of the page. Page 29 #MAX_QUOTES 31 F1 : ARRAY; F1 = MOV(c,10,'S')x; { <----- ERROR#60:Don't know what to do with "X" } F2 : ARRAY; F2 = MOV(c,30,'S'); F3 : ARRAY; F3 = f2-f1; C1 = ISECT(f1,f2)=0; +--------------------------TAS ERROR 60 Has Occurred-------------- ----------------+ The following error has been detected around Line 3, Column 20 ERROR#60:Don't know what to do with "X" Press ESC to continue -----------------------Explanation for Error Number 60------------ --------------------+ Cause: TAS syntax check has encountered a symbol or word that is either misplaced, mis-spelled, or preceded by a word that might be mis-spelled. Recommendation: Check the spelling of the word pointed out and the previous word. Also, check that you are using it in accordance with the description given in the User's Guide. Page 30 Running TAS Special Keys within TAS F1 The F1 key is the HELP Key. This key will cause a help screen to be display when you press it. The help topic will be for the current cursor location (i.e., "context sensitive help"). ALT-X The ALT-X key will exit from TAS to DOS. This will allow you to do a few things outside of TAS. Because TAS is a large program, you won't have a a great deal of storage left when you exit to DOS. To return to TAS from DOS, type "EXIT". ALT-M The ALT-M key will tell you how much memory is available to TAS and the maximum size used of the SYMBOL TABLE. This key will also display the amount of EMS memory used by the program as well as the video display parameters detected by the program. ESC The ESC key will always leave the screen or prompt you are in and immediately "pop" you back to the previous menu. If a TAS script is running, a prompt window will open, asking you if you want to abort the run. alt-V While a script is running, you can view the output file by typing the alt-V key combination. This will bring up a file viewer to look at the current output file. p The p letter key will print a graph when it is displayed. Page 31 Activity Editors The following sections will describe each of the activity types along with their editor screens. Scripts - Editing TAS Scripts TAS has a built-in text editor which can be used to create and modify TAS script files. All TAS script files end with the suffix ".TAS". The editor screen will then appear with the contents of the file displayed. If the file is New, you will see a shaded portion after the first empty line in the file. This shaded area is used to show unused lines in the file. To insert new lines in the file, use either the Alt-I key or the INS key as described below. The TAS editor cannot handle lines larger than 78 characters . If the line is longer than that, it will be broken at column 78 and continued onto the next line. If the total length of the line is more than 256 characters, the last part of the line will be lost if the file is saved. You should be aware of this when creating a script in another editor and then using the TAS editor to modify it. An arbitrary "break" at column 76 might cause a word to be split in the middle, thus introducing an error into the script. Page 32 Activity Editors Editor Function Keys F1 HELP Key If you need help with the editor, hit the F1 (Help) Key. You will see a list of editor commands. F3 Save Script File Key When you are done with your editing, you can save the file by hitting the F3 (Save) Key. If you do not want to save the file, hit the ESC (Abort) Key. F4 Run Script Key The Run Script key will run the script you are currently editing without saving it back to its original script file. F5 Check Script Key If you wish to check your script file for errors in syntax, press the F5 key. If there are errors in the script which can be detected by the Check Script function, an error message showing the type of error encountered and the line and column number on which the error occurred will appear in a window at the bottom of the screen. This window will disappear after a few seconds or when you hit a key. Then the script file will be positioned so that the cursor is on the line where the error was detected. It is usually the case that the error is somewhere either on that line or on the previous line. F7 Formula Builder Key One key available in the editor is the Formula Builder Key. This key will bring up a list of Technical Indicator functions and Pre-defined Data Arrays. If you select one of the functions or arrays, the subsequent parameters of the function (e.g. MOV "Moving Average" requires 3 additional parameters) will be prompted. Enter each parameter. When you are done, the formula and parameters will be placed into your script file at the location of the cursor when you hit F7. Editor Control Keys Alt-R Rename script file. You will be asked to provide a new name for the script file. When you save the script, it will be saved with the new name. Alt-S Save script file. The script file will be saved to disk under the name shown at the top of the edit screen. You can continue editing the script after it is saved. Alt-I Insert a new line into the script following the cursor location. Alt-D Delete the line containing the cursor. Page 33 Alt-E Invoke your own Editor with the current contents of the file. Once you save your changes from within your own editor, the modified file will be restored to the builtin editor with your changes. INS Toggle Insert mode. When in insert mode, the cursor is a large block. Pressing the ENTER key while in insert mode will cause a new line to be inserted into the file with the characters to the right of the cursor on which the ENTER key was pressed. Selections - Scan and Report Using the Selection activity of TAS, you can create your own report containing up to 7 columns of calculated formulas or data values. In addition, you can use the Condition entry areas (below the Formulas) to specify which conditions must be satisfied for a ticker to be included in the report output. The figure below shows the equivalent of the MetaStock Utility "Rank" option where the first formula is the Current Price ("C" is the Closing Price), the second formula is the 26 day Rate of Change (ROC). The third formula is the 10 day Simple Moving Average of the price. The fourth is the 10 day Simple Moving Average of "F2", where "F2" is the 26 day ROC. Finally, the last formula F5 is the percentage by which the Price is above or below the moving average contained in F3. Page 34 Activity Editors Formulas for the Selection You can place any formulas or data value in each of the Formula areas. If you hit the F7 key, a list of functions included in TAS will be shown on the screen and you will be prompted for the parameters of the function. Conditions for the Selection Use the F6 (Next) key to move from the Formula window to the Condition window. The CONDITION entries are used to "select" only those tickers that match all the conditions specified. The conditions are specified in terms of the formulas given above. In the example above, if you only wanted to see tickers whose ROC (Formula 'F2') was greater than 50, then you could set CONDITION 1 F2 > 50 Also, if you had another condition, for example the current price of the ticker is greater than $5, you could place that condition as follows CONDITION 2 C > 5 and that would select only tickers whose ROC is greater than 50 and whose price is greater than 5. Titles for the Selection Output Report Use the F6 (Next) key to move from the Condition window to the Title window. You will see a column of titles to the right of each line in the Formula window. You can associate an eight character title with each formula. This title will show up at the top of the column containing the values from the associated formula in the report. If no title is entered, the actual formula will be used for the title in the report. Selection Run Options The OPTION Key (F5) allows you to set options for the SELECTION, such as the MAXIMUM QUOTES to read, and any INDEX file you might want to use. Be sure to use the F3 key (SAVE) if you are in the OPTION screen to save your options. Index Ticker If you want to run a selection that uses some index, such as the SP- 500, you can specify the ticker here. Then, in your formulas for the selection, you refer to the index ticker's value with the INDEX array name. Page 35 Maximum Quotes You can specify the maximum number of quotes to load for the selection. Setting this value high enough to compute each indicator correctly and no higher will speed the processing of each ticker, since only relevant data will be loaded. Minimum Quotes You can specify the minimum number of quotes to load for the selection. Start Date If you want to start your selection on a specific date, specify that date here. Make sure that the date is a date you have in the file. If it is not, the test will begin on the first date prior to that date. End Date If you want to end your selection on a specific date, specify that date here. Make sure that the date is one you have in the file. If it is not, the test will end on the first date prior to the end date. Running Your Selection Once your SELECTION is built, you can run it using the F4 Key. You will be asked for a TICKER LIST against which to run the SELECTION. Choose one. Once the SELECTION starts running, there is no output to the main part of the screen until the SELECTION completes. At that point, a "report" will display on your screen with the TICKER in the first column and the formula values you set up for F1 through F7 in each column. Page 36 Activity Editors Sorting on Selected Columns You can SORT your report by the contents of any column by typing the ALT key at the same time as you hold down the number over the column you want to sort on. For example, to sort on the contents of the column next to TICKER (this would be column numbered "2"), you would type ALT-2 key pair. If you want to change the order of the sorting from ascending order to descending order, type ALT-D (for "Descending"). To go back to ascending order, type ALT-A. Once you have set the sorting direction, you can then resort using a ALT-column_number again. Printing Your Selection Report To PRINT the contents of your report in the current sort order, type ALT-P. If you want to print to a file, enter a file name. To print to your PRINTER, type LPT1 or PRN (or whatever address your printer is hooked up to) in the file name prompt. Creating a Ticker List If you want to create a ticker list from the securities selected, you can press the Alt-T key combination. You will be prompted for the name of the ticker list to be created. Errors In Selection Formulas If you have any errors in the SELECTION you have created, you will be told about them when you try to run the SELECTION. An error message will be displayed and then the TAS EDITOR will be run with a dummy file called _RUNSEL.TAS. This file is the file that is created from your SELECTION. It is a special form of a TAS script. You should recognize the formulas though, since they are the ones you entered in your SELECTION. The EDIT screen will redisplay the error message and the explanation of the error at the bottom of the screen. Hit the ESC key and the cursor will be placed near the place where the error was found. In addition, the error message will be placed in the file to the right of the line in error. Look at the formula or condition and try to figure out what the problem is. You are only half done though. Now you have to go back to your SELECTION Editor screen (by typing ESC) and fix the formula(s) in that screen. Do not try to fix the problem in the Script Editor screen, since this is just a temporary view of the actual Selection Page 37 file. Once you have corrected the error in the Selection screen, be sure to save (by hitting F3) your file. Profit Tests - Test a system The Profit Test activity editor screen is similar in appearance to the Selection editor screen. Shown below is a sample of the Profit Test Modification screen. Profit Test Formulas You can fill in the FORMULAs (F1 to F8) with indicators (or combinations of indicators) you want to 'plot' for the profit test. Then, in the CONDITION entry areas (COND C1 to C6), you fill in conditions you would use in a BUY, SELL or STOP loss signal. To switch between Formulas, Conditions, and When screens, use the F6 function key. Profit Test Conditions Once you have entered your FORMULAS and the CONDitions, you can choose which conditions you want to use for the BUY, SELL and STOP signals. Page 38 Activity Editors In the example above, only RSI(14) is being plotted. The condition C1 tests to see if the RSI has crossed from below 30 to above 30 (Buy Signal). Condition C2 tests if the RSI has crossed from above 70 to below 70 (Sell Signal). Notice how C1 is entered below BUY WHEN, indicating the Profit Tester should buy if condition C1 is true (and the stock is not already held). And, then C2 is below SELL WHEN, indicating a similar SELL strategy. Profit Test Options Profit Test has a number of options which are set by hitting the F5 Function Key in this screen. You will see the following screen. Each of the items in bold represent one of several choices available for the option. When you bring up this screen, you can choose options by using the TAB key to move to each field and selecting the appropriate option. Type the HELP Key (F1) at each field to see the meaning of the choices. When you are done with changes to this screen, hit the F3 key to save the options. If you are in a "pop-up" window, hit ENTER, then hit F3. Profit Test Option Settings Initial Cash This is the amount of "money" the trading should start with. It must be sufficient to buy the amount of shares specified by the Share Purchase option below. For example, if you start with $1,000 and you are buying Round Lots (100 shares), your stock had better not sell for more than $10 per share or you won't have enough money to buy a round lot. Page 39 Test Type There are 3 choices for this option. You can perform a LONG , SHORT or BOTH test. A LONG test only takes long positions, that is, it only buys to open a position and sells to close it. A SHORT test only takes short positions, selling to open and buying to close ("cover") the position. A BOTH test opens a long or short position and reverses each time a signal is generated to "go the other way". This is essentially a "stop and reverse" system. Commissions You can use several commission structures for your simulated trading. The commissions for Charles Schwab, OLDE Discount, and PCFN brokerages are built into the profit tester. These commissions are accurate as of 1/1/91. You can also specify a percentage commission amount for each trade. Finally, you can ignore commissions altogether. Share Purchases You can elect to purchase shares of the security in either Round Lots or using all available cash. If you choose round lots, your profit test will purchase or sell stocks in groups of 100. This is important if you are using a real commission schedule, since the commission per share is reduced when you trade in round lots. Page 40 Activity Editors Price Slippage Price Slippage refers to the price at which you want to exercise the trade. Generally, you cannot execute a trade at the exact price you want, nor can you always trade at the previous day's closing price. So, you have several options for choosing the trade price. Price Slippage Meaning Type 0 - TODAYS Today's CLOSE closing price 1 - NEXT Tomorrow's AVERAGE (High+Low+Clos e)/3 2 - NEXT OPEN Tomorrow's Open Price 3 - NEXT Tomorrow's CLOSE Close Price 4 - NEXT HIGH Tomorrow's High Price 5 - NEXT LOW Tomorrow's Low Price The prices at which the BUY, SELL and STOP transactions occur are obtained from the choices given on the Profit Test Build Options screen. There are several choices, one of which is to buy at the close for the prior day. This is the default. If you have OPEN data, you should choose the option to buy at the OPEN price. If not, then you can choose an average of the price range, or several other choices. Just to elaborate on the profit testing, suppose on day 2/15/90, your buy signal is reached..in other words, the BUY WHEN is true. The price at which your buy is made is most accurately at the OPEN of the next day (since you are using CLOSING data for your test up to 2/15/90, you wouldn't have been able to really buy at the CLOSE for 2/15/90). If you don't have OPEN data, you can use some other choice from the prices on 2/16, the following day. But, in every case, the actual BUY takes place on 2/16/90, the day following the date the signal was given (can't buy after the close). Page 41 Output File Name If you want the output report from the profit test to go to a file, specify the name here. Report Detail There are three choices for this option: DETAIL, TICKERSUMMARY, and TOTALSUMMARY. DETAIL Show every trade TICKERSUMMARY Show totals for each ticker TOTALSUMMARY Show totals only for all tickers Maximum Quotes You can specify the maximum number of quotes to load for the profit test. This number should be less than or equal to the Maximum Quotes per Symbol setting in your Configuration Menu. Index Ticker If you want to run a profit test that uses some index, such as the SP-500, you can specify the ticker here. Then, in your profit test, you refer to the index ticker's value with the INDEX array name. Reinvest Profits This option determines how much money you want the profit tester to use for each trade. If you specify "Y", the profit test will use your current cash po- sition, including profits, minus losses and commissions to determine how much money you have available to trade. If you specify "N", the profit tester will initiate each trade with the same amount of cash, regardless of your prior profits, losses or commissions. Start Date If you want to start your test on a specific date, specify that date here. Make sure that the date is a date you have in the file. If it is not, the test will begin on the first date prior to that date. End Date If you want to end your test on a specific date, specify that date here. Make sure that the date is a date you have in the file. If it is not, the test will begin on the first date prior to that date. Page 42 Activity Editors Running the Profit Test To run the Profit Test hit the F4 key (once you leave the Options screen). If you want to save the Profit Test formulas, save it with the F3 key and then reselect it to run it. Errors In Profit Test Formulas If you have any errors in the Profit Test you have created, you will be told about them when you try to run the PROFIT TEST. An error message will be displayed and then the TAS EDITOR will be run with a file called _RUNPT.TAS. This file is the file that is created from your PROFIT TEST. It is a special form of a TAS script. You should recognize the formulas though, since they are the ones you entered in your PROFIT TEST. The EDIT screen will redisplay the error message and the explanation of the error at the bottom of the screen. Hit the ESC key and the cursor will be placed near the place where the error was found. In addition, the error message will be placed in the file to the right of the line in error. Look at the formula or condition and try to figure out what the problem is. Now you have to go back to your Profit Test Editor screen (by typing ESC) and fix the formula(s) in that screen. Do not try to fix the problem in the Script Editor screen, since this is just a temporary view of the actual Selection file. Once you have corrected the error in the Profit Test screen, be sure to save (by hitting F3) your file. The file that is built when you create (or modify) a Profit Test has a special file extension ".PTS" (Profit Test Script). This file has a special format that can be read by the Build/Run Profit Test menu. If you go in with an editor and change any part of the .PTS file, it is very likely that the .PTS file WILL NO LONGER WORK when you pull it up into the Profit Test screen. If you want to change a .PTS file, copy it to a file .TAS file name and edit that file. Once you do that, you have to run the file as a TAS SCRIPT, not a Profit Test. Page 43 Ticker Lists - Group Securities You can create "ticker lists" with TAS. A "ticker list" is a list of stock or ticker symbols which you can name as a group. This allows you to create individualized lists of symbols against which you can run your TAS scripts. As an example, you could create a ticker list containing the Dow Jones 30 Industrials, or a list containing only stocks you hold. When you choose the Ticker List/Edit activity item, the Ticker List screen will appear with all the ticker symbols contained in the Data Directories you have configured. Each symbol that is highlighted in YELLOW has been "selected" for inclusion in the ticker list. To select or unselect a symbol, move the cursor to the symbol and hit the SPACE Bar. If the symbol is selected, it becomes unselected or vice versa. If you want to Select All Tickers, hit the F9 (SELECT ALL) Key. To Unselect All Tickers, hit the F8 (UnSELECT ALL) Key. Once you have created the ticker list, hit the F3 (Save) Key to save it. If you do not want to save the list, hit the ESC (Abort) Key. If you want to run a TAS script against all of your data, create a new Ticker List called "ALL". Hit the F9 Key to select all symbols. Then hit the F3 Key to save the list. Page 44 Activity Editors In order to avoid significant delays while reading the tickers for every data directory, TAS will read the ticker symbols one time and create a special file with all tickers and their full names. TAS places the total list in a file called ALLTICK.SYM. Subsequent ticker list modification requests will read the ALLTICK.SYM file rather than going to the directories themselves. This speeds up ticker list loading many times over. If you change, add or delete ticker symbols from your directories, the ALLTICK.SYM list is out of date. To refresh the list, use the ALT-R (Refresh) key while viewing a list of ticker symbols. If you have set the Setup/Program Options option Include Ticker Period to "Yes", your ticker names will be followed by a slash and the period of the file, e.g. "AAPL/D" for APPLE COMPUTER Daily data. The period is not available with ChartPro data files. The ticker symbols are displayed initially in the order in which the files are found in your historical data directories. If you would like to sort them by ticker symbol, you can press the alt-S (Sort Tickers) key. Page 45 Utilities The Utilities menu is used to access functions outside of TAS. You can use this menu to switch to DOS, view a file, or run your own charting program. The Utilities menu appears as shown below: DOS Shell The DOS Shell command can bring up a DOS shell from which you can return to TAS by typing EXIT. This command will only work if you have at least 128Kb free memory available while in TAS. Run Chart Program Once you have setup your chart command (page 19) and your Chart Directory (page 21), you can use this menu item to invoke your chart Page 46 Utilities program. When you exit from that program, you will be returned to TAS. View A File If you want to view any file (smaller than 64Kb), you can use this menu item. Choose the file you want to view from the list which appears when you select this item. To return from View Mode, use the ESC key. Page 47 TAS Script Processing TAS reads each security name in the TICKER LIST from the historical data file. It reads the quotes for the file into the pre-defined data arrays up to the lower of either (1) the number specified in the QUOTES PER SYMBOL (in the Configure TAS Menu) (2) the number specified in #MAX_QUOTES in the script file itself, (3) all the quotes in the file, or (4), the number of quotes between the SCAN_DATE or Start Date and End Date. Once all the price history has been read into the data arrays, TAS "executes" the statements in the TAS script file. Once all statements in the file have been executed, TAS moves on to the next security's symbol in the TICKER LIST. This process continues until all the symbols in the TICKER LIST have been read or until an error is encountered in the script file. The order in which TAS processes the securities in the ticker list is in the order in which the security files are found in the Metastock directories or in the Chartpro directories, not the order of the ticker list. Page 48 TAS Script Language TAS Script Language The TAS Script Language makes it possible for you to tell TAS what you want to look for, compute, print, graph, and test. TAS scripts are simply text files that contain statements of what you want the program to do. These files can then be run to perform specific searching or computational tasks. The choices made in the way you tell TAS to do something are what can be called the "syntax" or grammar of the Script language. In a way, this language is similar to English, where you would say "If a is greater than b then tell me about it", except, as you will see, TAS also has abbreviations for relationships like "is greater than". Other than that, however, the language can be read like English and algebraic notation combined. The following topics will give an explanation of the TAS script language. The TAS package contains numerous examples of TAS Scripts. You should print them and look at them while reading the next section. The sample scripts contain "comments" which explain what the script is doing at each point of the script. Syntax In the subsequent discussion, the word "statement" is used. A "statement" is like a sentence in English. Like a sentence, it is composed of "words". A semi-colon (;) is generally used to tell TAS that the statement you just entered is done. Every statement should be terminated by a semi-colon, though TAS does not enforce this rule in every case. In the syntax descriptions below, words you must use are in UPPER CASE, and parts of the statement that are up to you are in lower case. Page 49 Building Blocks The "Building Blocks" of TAS scripts are the following types of items: Variables Variables are where you put values or, in the case of "pre-defined" variables, where you get them. The names are anything you choose, but they have to start with a letter of the alphabet and must consist of characters from the following set {A to Z, 0 to 9, and underscore}. Other characters are not allowed in the variable name. Assignment Statement The ASSIGNMENT statement ("=") is how you can move a value from one place to another. Arithmetic Operators These are the usual ADD(+), SUBTRACT (-), MULTIPLY(*) and DIVIDE(/) and EXPONENTIATION (^). Functions A "function" is a built-in TAS technical indicator , math function, or "output" function which usually returns a value or performs some predefined action. IF statement An "IF" statement is used to test a condition or value. Once the condition is tested, you can perform certain actions "if" it is TRUE or "if" it is false. WHILE statement The WHILE statement is used to control the execution of a sequence of instructions that need to be repeated until some condition is false. Page 50 TAS Script Language FOR statement The FOR statement is used to describe the values to be used for a "loop" or sequence of statements that need to be executed a certain number of times. BEGIN-END Blocks A BEGIN-END block is a way to "group" several statements into one. For example, the IF statement only allows you to execute the following "statement". However, if you use a BEGIN followed by multiple statements, followed by an END, the whole series of statements from the BEGIN through the END is considered to be ONE statement. It is similar to putting parentheses around an arithmetic expression. Logical AND The AND word takes a left-hand side and a right-hand side. If both are TRUE, the whole is TRUE. Logical OR The OR word also has a left and right side. If either is TRUE, the whole is TRUE. Page 51 Relational Operators These are how you test the "relation" between two single values. The English form of the operators and the symbolic form for the operators are shown in the table below. You may use either form for expressing an equality or in- equality relationship. English Language Symbolic Keyword form form EQUAL = GREATER THAN > GREATER THAN OR >= EQUAL LESS THAN < LESS THAN OR EQUAL <= NOT EQUAL <> Special Relational Operator for Arrays The CROSSED ABOVE/BELOW operator is used to determine if one indicator or data arrays crossed above or below another. It only works with array values Comments These are used to "document" the TAS script. They perform no function, but only help to understand what is going on in the general area of the script. They are good to use and should be included in the script to make it easier to derstand. un Variables Page 52 TAS Script Language A Variable is a name given to a "place" to put a "value". Think of it as a "name for a value"3. Except for pre-defined variables (see page 67) you can make up the names for the variables in your script. A variable name must start with an alphabetic letter, contain only letters, numbers and underscores ("_"). Some valid names are: my_stuff, my_122999, my999, m9, M32_togo, Beethoven, etc Generally, you first use variables in "assignment statements", that is, you first "put" something into them. Subsequently, you can use them as values passed to functions or another statement such as an IF statement or a WHILE statement. Creation of Variables TAS variables are created in one of two ways. You can "declare" them before using them, as you must do with ARRAY's, or you can just assign some value to them. TAS Variable Types "String" Variables These are variables to hold text information, like 'IBM', or 'THIS IS A STICK-UP'. String variables must be surrounded by single-quote (') characters. String variables can be different lengths, depending on what you put into them. They can contain blanks at the end of the variable, which you may need to remove with the TRIM function. "Numeric" Variables These are variables that hold numbers, like 32, or -75.69, or 10000034. There are two types of numeric variables, INTEGERS and REAL numbers. An INTEGER is a number which has no decimal point and must be smaller than 32,767 in value. 3The variable names are anything you choose, but they have to start with a letter of the alphabet and must consist of characters from the following set {A to Z, 0 to 9, and underscore}. Other characters are not allowed in the variable name. Page 53 An INTEGER can be NO LARGER THAN 32,767 in value. If you need to use a number larger than 32,767 then you must include a decimal point followed by at least one zero in the number. For example, if you want to use the number 1 million in your script, you cannot say 10000000 because the number is larger than 32,767 and it does not contain a decimal point. In this case, you must say 1000000.0 to tell TAS that the number is a REAL number. "Numeric Array" Variables These are variables that hold many numbers in an "array (or " collection of numbers). All of the numbers in the array have the same variable name; however, you cannot "look" at them all at once. You must pick out one of the numbers of the array by specifying its "location" in the array. Each array has exactly QUOTE_COUNT entries. The variable QUOTE_COUNT is "filled in" by TAS when the script runs for the ticker file. Given a ticker that has 100 quotes (or the maximum number of quotes to load, MAX_QUOTES, set to 100) the following indices are usable for any array in the ticker file: English Index Index guage Lan Relati Relativ Index ve to e to Today First Day Today 0 100 Yesterday -1 99 2 Days -2 98 Ago 3 Days -3 97 Ago ......... ..... ..... ......... .. 99 Days -99 1 Page 54 Ago TAS Script Language An example of an array that is always available when a ticker is processed is the Closing Price array,"C". Obviously, there are many Closing Prices (one for each quote, in fact), and in order to refer to the Closing Price on a particular day, there must be some way to reference it. In the absence of any explicit reference to a particular day in an array, TAS will assume the reference is for the entire array. In other words, the statement below X = H + C; means X = ADD(H, C); Performing a calculation on an entire array can be time-consuming if it is not necessary. If, for example, you only wanted to add the High and the Close for the latest day, you would say X = H[0] + C[0]; or X = High of Today + Close of Today If you need to know what the value of the Closing Price was two days before the last quote's day, you have to tell TAS that you want the quote two days before. You can do this in one of three ways. Suppose you have 100 days of data loaded. To get the Closing Price quote from two days prior to the last day, you could say: 1)C[-2] 2)C[98] 3) C 2 DAYS AGO Methods (1) and (2) above use "subscript" notation to tell TAS which number in the array is needed. In the first case, you are saying "give me the Closing Price array entry 2 days backward from the last entry". The negative number says to start "counting" back days from the last day. The second version, shown in (2), says "give me the Closing Price array entry 98 days from the first day loaded". Since we had stipulated 100 days were loaded, this is the same as the price two days ago (100-98 = 2). Finally, the last expression, shown in (3), says in English that you want to retrieve the Closing Price 2 days ago. In the interest of readability, this version is the best, but it is more wordy and does incur a very slight performance penalty when you run the script, since TAS has extra work to do in order to interpret the English phrase. In addition, you can also describe the current day's Closing value by saying Page 55 CLOSE OF TODAY and you can refer to yesterday's Closing price by saying CLOSE OF YESTERDAY Other pre-defined data arrays, like H, L, C, V (for High Price, Low Price, Closing Price and Volume) are examples of arrays. If you want to refer to a closing price 10 days ago (using our earlier example of 100 days loaded), you can say C[-10] or C[90] or CLOSE 10 DAYS AGO Each time you refer to an "element" of an array, you need to either provide the "subscript" in square brackets, e.g. [-10], which means "subscript minus ten" or say "xx DAYS AGO". You can define your own variable array by "declaring" it (prior to first using it) as follows: variable_name : ARRAY; OR variable_name IS AN ARRAY; where 'variable_name' is the name by which you want to refer to the array. If you want to declare more than one variable of the same type, you can also declare each separated from the next by a comma, and ending with a colon followed by the type of each of the variables. For example, to declare strings named S1,S2, and S3, you could say S1,S2, S3 : String; You might wonder "Why would I define my own array?". The answer to that depends on what you are trying to do. Generally, you define your own array because you want to put some indicator value into it, or you want to create your own new indicator from existing functions and data. Most builtin indicators create arrays of numbers. When using a charting program, you can see these numbers as a line on a graph. Each of the points on the line are values of the indicator for a particular day. Now, suppose you wanted to know what the value of the indicator was two days ago. Normally, when an indicator is computed, it returns (or creates) an array. However, if you don't put the result of the indicator function into an array (declared via the ARRAY declaration as shown above), then the result stored is the indicator value for the current day only. In order to "look" at the indicator value for other than the last day loaded, you must place it into an array that you have already declared. For more information on placing the results of a function into an array or variable, see the section that follows. Page 56 TAS Script Language Assignment Statement The Assignment Statement is used to set the contents of a variable or array to the result of an "expression". An "expression" is a term, that means sequence of mathematical operations, a logical relation and/or the result of a "function". It might help to give some examples of assignment operations: a = b + 3 / 4; The "=" (equal) is the operator that says "assign to"4. So, reading the above assignment, in English, it says "add the contents of variable 'b' to the result of dividing 3 by 4. Place this result in variable 'a'". If variable 'b' contained 6 when this statement was encountered, then variable 'a' would contain 6.75 (6 + 3/4). Another example is: a = (c[-1] + c[0]) / 2; In this example, the array 'c' is pre-defined as the "closing price array". So, the statement is adding the closing price yesterday (c[-1]) to the closing price today (c[0]). It is then dividing the total of this addition by 2 and placing the result in variable 'a'. Note the use of the parentheses to "group" the addition so that it would be done before the division by 2. If there were no paren- theses, the result would have been considerably different. Instead, it would have divided today's closing price by 2, added it to yesterday's closing price, and placed the result in 'a'. Another example of an assignment is the result of a "function" call. All Technical Indicators available in TAS are created by making a "function" call. In other words, the Technical Indicator is referred to by its name (the "function"). So, for example, a = mov(c,21,'E'); calculates the 21 day exponential moving average ("mov" function) of the closing price array. If variable 'a' has been declared to be an ARRAY prior to this point, then 'a' contains all the moving average "points". If 'a' has not been declared as an ARRAY, then 'a' will contain the value of the moving average at the last point of the range, i.e., today's value. See the section titled "Numeric ArrayVariables for a description of arrays and "subscripts". 4 TAS will also accept a simple "equal" sign in lieu of the "colon- equal" sequence of characters for an assignment statement. Page 57 Arithmetic Operators Arithmetic Operators are addition (plus sign '+'), subtraction (minus sign '-'), multiplication (asterisk '*') , division (slash '/') and "exponentiation" (caret "^"). When you write an arithmetic expression, you should use parentheses to guarantee the order in which the operations are performed. In general, exponentiation is performed first, then division and multiplication are performed, then lastly, addition and subtraction. Functions A "function" is a reference to a "built-in" Technical Indicator function (like "MOV(...)"), an output function (like WRITE or WRITELN), or an array manipulation function (like DIVBY). IF Statement The IF statement is perhaps the most powerful feature of TAS. It enables you to create complex relationships between indicators based on their relationship with other indicators and values. An IF statement is written as follows: IF condition THEN statement to execute if the condition is true ELSE statement to execute if the condition is false; The ELSE part of the IF statement is optional, but sometimes it is convenient to make a two way decision about something. You could alternatively say: IF condition THEN statement to execute if the condition is true; The TAS language does not require you to include the word THEN after the IF part of the statement. You must terminate each IF statement with a semi-colon. Note, however, that IF statements containing an ELSE part are terminated after the ELSE part. For example, IF a IS GREATER THAN b THEN WRITELN('a is greater than b, hurray!') ELSE WRITELN('a is not greater than b, sorry.'); Note how there is a semi-colon on the last line, but not after the first WRITELN. However, if you wanted to print a message only if "a" is greater than "b", then you would say IF a GREATER THAN b THEN WRITELN('a is greater than b, hurray!'); Page 58 TAS Script Language Note the semi-colon after the last line. WHILE Statement The WHILE statement executes a statement (or group of statements surrounded by a BEGIN..END) as long as the condition given in the WHILE statement is true. A WHILE statement is written as follows: WHILE condition statement to execute "while" the condition is true FOR Statement The FOR statement executes a statement (or group of statements surrounded by a BEGIN..END) a certain number of times, and while a condition is true. The FOR statement has three parts to it. each part separated from the previous part by a semi-colon. The first part is done once, before the statement following the FOR is executed. This part of the FOR statement is called the initializer. The second part is the test of the condition that controls the loop. This part is called the condition. The third part is executed each time after the statement following the FOR has been executed. This third part is called the re-initialization step. The format of the FOR statement is FOR initializer; condition; re-initialization; statement; As an example, suppose you wanted to add the HIGH and the LOW for each day of the security's loaded data and also get the difference of the HIGH and the LOW5. Also suppose you wanted to place both of these values in their own array. You could put a FOR loop "outside" of the actions you wanted to perform for each day. Using the index variable i to refer to each day's array entry, you would set it up as follows: HIGHLOWSUM : ARRAY; HIGHLOWDIFF : ARRAY; FOR i = 1; i <= QUOTE_COUNT; i = i+1; BEGIN HIGHLOWSUM[i] = CLOSE[i] + HIGH[i]; HIGHLOWDIFF[i] = CLOSE[i] - HIGH[i]; END; This statement is a very powerful and convenient way to "iterate" or loop through some portion of the price or indicator data. 5Of course, you really wouldn't want to do this with a FOR statement, since both of these values can be computed by the following two simpler statements: HighLowSum = C + H; HighLowDiff = C - H; Page 59 FOR EACH POINT Statement The For Each Point statement is another (and perhaps easier) method of processing each loaded data point. Unlike the For statement, the For Each version will handle all the subscripting or indexing for the statement that follows. The format of the FOR EACH statement is FOR EACH POINT STARTING AT initial_index [USING variable] statement; where initial_index is an expression which will be the first quote day accessed in statement and the optional variable will be set to the index of the day to be accessed. As an example, the following three routines are identical in what they do. Each will add today's close minus yesterday's high to the variable A, for each day in the file. Each starts at day 2, since the statement that follows refers to the prior day. (1) For I=2 ; I <= Quote_Count; I = I + 1; A = A + C[I] - H[I-1]; and (2) For Each Point Starting at 2 Using I A = A + C[I] - H[I-1]; and (3) For Each Point Starting at 1 A = A + C[0] - H[-1]; Example (1) uses the For statement as described in the previous topic. Note how the subscript I is used in both examples (1) and (2) to reference the current day index. In example (3), there is no use of the variable I to reference each day, since the day index is implied by the For Each statement when the Using variable portion is omitted. BREAK Statement The BREAK statement can be used within either a FOR or WHILE loop to "break" out of a loop before the terminating condition has been reached. You must not use a GOTO statement to leave a FOR or WHILE loop. BEGIN..END Statement Suppose you want to do more than one thing if the condition "a is greater than b" is true. In that case, you would need to use a BEGIN .. END block. Page 60 TAS Script Language A "BEGIN..END" block "groups" all statements between the BEGIN and the END so that the entire "group" is treated as if it were one statement. This is useful in the case of the IF (or FOR and WHILE) statement, because the action to be taken following the statement THEN or ELSE part of the IF can only be one statement. But if you use the BEGIN..END block to group several statements, the entire block is treated as a "single" statement. Think of BEGIN..END blocks in the same way you would think of parenthesized arithmetic expressions. You use parentheses to "group" some operations so that they are treated as a group. An example of the use of the BEGIN..END block in an IF statement is shown below: IF a GREATER THAN b THEN BEGIN a = a - 1; b = mov(c,21,'E'); WRITELN('New values for a and b are:' ,a,' ',b); END; All three statements following the BEGIN will be executed (acted upon) if the value of "a" is greater than the value of "b". If you had left out the BEGIN..END section, only the first statement ("a = a - 1") would have been done if "a GREATER THAN b" was true. The following two statements would have ALWAYS been done, since they were not part of the IF. GOTO Statement and LABELS You can use the GOTO statement in a script to transfer control to a LABEL you define in the script. A LABEL is defined by a COLON (":") immediately followed by a LABEL NAME. For example, in the script below, the third line has the sequence ":AGAIN". This makes "AGAIN" the name of a LABEL. On the tenth line of the script, there is a "GOTO AGAIN" which transfers the "flow of control" of the script back to the statement just following the label 'AGAIN'. The purpose of the script below is to show an example of GOTO and LABEL's, but incidentally, it also computes all the moving averages for periods from 20 days to 40 days and prints them6. 6This example is rather contrived, since it is easily replaced by a FOR loop which doesn't require using a LABEL or a GOTO. Page 61 ma_array10 IS AN array; n = 20; :AGAIN ma_array10 = mov(c,n,'e'); writeln( ticker, date,int(n), ' day moving average is ', ma_array10); n = n+1; if n LESS THAN 40 then GOTO AGAIN; When you use the GOTO within a BEGIN..END block, you must be careful not to GOTO someplace outside of the block. Your script must encounter the END statement which matches the previous BEGIN statement. GOSUB statement The GOSUB statement is used to "go to a subroutine". This statement can be used when you have the same section of script code that you want to execute several times. Rather than including the same lines in the script in each place you want to use them, you can place them in one location in the script and use GOSUB each place you want to execute them. When you use GOSUB, you specify a label where the 'subroutine' starts. When the subroutine is completed, it should have a RETURN statement. The RETURN statement will return the script control back to the statement FOLLOWING the GOSUB. Here is a sample script using the GOSUB statement: Page 62 TAS Script Language a = 5; gosub s1; gosub s2; return; :s1 begin writeln(ticker); writeln('s1 entered, a = ',int(a)); return; end; :s2 a = a+1; begin writeln('s2 entered, a = ',int(a)); gosub s3; return; end; :s3 a = a+1; begin writeln('s3 entered, a = ',int(a)); return; end; The output from this script is: AMH s1 entered, a = 5 s2 entered, a = 6 s3 entered, a = 7 RETURN statement The RETURN statement in a script will stop processing the current ticker or return from a GOSUB call. For example, if you want to avoid computing several complex indicators if there are less than 100 quotes in the file or the price is less than $5, you could put the following section of code BEFORE your calculations in the script: IF quote_count LESS THAN 100 OR close LESS THAN 5 THEN RETURN; Or, if you have a subroutine that you call with the GOSUB statement, you need to return back to the place where the GOSUB was made by using a RETURN statement at the end of the subroutine. Page 63 GOSUB SUB1; {Call subroutine 1} RETURN; {Return to TAS and end script} :SUB1 { BEGINNING OF SUB1} { DO WHATEVER SUB1 DOES HERE ......................} RETURN; { RETURN FROM SUB1} STOP Statement The STOP statement can be used to completely stop a script's processing and return to TAS without processing any more ticker symbols. PROLOG statement The Prolog statement is executed once before any other data has been read for any ticker, and before any other statement in a script. It can be used to set headings, initialize your variables, get user input via the Ask function. You may not load or access any data arrays within the PROLOG statement, since the data arrays have not yet been allocated by the program (TAS doesn't know how big to make them yet!). EPILOG statement The Epilog statement is executed once after all other data has been read for all tickers, and just before the script is going to complete. It can be used to produce totals, do the final SORT actions required by your script, or anthing else that will finish up and complete your processing. Within the EPILOG statement, you have access to all data arrays. Logical Operators You can combine relations by using the words "AND" and "OR" and "NOT". They have the same sense as in English. Whenever you use AND and OR, you can use parentheses to group your relations to be sure they are computed the way you want them to be understood. For example: IF a GREATER THAN b AND b EQUAL TO 1 THEN WRITELN('a is greater than b and b is equal to 1'); This example compares "a" to "b". If "a" is greater than "b", then it compares "b" to the number 1. If "b" is equal to 1, then the message a is greater than b and b is equal to 1 will be printed. If either of the "relations" (a in "relation" to b AND b in "relation" to 1) is not true, then the WRITELN will not be done. On the other hand, suppose we want to print the message if either of the conditions is true. Then we would say: Page 64 TAS Script Language IF a > b OR b = 1 THEN WRITELN('a is greater than b OR b is equal to 1'); In this case, it would print the message if "a" were greater than "b" or if "b" were equal to 1. You can also ask for a condition to be false by preceding it with the word "NOT" as in IF NOT a GREATER THAN b THEN WRITELN('a is NOT greater than b'); Relational Operators Relational Operators describe a "relationship" between the ex- pression on the left of the operator and the expression on the right of the operator. For example, "a > b". 'a' is on the left side, 'b' is on the right side, and the operator is '>' which means "greater than". Relational operators can be expressed using mathematical notation (">", "<", "<>", ">=") or by using English forms of the same relation, such as "GREATER THAN", "LESS THAN", etc). You can only use relational operators with single numeric values, that is, you cannot ask if one array is greater than another array, though you can ask if one entry in an array is greater than another entry in an array. Crossed Above/Below Operator TAS has a special operator to determine if one array has crossed above or below another array within a specified number of days. The way you use this operator is to say array1 CROSSED ABOVE array2 WITHIN n DAYS or array1 CROSSED BELOW array2 WITHIN n DAYS both array1 and array2 must be arrays. For example, if you wished to see if the Closing price had crossed above the 20 day simple moving average of the Close within the last two days, you could say If Close CROSSED ABOVE sma(C,20) WITHIN 1 DAYS which counts a crossover today as 0 days ago, yesterday as 1 day ago. So, in this case, asking for a crossover today or yesterday would be "within 1 days". Comments There are two ways you can add comments or descriptive notes to a TAS script. Comments can be surrounded on both sides by "curly braces". These are the characters at the right of your keyboard. They look like this: { - Left "curly brace" } - Right "curly brace" Page 65 You can place these "curly braces" around any thing in your script file that you do not want TAS see. It is only for your eyes and the eyes of other humans. The second form of comment is to use two "forward slashes" to tell TAS to ignore anything to the right of the slashes. For example you could say: valuex = 32; // set the value of the x variable Double slash comments are slightly easier to type than using opening and closing braces, and since comments are good to use, anything that makes them easier to write is also good. Page 66 TAS Script Language Pre-Defined Variables Predefined Variables are variables that are "filled in" when each MetaStock TICKER is processed or at specific times during the processing of ticker files. TICKER The 'ticker' symbol, e.g., AXP FULLNAME The 'full name', e.g., AMERICAN EXPRESS DATAPATH contains the DOS file name of the data subdirectory currently being processed. TICKER_PERIOD contains the periodicity of the ticker file. This is taken from the Metastock PERIOD field. QUOTE_COUNT The number of quotes in the file QUOTE_RANGE Initially set to QUOTE_COUNT by TAS. This variable can be modified by the script to set the index of the last quote in the file for computation. FIRST_TICKER Variable, which, if equal to 1 (one), indicates this ticker is the first to be processed. LAST_TICKER Variable, which, if equal to 1 (one), indicates this ticker is the last to be processed. Note that this variable will not be set if there are any ticker symbols in your ticker list that are not in your historical data files. It is best to use the EPILOG statement to perform end of script operations. DATE The date of the latest quote in the file in the format MM/DD/YY. Page 67 PLOT_PHASE Variable which is set to 1 when the Profit Test Script is entered for the first time for a ticker. TEST_PHASE Variable which is set to 1 when the Profit Test Script is entered for the EACH quote for a ticker. END_PHASE Variable which is set to 1 when the Profit Test Script is entered for the last quote for a ticker. Pre-Defined DATA Arrays A pre-defined DATA Array contains one entry of one type of value for each day in the ticker file. There are as many entries in each array as there are days loaded for the ticker. Unlike user-defined arrays, the pre-defined arrays should not be defined within the script with the array declaration. Since they are pre-defined, they are always available for use within the script. There are two ways to refer to each of the pre-defined arrays. There is an English language name, such as CLOSE and a "short variable name", such as "C", for the Closing Price array. The names for the pre-defined arrays are shown in the table that follows: Page 68 TAS Script Language Pre-defined DATA Arrays English Short Description language able Vari name for Name array OPEN O The OPEN PRICE "data array" HIGH H The HIGH "data array" LOW L The LOW "data array" CLOSE C The CLOSE "data array" VOLUME V The VOLUME "data array" OPEN_INTERES OI The OPEN T EST INTER "data array" EQUITY EQUITY During a profit test, this array contains the equity position (cash plus shares * price) of the test. INDEX INDEX Array containing the CLOSE quotes for a TICKER de- fined by an INDEX command. Page 69 DATES DATES Array of DATES associated with each of the price entries. These dates are in number for- mat, not string format. Page 70 Pre-defined Functions Pre-defined Functions TAS indicators and functions which are also available in MetaStock have the same names and same parameters7 as those documented in the MetaStock Custom Formulas Section of the MetaStock "User's Manual". Refer to the Metastock documentation, the Encyclopedia of Technical Market Indicators, or any other technical analysis reference for additional information about these functions and their computation and use. Technical Indicators available in Metastock ad Accumulation/Distribution Usage: ad() The Accumulation/Distribution indicator, developed by Marc Chaikin, calculates the percent range a stock moves in a given day and multiplies this times the volume. The relationship of the close is (Close - Low) - (High - Close). This is then divided by the range (High - Low) and multiplied by the volume. The result is added to the running total. The buying pressure is compared to selling pressure for each day and like the OBV the indicator is cumulative. The A/D line is analyzed much like the OBV. If a stock is going to rise then there should be volume behind it. This volume is measured by the degree the close is closer to the high of the day. If there is buying pressure then the percent of the close times the volume will be greater. This adds more to the A/D line and divergences may be detected before the price has actually risen to a great extent. Sample script: 7 In some instances, the parameter to a MetaStock named function has to have single quotes around it. This is the case with any function that passes a single character as a parameter, such as the last parameter in the "mov" (Moving Average) function. Page 71 {A/D Volume Line for one year of data} #Max_Quotes 265 OpenGraph(3,-264,0); SizeGraph(3,1,3); Graph(1,'PRICE'); Graph(v,'VOLUME'); Graph(ad(), 'ACCUMULATION DISTRIBUTION LINE', mov(ad(),30,'s'),'30 DMA'); CloseGraph(); References: Chaikin, Marc. 177 E. 77th Street, New York, NY 10021 adx Average Directional Movement Usage: adx(periods) The Average Directional Movement (ADX) indicator is the exponentially-smoothed Directional Movement Index (DMI) over p periods. adxr Average Directional Movement Rating Usage: adxr(periods) Each element [i] of the array returned by the ADXR function is the exponential moving average of ADX over p periods relative to ADX[i], and ranges between 0 and 100. ADXR provides a measure of directionality of a security. add Add two arrays Usage: add(a,b) Add each element of array "a" to the corresponding element of array "b". cci Commodity Channel Index Array Usage: cci(periods) periods = number of periods in the CCI calculation as shown below. The CCI is a price momentum indicator that works well for commodities, stocks, and mutual funds. Mathematically, CCI[i] = (M - A)/(X * D) percent where: M =Mean price of current-day sample period. A =p-period simple moving average of M. D =Mean deviation of absolute values of the numerator over p periods. Page 72 Pre-defined Functions X =An adjusting factor, 0.15, which normalizes the excursions to a trading range of +/- 100. The CCI is a sort of "noise" filter, for which the random fluctua- tions should fall inside the +/- 100 percent range. Excursions outside this range tend to be nonrandom and indicate trading opportunities. Suggested trading rules are: 1.Buy long when CCI goes above +100%. 2.Sell long when CCI subsequently returns below 100%. 3.Sell short when CCI goes below -100%. 4.Cover shorts when CCI subsequently returns above -100%. Selection of a large number of periods (p) will filter out much of the noise, but can mask trading opportunities and trends. A smaller number of periods can create false signals. 90 and 53 weeks as tentative starting periods for your analysis are suggested. Another way of using the CCI is to note when the security being analyzed rises dramatically, but the rise is not reflected by the overall momentum represented by the CCI. Such a divergence is usually followed by a price correction for the security. co Chaikin's Oscillator Usage: co() Chaikin's Oscillator can be used to detect trend changes by watching short-term movement. An oscillator establishes a baseline using relatively longer-term data, and then measures fluctuations of the shorter-term data about this baseline. Chaikin's Oscillator uses volume accumulation data and is obtained by subtracting the 10-day exponential moving average of the Accumulation/ Distribution (AD) function line from the 3-day exponential moving average of the same function line. f you want to try different long-term and short-term periods, you can construct your own equivalent function using the MOV and AD functions. Because short-term movements tend to be erratic, use of such indicators should be only part of the your overall trading strategy. cos Trigonometric cosine Usage: cos(array) Cosine of each entry in array 'a'. Use the cos_(n) function to compute the cosine of a single number "n". cum Cumulative Sum of Array "a" Usage: cum(array) Page 73 Computes the cumulative sum of array "a". That is, each element of the returned array is the sum of all the preceding corresponding elements of the argument array. Since the elements are signed numbers, the cumulative sum can be increasing, decreasing, fluctuating, or it can remain constant. See also SUM function. div Divide two arrays Usage: div(a,b) Divide each element of array "a" by the corresponding element of array "b". dmi Directional Movement Index Usage: dmi(periods) The DMI and its derivative indicators can reveal when the market trends are significant enough to warrant entry into trades. Two other DMI-related indicators typically used in making trading decisions are the plus and minus directional indicators (PDI and MDI, respectively). DMI = (PDI - MDI) / (PDI + MDI) Please refer to the PDI and MDI descriptions for definitions of these functions. A typical trading-rule set is: 1. Enter trade only when ADX is rising. 2. Buy when PDI crosses above MDI. 3. Sell when PDI crosses below MDI, or when ADX turns lower. 4. Enter a short sale trade when ADX is rising and PDI crosses below MDI. 5. Cover (or close out) a short sale trade when PDI crosses above MDI or ADX turns lower. exp Exponential Function Usage: exp(array) Computes the exponential value of each element of array "a": 2.71828a ("e" raised to the "a" power). Use the exp_(n) function to compute the exponential of a single number "n". hhv Highest High Value Usage: hhv(a,p) Returns Highest High Value in the array 'a' over the period 'p'. Page 74 Pre-defined Functions The first 'p' values of the result are zero. llv Lowest Low Value Usage: llv(a,p) Returns Lowest Low Value in the array 'a' over the period 'p' The first 'p' values of the result are zero. log Natural Logarithm Usage: log(a) Natural logarithm (loge) of each entry in array 'a'. Use the log_(n) function to compute the natural logarithm of a single number "n". macd MACD indicator Usage: macd() The MACD (Moving Average Convergence Divergence) indicator was developed by Gerald Appel. It is a price momentum oscillator representing the point spread difference between fast and slow exponential moving averages of the closing price, approximately equal to: macd() = mov(C,12,E) - mov(C,26,E) If MACD is displayed graphically, a trigger line, mov(macd(),9,E), will also be displayed. A simple application is to buy or sell when the MACD passes through the trigger line. However, for this function to be effective, more complex decision rules generally will be required. macd() approximately equals macdx(12,26,9). mdi Minus Directional Movement (-DI) Usage: mdi(p) This function is part of the "DMI family" of functions. It enters into the DMI and ADX function calculations, and is used with the trading decision rules presented above in the DMI function description. MDI = SMDM/STR where: SMDM = Smoothed Minus Directional Movement STR = Smoothed Wilder's True Range. Minus Directional Movement (MDM) is the largest part of the current period's price range that is outside the previous period's price range. mfi Money Flow Index Usage: mfi(p) Page 75 as described in Equis "The Pointer" Volume 5, Number 4 and corrected in Vol 6, Number 1. mo Momentum Array Usage: mo(p) p = number of periods This function provides the price momentum expressed as a ratio. Each element of the returned array represents the ratio of the closing price for that day to the closing price "p" days before.: mo[i] = C[i]/C[i-p] Thus, MO indicates the velocity or rate of change of a security's price. ROC is a similar function except that ROC expresses the momentum as percentage or dollars (selectable). mov Moving Average Usage: mov(d,p,t) Moving Average Array d = Data Array p = number of periods t = Moving Average Type 'E' - Exponential 'S' - Simple 'W' - Weighted 'TRI' - Triangular Each element [i] of the returned array represents a computation that uses data from "p" elements of array "d" relative to element [i]. Thus, if "p" represents days, the average moves along with each day represented by the returned array. For example, the 10-day moving average for 5 days ago uses data from 14 days ago to 5 days ago, inclusive. The specific value for each element in the returned array (using the same data) depends on the moving average type selected using the "t" parameter: S - for Simple Moving Average. Each element in the simple moving average is the sum of the elements for "p" periods, divided by "p". Although the simple moving agerage has its uses, most analysts prefer to "smooth" the input data. This is based on the premise that older data entering into the calculation for days remote from a particular day (the "current day") should have less impact than newer data for days nearer the current day. Smoothing is performed by multiplying the data elements by a variable scaling factor. The two scaling factors commonly in use are the simple weight and the exponential: Page 76 Pre-defined Functions W - for Weighted Moving Average. The scaling factor is equal to the number of days from the beginning of the period. The multiplication products are summed, and the weighted average is determined by dividing this sum by the sum of the scale factors (the multipliers). For example, for a 5-day moving average of array "d", Index Scale Product relative Factor to Current Day 0 5 5 * d[0] -1 4 4 * d[- 1] -2 3 3 * d[- 2] -3 2 2 * d[- 3] -4 1 1 * d[- 4] The sum of the scale factors is 15. Thus, the weighted moving average for the current day is the sum of the products divided by 15. E - for Exponential Moving Average. The scaling factor is obtained by converting the period "p" to a percentage, applying this percentage to the argument array's current day value, applying the remaining percentage to the previous day's exponential moving average value, and summing the two products. The cumulative effect of repeatedly applying a scaling factor to older data is to "exponentially" reduce the older data while never actually losing it entirely. Current Day Factor (CDF) = 2 / (p + 1) Previous Day Factor (PDF) = 1 - CDF and Return Array[i] = (Argument Array[i] * CDF) + (Return Array[i-1] * PDF) Because this function is used so frequently, there are also shorthand forms for the exponential, simple and triangular moving averages, EMA, SMA, and TMA respectively. Page 77 mul Multiply two arrays Usage: mul(a,b) Multiply each element of array "a" by the corresponding element of array "b". neg Negative of Array "a" Usage: neg(a) Reverses the sign of each element of the array a by multiplying each element by negative one. nvi Negative Volume Indicator Usage: nvi() The Negative Volume Index (NVI) is used in an attempt to detect days when "smart" investors are active. Some analysts believe that the smart investors avoid trading in high-volume periods, and do their buying and selling during quiet periods of declining volume. The NVI is a cumulative indicator that can change only when the volume decreases. The amount accumulated for each (declining) period is equal to the percent change of a security's price multiplied by the previous period's NVI: if V[i] < V[i-1] then NVI[i] = NVI[i-1] + ( ((C[i] -C[i-1])/C[i-1]) * NVI[i-1]) if V[i] >= V[i-1] then NVI[i] = NVI[i- obv On Balance Volume Usage: obv() On balance volume uses the change of the close plus volume to determine how much buying or selling pressure there is in a stock. If the close is higher than yesterday then the volume is added to yesterdays OBV. If the stock closes lower than yesterday the volume is subtracted from the OBV indicator. Because this indicator keeps a running total it can reveal the accumulation or distribution of a stock. This can show early interest in a stock or an eventual sell off. OBV can be analyzed several ways. A simple moving average of the OBV can be used to watch for breakouts. For more intense study, the patterns the indicator makes can be compared to the stock for divergences, higher highs, or lower lows. These patterns may suggest activity not seen in just in the price chart. Sample script: {On Balance Volume for one year of data} Page 78 Pre-defined Functions #max_quotes 265 opengraph(3,-264,0); sizegraph(3,1,3); graph(1,'PRICE'); graph(v,'VOLUME'); graph(obv(),'ON BALANCE VOLUME', mov(obv(),30,'s'),'30 DMA'); closegraph(); References: Granville, Joseph E. New Strategy of Daily Stock Market Timing for Maximum Profit. Englewood Cliffs NJ: Prentice_Hall, 1976. oscp Price Oscillator Usage: oscp(p1,p2,t,r) Price Oscillator formed by subtracting a "t" type "p2" day moving average of the Closing Price from a "t" type "p1" day moving average of the Closing Price. p1 = shorter moving average period p2 = longer moving average period t = Moving Average Type 'E' - Exponential 'S' - Simple 'W' - Weighted 'TRI' - Triangular r = ROC Type '%' - percentage ROC '$' - Unit ROC oscv Volume Oscillator Usage: oscv(p1,p2,t,r) Volume Oscillator formed by subtracting a "t" type "p2" day moving average of the Volume from a "t" type "p1" day moving average of the Volume. p1 = shorter moving average period p2 = longer moving average period t = Moving Average Type 'E' - Exponential 'S' - Simple 'W' - Weighted 'TRI' - Triangular r = ROC Type '%' - percentage ROC '$' - Unit ROC pdi Positive Directional Movement (+DI) Usage: pdi(p) Page 79 This function is part of the "DMI family" of functions. It enters into the DMI and ADX function calculations, and is used with the trading decision rules presented above in the DMI function description. PDI = SPDM/STR where: SPDM = Smoothed Plus Directional Movement STR = Smoothed Wilder's True Range. Plus Directional Movement (PDM) is the largest part of the current period's price range that is outside the previous period's price range. per Performance Indicator Usage: per(p) Performance Indicator computed as follows: a c o / c / per[i] = CLOSE[i] c 1 - / * 100 c / cCLOSE[1] / e 0 pvi Positive Volume Indicator Usage: pvi() The Positive Volume Index (PVI) is the opposite of the Negative Volume Index (NVI). It is used in an attempt to detect days when unsophisticated investors are active. The PVI is a cumulative indicator that can change only when the volume increases. The amount accumulated for each (increasing) period is equal to the percent change of a security's price multiplied by the previous period's PVI: if V[i] > V[i-1] then PVI[i] = PVI[i-1] + ( ((C[i] -C[i-1])/C[i-1]) * PVI[i-1]) if V[i] <= V[i-1] then PVI[i] = PVI[i-1] ref Reference function Usage: ref(d,p) Page 80 Pre-defined Functions This function is used to "shift" a data array "d" forward by "p" entries. For example, if you wanted to compute the compute a rate of change over a ten day period, you could use the formula X = SUB( CLOSE, REF(CLOSE,-10) ) to place this value into the array named X. rsi Wilder's Relative Strength Usage: rsi(p) p = number of periods This indicator is credited to J. Welles Wilder. The RSI function performs the following calculation: RSI = 100 - (100/(1+X)) where X is the ratio of the exponentially-smoothed moving average of gains to the absolute value of the expentially smoothed moving average of losses, taken over "p" periods. Thus, RSI is a price momentum indicator that is a function of changes in closing prices. Note This function is unrelated to relative strength indicators that compare price to the various market indicators. roc Rate Of Change Array Usage: roc(d,p,r) Computes the rate of change of the data array "D" over "p" periods, using either a percentage basis or a dollar unit basis. d = Data Array p = number of periods r = ROC Type '%' - percentage ROC '$' - Unit ROC Each element [i] of the returned array equals the the rate of change of data array "d" over "p" periods relative to d[i], using either a percentage basis or a dollar unit basis. sar Wilder's Parabolic Usage: sar(i,m) The Parabolic (or Stop and Reverse) indicator creates a parabolic stop line either over or under the price graph. where 'i' = increment value and initial 'm' = maximum acceleration factor Wilder's explanation uses the values of i = .02 and m= 0.20 In ChartPro, this indicator is referred to as Technical Study 'PTP' Page 81 sin Trigonometric sine Usage: sin(a) of each entry in array 'a' Use sin_(n) for the sine of a single number. sqrt Square root Usage: sqrt(a) of each entry in array 'a'. Use the sqrt_(n) function to compute the square root of a single number "n". std Statistical Standard Deviation. Usage: std(d,p) Computes the standard deviation of the array 'd' using 'p' data points. Defined as the square root of the variance (see var below). stoch Stochastic Oscillator Usage: stoch(p,s) p = number of periods s = k slowing periods STOCH is a moving price velocity or momentum indicator. Each element of the returned array is defined as follows: Return_Array[i] = ( (Close[i] - LV[i])/(HV[i] - LV[i]) ) * 100 where: LV[i] is the "s" period low at p[i]; i.e., LV = llv(p,s) HV[i] is the "s" period high at p[i]; i.e., HV = hhv(p,s) Since there is no built-in smoothing, this function tends to exhibit erratic behaviour as it drops-off old data and picks-up new data. This can be reduced by application of the moving average function (MOV). Also, sell and buy signals can be defined for first moving- average levels above and below a second moving-average line of the same function. sub Subtract one array from another Usage: sub(a,b) Subtract each element of array "b from the corresponding element of array "a". sum Sum array over period Usage: sum(a,p) Page 82 Pre-defined Functions Create a 'p' day summation of array 'a'. Sums the elements of array "a" over "p" days. This function is similar to the CUM function, the difference being the cumulative sum for each element is limited to "p" days. tan Trigonometric tangent Usage: tan(a) of each entry in array 'a'. Use tan_(n) for the tangent of a single number. trix TRIX Function Usage: trix(p) Calculate a 1 day percent Rate of Change of a p day triple expo- nential moving average of the closing price. TRIX calculates a 1-day percent rate of change of a "p"-day triple exponential moving average of the closing price. Triple exponential smoothing essentially eliminates the influence of cycles shorter than "p" periods. If a 9-day (typical) moving average of the TRIX function were plotted along with the the TRIX function, buy would be indicated when TRIX moves above the moving average line, and sell would be indicated when TRIX moves below the line. tsf Time Series Forecast Usage: tsf(a,p) This function computes a p day linear regression of the array a for each day. var Statistical Variance Usage: var(d,p) of the array 'p' over the time period 'p'. Each element [i] of the returned array is the stastical variance of "p" data points taken from array "d" starting at element [i]. Variance indicates how widespread the realizations of a function are likely to be. This, it can serve as a predictive indicator. Variance is derived as follows: 1.Calculate the simple moving average of data array d for p periods Page 83 W = mov(d,p,'S'). 2.Determine the difference between d and the simple moving average X = d-W 3.Sum the squares of the preceeding, and divide by p Y = X*X Z = sum(Y,p), Variance = Z/p. Note The square-root of the variance is the standard deviation (see STD function). vhf Vertical/Horizontal Filter Usage: vhf(array,period) The VHF function computes a ratio of the difference between the highest and lowest values of the "array" over the "period" to the sum of the absolute values of the one day point rate of change for the period. vol Volatility Indicator. Usage: vol(pm,pr) This is the 'pr' day Rate Of Change Oscillator of a 'pm' day ex- ponential Moving Average of the difference between each day's high and low price. wc Weighted Close Usage: wc() defined as (2 * CLOSE + HIGH + LOW)/4 willa William's A/D Usage: willa() WILLA is a cumulative price indicator, for which a value for each day is added to the previous day's cumulative sum as follows: Page 84 Pre-defined Functions If C[i] > C[i - 1], return array element [i] = value at [i - 1] plus the following accumulation amount: C[i] minus the smaller of C[i - 1] or L[i] If C[i] < C[i - 1], return array element [i] = value at [i - 1] plus the following accumulation amount: C[i] minus the larger of C[i - 1] or H[i] Divergence-based trading rules are: Sell if security goes to new high but WILLA does not go to new high. Buy if security goes to new low but WILLA noes not go to new low. Note The AD function is a similar indicator, except that it is based on volume instead of price. willr William's %R Usage: willr(p) for 'p' periods. This is equivalent to a 'p' period stochastic with 1 day smoothing. The result is then reduced by 100. zig Zig Zag Function Usage: zig(a,r,t) Compute a ZIG ZAG function for array 'a'. 'r' is the minimum percentage or unit (dollar) change which must be made in order to reflect a change in the Zig Zag line. The third parameter 't' is either '%' or '$'. If it is '%', then the 'r' value is expressed as a percentage change, otherwise it is a unit (or dollar) change. If you want to see what kind of profits you could make, run the ZIG.PTS Profit Test file. According the Equis Metastock User's Manual, "The Zig Zag indicator has 20/20 hindsight. Unfortunately, the Zig Zag's foresight is not as profitable. This is because the last "leg" of the Zig Zag indicator isn't fixed until future prices are known. If you use the Zig Zag indicator to predict future prices, you are probably fooling yourself." Sorry, but that's the way it works. It is provided in TAS as a sort of "benchmark" to judge how much the IDEAL strategy could SQUEEZE out of a portfolio. It is nearly ideal, because it knows the future. Page 85 TAS Functions addto Add number to array Usage: addto(a,n) Adds the number "n" to each entry of array "a" and returns the result in an array. angle Angle of a line Usage: angle(a) returns the angle in degrees of the line described by the array 'a'. This function is only usable on an array that has been created by either linreg or linreg2. Do not confuse the angle returned by this function with the angle as viewed on a chart of a security. When you view a chart, your charting program most likely has scaled your view so that the zero y-axis is not visible. In addition, the angle on a screen monitor is distorted by the aspect ratio of your monitor (typically 4 wide by 3 high). The angle returned by this function is a true mathematical angle which is calculated using the (0,0) origin. alpha Alpha function Usage: alpha() The alpha function is a "sister" function of the beta function. This function describes how much the stock's price would have moved on average on a yearly basis assuming the INDEX did not change. An alpha of .20 means that the stock would have increased 20% more than the INDEX during the year. In terms of a two way linear regression (performed by the beta function), the alpha is related to the y-intercept of the linear regression line. It is important to note that the alpha function must be called immediately after the beta function. At any other time, the results of the alpha function are undefined. avgprc Average Price Usage: avgprc() Creates an array where each entry is that day's (HIGH+LOW+CLOSE)/3 Page 86 Pre-defined Functions bbandt Top Bollinger Band Usage: bbandt(p,s) Bollinger Band upper (top) indicator for "p" periods with "s" standard deviations added to the p-day simple moving average. bbandb Bottom Bollinger Band Usage: bbandb(p,s) Bollinger Band lower (bottom) indicator for "p" periods with "s" standard deviations subtracted from the p-day simple moving average. beta "Beta" function Usage: beta(r) The beta function calculates the linear regression of the percentage rate of change of the closing price (of the current ticker being processed) to the percentage rate of change of the INDEX. Values of r, the rate of change period, are 'D' Daily rate of change 'W' Weekly rate of change 'M' Monthly rate of change The weekly rate of change calculates the rate of change from Friday to Friday and the monthly rate of change calculates the rate of change from the first of each month. The actual value returned by the beta function is the slope of the line created by this two way linear regression. The purpose of the beta function is to measure the stock's sen- sitivity to movement in the general market over the period of time chosen. A beta value of 2.00 means that the stock tends to move with the market, but 2 times as far (percentage change is twice as much). A beta of -.5 means that the stock moves in the opposite direction of the market, but only one half as far. compress Date Compression Usage: compress(cfactor) Compress will compress a security file's data by amount specified by cfactor. cfactor can have the following values: W weekly compression M monthly compression Y yearly compression n any number of bars to be summed for compression The cfactor parameter, if it is a letter, must be enclosed in single quotes. For example, to compress daily to weekly data, you would use Compress('W'); Compression points for the different periods are: Weekly : the Friday of the week Monthly : the end of the month Page 87 Yearly : the end of the year This function is only valid within a Prolog statement. After the Prolog statement runs, the data compression value cannot be changed. const Constant Array Usage: const(n) The const(n) function returns an array containing a "constant" value n. For example, CONST(100) creates an array that contains the number 100 in each element of the array. Contrast this to the SET function which sets an array to a constant value. CONST is preferable to SET, since its result can be used in a formula. corrcoef Correlation Coefficient Usage: corrcoef() returns the "correlation coefficient" of the last linear regression performed. This value ranges from -100 to +100. If the data points match the points in the linear regression approximation, the correlation coefficient will be 100. If the points show no correlation with the approximation, the correlation coefficient will be zero. datestr Create a formatted date Usage: datestr(d) Create a "date string" in the form MM/DD/YY from the DATES array entry 'd'. daymon Day of Month function Usage: daymon(d) Returns the "DAY OF THE MONTH" of the DATE contained in variable "d". The value returned is the day of the month. For example, daymon(910204) will return 4. daywk Day of Week function Usage: daywk(d) Returns the "DAY OF THE WEEK" of the DATE contained in variable "d". The value returned is a number from 0 to 6, where 0 is Sunday, 1 is Monday, 2 is Tuesday, 3 is Wednesday, 4 is Thursday, 5 is Friday and 6 is Saturday. defined Check if variable exists Usage: defined(v) Page 88 Pre-defined Functions Returns zero if the variable v has not been defined or used prior to this point in the script. This function is used frequently when you have a script that can be passed variable values from the DOS command line. If no variable values are passed on the command line, you would want to set the variables to some "default" value. Example: The script is written to use the moving average period contained in the variable period. If the period value is specified on the command line, it should use that value, but if not, it should use 21. The script would be written as follows: IF NOT DEFINED(period) THEN PERIOD = 21; MA = MOV(C,PERIOD,'S'); You could invoke the script using the parameter @PERIOD=50 to use a 50 day period, or if you didn't specify anything, the script would use a 21 day period. divby Divide array by number Usage: divby(a,x) Divide each element of array "a" by the value of "x". In this case, "x" is a single number. DOS Execute a DOS command Usage: DOS('command') This function executes the DOS command specified by "command". The DOS command must be a string surrounded by single quotes, or a string variable. Example: If while processing the ticker symbol "IBM" the DOS function is called as follows, DOS('Copy '+TICKER+'.PRO B:'); it will issue the DOS command COPY IBM.PRO B: copying the file "IBM.PRO" to drive B: Dump_Array Dump Array Contents Usage: Dump_Array(a1,a2...aN) Dump the contents of arrays"a1" to "aN" to the screen or a file. Each entry in the array is shown as a decimal number with the entry number in square brackets to the left, followed by the date. DUMP_ARRAY can be called with up to 12 array names. They will be printed side-by-side on the display. This function is useful for checking out the contents of an ar- ray...in other words, it is a debugging tool, not a report generat- ing tool. Page 89 ema Exponential Moving Average Usage: ema(a,p) Calculates an exponential moving average of the contents of the array a with the period p. Note that this is simply a shorthand version of the mov() function. expand Expand formatted string Usage: expand(format_string,v1,v2,....,vN) The expand function will "expand" the variables v1,v2,...vN according to the format specification given by the format_string. The function returns a string variable which can be printed, or displayed, just as the format function does. Example Suppose the current close for IBM is 48.75, the high is 52.375. To print the close, the high and the 21 day Moving Average (without decimal point), you could say WriteLn(Expand('%s %7.2f %7.2f %5.0f', Ticker, Close, High, Mov(Close,21,'S'))); which will print IBM 48.75 52.38 49 See the description of Format Specifiers (page 103) for a description of the format_strings you can use. findfst Find first value Usage: findfst(a,v) findfst finds the first occurance of the numeric value v in the array a and returns the day index (negative days in the past) on which the value occurred. If the value v was not found in a, the findfst function returns a positive number. findlst Find last value Usage: findlst(a,v) findlst finds the last occurance of the numeric value v in the array a and returns the day index (negative days in the past) on which the value occurred. If the value v was not found in a, the findlst function returns a positive number. findstr Find substring Usage: findstr(s1,s2) The findstr function will return the location of string s2 in string s1. If the string s2 is not found in s1, the result is 0. Page 90 Pre-defined Functions future Future array element Usage: future(a,n) This function can be used in a profit test to "cheat" by looking into the "future" to a date that is not currently under investiga- tion by the profit test routines. The function returns the value of the array "a" as of the point "n" days into the future. ifdn One if Down Usage: ifdn(a,p) This function returns an array containing a one in every position in which the array "a" is down from its value "p" periods in the past, and a zero in every other position. The statements x : array; x = ifdn(c,1); is equivalent to the following: x : array; For Each Point starting at p+1 if c[0] < c[-p] then x[0] = 1; else x[0] = 0; ifup One if Up Usage: ifup(a,p) This function returns an array containing a one in every position in which the array "a" is up from its value "p" periods in the past, and a zero in every other position. The statements x : array; x = ifup(c,1); is equivalent to the following: x : array; For Each Point starting at p+1 if c[0] > c[-p] then x[0] = 1; else x[0] = 0; int Create Integer Usage: int(x) Turns the number "x" into an "integer" by dropping any part of the number to the right of the decimal point. An integer is a number without a fractional part (the part after the decimal). The maximum number that you can turn into an integer is 32,767. Page 91 isect Find array intersection Usage: isect(a,b) Find the latest intersecting point of the two arrays "a" and "b". Returns the number of days since the two arrays intersected (as a negative number) or 1 (positive one) if they have never intersected. NOTE: Since the graph of the two arrays actually crosses BETWEEN two days, the value returned will be the later day AFTER the crossing. For example, if the arrays crossed between yesterday and today, the value returned will be zero. If they crossed between two days ago and yesterday, the value returned will be -1, and so forth. linreg Linear Regression Usage: linreg(a,s,e) Create a linear regression line using "least-squares" method to find the mathematical average of the values in the array "a" starting at entry "s" and ending at entry "e". If "s" is zero, it refers to the first value in the array. If "e" is zero, it refers to the last value in the array. Positive values for "s" or "e" refer to the appropriate array entries (counting from 0). A negative number in the "s" or "e" index is subtracted from the total number of entries in the array to get the appropriate positive array index. For example, x : array; x = linreg(c,-50,-10); will find the line passing most closely through the closing prices from 50 days before the last day in the file to 10 days before the last day in the file. linreg2 2 Way Linear Regression Usage: linreg2(y,x,s,e) Create a linear regression line using "least-squares" method to find the mathematical average of the values in the array y over the array x starting at entry "s" and ending at entry "e". If "s" is zero, it refers to the first value in the array. If "e" is zero, it refers to the last value in the array. Positive values for "s" or "e" refer to the appropriate array entries (counting from 0). A negative number in the "s" or "e" index is subtracted from the total number of entries in the array to get the appropriate positive array index. For example, x : array; x = linreg2(c,v,-50,-10); will find the line passing most closely through the closing prices and volume from 50 days before the last day in the file to 10 days before the last day in the file. Page 92 Pre-defined Functions load Load a data array Usage: load(t,f) The load function will retrieve the first occurrence of a ticker from the historical data directories. The ticker is specified as the first parameter to the load function. The second parameter of the load function is the field to be loaded from the ticker file. The name of the field must be surrounded by single quotes or it must be a string variable containing the name of the field. The field names are the same as the pre-defined data array names, that is, C for closing price, H for high price, etc. The value returned from the load function is an array containing the portion of the ticker file requested by the field name. macdx MACD Extended Usage: macdx(s,l,t) Compute an MACD indicator using a short term EMA of "s" periods, a long term EMA of "l" periods, and a trigger line of "t" periods. max Maximum value of a pair Usage: max(a,b) This function will return the maximum number between a pair of numbers. The statement result = max(a,b); is equivalent to If a > b then result = a else result=b maxPair Maximum value of two arrays Usage: maxPair(a,b) This function will create an array containing the pair by pair maximum values in the arrays a and b. The statement result : array; result = maxPair(a,b); is equivalent to result : array; For Each Point using I If a[I]> b[I] then result[I] = a[I] else result[I] = b[I] maxVal Maximum value in array Usage: maxVal(a) This function will return the maximum value in the array a. The statement Page 93 result = maxVal(a); is equivalent to result = 0; For Each Point using I If a[I]> result then result = a[I] maxQuotes Set Maximum Data Points Usage: maxQuotes(n) Sets the maximum data points (quotes) that will be read in for each security. This function is only valid within a Prolog statement. After the Prolog statement runs, the maximum data points cannot be changed. memleft Show remaining memory Usage:memleft() The memleft function will return the number of bytes of available memory. min Minimum value of a pair Usage: min(a,b) This function will return the minimum number between a pair of numbers. The statement result = min(a,b); is equivalent to If a < b then result = a else result=b minPair Minimum value of two arrays Usage: minPair(a,b) This function will create an array containing the pair by pair minimum values in the arrays a and b. The statement result : array; result = minPair(a,b); is equivalent to result : array; For Each Point using I If a[I]< b[I] then result[I] = a[I] else result[I] = b[I] minVal Minimum value in array Usage: maxVal(a) This function will return the minimum value in the array a. The statement result = minVal(a); is equivalent to Page 94 Pre-defined Functions result = 9999999; For Each Point using I If a[I]< result then result = a[I] month Month function Usage: month(d) Returns the Month (1-12) of the date value contained in the parameter. mulby Multiply by number Usage: mulby(a,x) Multiply each element of array "a" by the value of "x". In this case, "x" is a single number. now Current date Usage: now() Returns the current date at the time TAS is running. This date is a Date type variable in the form yymmdd. outputFile Specify listing file Usage: outputFile(f) The outputFile function can be used to set the file name f into which the script output is to be directed. over Over function Usage: over(a,b) If array "a" is "over" array "b", this function returns the number of days since array "a" crossed above(or over) array "b". See the description of the isect function page 92 for the values returned when the arrays cross. This function is especially useful to test for a crossover situation. If you want to know if the close just crossed "over" the 21 day moving average of the close, you can say if over(Close,Mov(Close,21,'E')) = 0 Then writeln('Close crossed EMA today'); pause Wait for keyboard input Usage: pause(s) The pause function will wait for up to s seconds or until a keystroke is pressed. peak Find Peak in Array Usage: peak(a,n) Page 95 returns the index of the 'n'-th peak value in array 'a'. A 'peak' is defined as a high value surrounded by lower values. The value returned from this function is the array index to the peak value. Page 96 Pre-defined Functions Page 97 In the figure above, the peak(C,2) call would return the index of the point marked P2. If you consider the volume vertical bars a day, then the value returned in this example would be '-13', or 13 days prior to the last day. per1 Performance using Array Usage: per1(a) Computes the "performance indicator" for an array a. The performance indicator is computed as a c o / c / per(a) = a[1] c * 100 -1/ c / ca[0] / e 0 redo Rerun profit test Usage: redo() The redo() function causes a profit test to be rerun again. The redo_count() function (below) returns a value one greater than the last time it was called. redo_count Profit Test Reruns Usage: redo_count() The redo_count() function returns the number of times a redo() function has been called for the same security file. It can be used to rerun a profit test with different variable values (i.e., optimize). set Set Array to Value Usage: set(a,v) Sets all entries in array 'a' to the value 'v'. For example, you could use this function to create an array where each entry is 22.5. sign Sign of array entries Usage: sign(a) This function will create an array of the "signs" of each entry in the array a. The statements Page 98 Pre-defined Functions result : array; result = sign(a); is equivalent to For each Point using I if a[I] > 0 then result[I] = +1 else if a[I] < 0 then result[I] = -1 else result[I] = 0; slope Slope of Line Usage: slope(a) will return the mathematical "slope" of the line whose points are contained in array "a". This array must have been created with the linreg function. The slope m of a line is defined according to the following formula y = mx + b m = (y-b)/x The slope of a linear regression line is simply the average change in the y-value of the data array (e.g., price) divided by the number of price bars (e.g. "days") over which the change is calculated. A 5 point rise over 10 days would be a slope of 5/10 or 0.50. sma Simple Moving Average Usage: ema(a,p) Calculates a simple moving average of the contents of the array a with the period p. Note that this is simply a shorthand version of the mov() function. strlen String Length Usage: strlen(s) The strlen function will return the length of the string variable "s" as an integer. For example, X = strlen('IBM'); will set X to 3. strrep String Replace Usage: strrep(s1,s2,n) will return a string whose n'th position is replaced in s1 by s2 for a length equal to the length of s2. For example, a = 'abcdef'; x = strrep(a,'gh',2); writeln(x); would print 'aghdef' Page 99 subfrom Subtract number from array Usage: subfrom(a,n) Subtract the number "n" from each entry in array "a" returning the result in an array. substr Substring function Usage: substr(s,b,l) The substr function takes a string "s" as the first argument and extracts the substring starting at character position 'b" for the length "l". For example, X = substr('ABCDEF', 2,4) will create set the variable X to the string 'BCDE'. tma Triangular Moving Average Usage: ema(a,p) Calculates a triangular moving average of the contents of the array a with the period p. Note that this is simply a shorthand version of the mov() function. trendline Create a Trendline Usage: trendline(a,s,e) Generate a line going through the points in array a from the day index s to the day index e. Example: x : array; x = trendline(C,-10,-2); creates a "line" that begins at and passes through the close 10 days in the past and ends at the point two days in the past. trendpar Parallel Trendline Usage: trendpar(a,t,s) trendline's sister function trendpar will draw a parallel line to trendline t, running through day s in array a. trough Find Trough in Array Usage: trough(a,n) returns the index of the 'n'-th "trough" value in array 'a'. A 'trough' is defined as a low value surrounded by higher values. The value returned from this function is the array index to the trough value. In the figure shown with the peak function above, the trough(C,2) call would return the index of the point marked 'T2'. Based on the Page 100 Pre-defined Functions volume bars shown, the value returned in this example would be '-11', or 11 days prior to the last day. tr Wilder's True Range Usage: tr() This function creates an array containing for each day, the higher of the following differences : Between today's high and today's low. Between today's high and yesterday's close. Between today's low and yesterday's close. The value of tr() for any day is always positive or zero. trim Trim blanks from a string Usage: trim() This function takes a string variable as input and returns a string variable as the return value. The returned string variable has all spaces removed from the right hand portion. year Year function Usage: year(d) Returns the Year (0-99) of the date value contained in the parameter. zero Zero Array Usage: zero(a) Sets each entry of array 'a' to zero. See the const function for a more flexible method of setting an array to a constant value. Page 101 Input/Output Functions WRITE and WRITELN Functions There are two direct output functions, WRITE and WRITELN. The WRITELN function is identical to the WRITE function, except that WRITELN causes a NEW LINE to be added at the end of the last field. The parameters to WRITE (and WRITELN) are either text strings, like 'this is a text string', surrounded by single quotes ('), or "variable values". A variable value is a value that you have assigned to a name by use of a formula or constant setting. There are "pre-defined" variables, such as H, L, C, V, O, TICKER, FULLNAME. These pre-defined variables are "filled in" when TAS reads the data values for each symbol. You can control the formatting of your output to some extent by using the characters sequence "\t" (backslash tee) in your text string. This will place a "tab" character in the output. TAS places "tab stops" every 4 columns of the output line. You can cause a new page to be printed by placing a "\p" (pagefeed) in your WRITELN string. In addition, the sizes of the two types of "numbers", are constant. If you are printing an INTEGER value, it is five characters wide, left-justified. If you are printing a number with a decimal point, it is eight characters wide (99999.999). This will allow you to line up the output with column headings. Page 102 Input/Output Functions CWRITE and CWRITELN Functions The CWRITE and CWRITELN functions are used to write to the output screen in different colors. The first two parameters to each of these functions are the foreground and background color of the text that follows. The colors are specified with the color names as shown on page under the heading Graph Color Values. 120 The CWRITE and CWRITELN functions are identical to the WRITE and WRITELN functions after the color specification. FORMAT Function The FORMAT function can be used to precisely control the way numbers print. This function takes two arguments. The first argument is the number to be formatted. The second argument is a "format specifier" string. Format Specifiers A format specifier string is is formed as follows: % [width] [.prec] [type] The [width] is the minimum number of characters to print. The [.prec] is the maximum number of characters to print or the minimum number of digits to print. Page 103 [type] for the FORMAT function can only be 'f' for REAL numbers For example, to print the closing price without the decimal point normally printed with the WRITELN fucntion, you could say writeln('Closing price is ',format(c of today,'%4.0f')); This would print the closing price in a field that is 4 characters wide with zero decimal places. Note also that the closing price printed would be rounded to the nearest integer. SORT Functions TAS contains functions which can be used to sort your report output. Rather than doing WRITE and WRITELN, you can call the SORTOUT function to place the report data in a "sort buffer". Once all the tickers have been processed (when LAST_TICKER is 1), you can then sort the data using the SORTON function. Finally, you can retrieve the sorted "lines" with the SORTGET function or print them with the SORTPRINT function. If you want to experiment with the SORT commands, you should start out simply and then work toward more complex combinations. These are advanced functions and are not necessarily appropriate for the person who doesn't want to plan their requirements. In order to understand how the sort commands work, you need to understand some terms. The first term is a "line". Each time you use the SORTOUT function, you give it a "line" of data which is placed in the "sort buffer". Each "line" is composed of 'columns". A "column" is a group of data values that are repeated for each SORTOUT function. So, for example, if you wanted to create a list of TICKERs and their Closing Prices, you would have two "columns", the TICKER and the Closing Price for the ticker. The "line" would consist of the combination of the TICKER and Closing Price. SORTOUT The SORTOUT function takes up to 40 parameters which are fields to be placed in the 'sort buffer'. As each ticker is processed, you can place the computed results in the 'sort buffer'. For example, suppose you wanted to create a report of tickers in order by their volume. You wanted the report to contain the TICKER, the High, Low and Closing prices as well. For each ticker you would say Page 104 Input/Output Functions SORTOUT(TICKER,H,L,C,V); SORTON Once all tickers have been processed, and their lines of data have been placed in the sort buffer using the SORTOUT function, you can sort the lines of data with the SORTON function. The SORTON function requires pairs of two parameters as follows: SORTON(column_number_1, direction_1,column_number_2, direction_2,....,column_number_N,direction_N) where: column_number_* is the parameter position of the data field (column) in the SORTOUT command that placed the data in the sort buffer. direction_* is either 'a' for ASCENDING or 'd' for DESCENDING sort. The SORTON function will sort first on column_number_1 in di- rection_1, then on the next column/direction pair, etc. Using the example given in the SORTOUT description above, since the report was to be sorted by VOLUME, that is the 5th parameter position ("column") in the SORTOUT function shown. The SORTON function returns as its value the number of records in the sort buffer. SORTGET After a SORTON function is called, the data in the sort array is in some particular sorting order. If you want to retrieve each "line" from the sort array, one at a time, you can use the SORTGET function. When you use the SORTGET function, you are asking TAS to "retrieve" the columns of data in the next line from the sort buffer and to place those data values in the variables you specify as parameters to the SORTGET function. After the SORTGET function returns, the variables you named in the SORTGET function call will be "filled in" with the values from the next line (in sequence) of the sort buffer. SORTGET(v1,v2,v3,....,vN) where v1 is the first variable to be filled in by SORTGET v2 is the second variable to be filled in by SORTGET, and vN is the last variable to be filled in by SORTGET. The number "N" must be exactly equal to the number of parameters used in the SORTOUT command that filled in the sort buffer. Page 105 The SORTGET function returns as its value a 1 (one) if the variables were "filled in" by a record from the sort buffer and 0 (zero) if not. This returned value can be used in a WHILE loop to determine when the last sort record has been obtained. SORTPRINT The trickiest part of using the SORT feature is the specification of the 'format string' used by the SORTPRINT function. If you have access to a C Programming book, you will find the format specifications under the PRINTF() function description. Short of that, a summary of the types of format specifiers follows: A format specifier is formed as follows: % [width] [.prec] [type] The [width] is the minimum number of characters to print. The [.prec] is the maximum number of characters to print or the minimum number of digits to print. [type] is one of three values: 'ld' for INTEGER values (result of INT() function) 'f' for REAL numbers (most results) 's' for a STRING CONSTANT (like TICKER or DATE) So, to print the results of the SORTOUT request given above, there must be five format specifiers (since there are five parameters to SORTOUT). The first parameter is the TICKER (which is a 'string') so its format specifier would simply be '%s'. The next three fields are all 'real' numbers (that is, they have decimal points), so their format could be '%7.3f' which would say, make the field 7 characters wide, and include three decimal places, like this '999.999', so this will work fine unless the price is greater than 1000. If it were, you could make the field '%8.3f' to add more room at the left. Finally, the last field, V (VOLUME) does not contain any portion beyond the decimal point. That is, shares are reported in whole numbers. But, because Volume is typically larger than the maximum value of an "integer" field (32,767) , it is also a 'REAL' number. To make the volume field report in whole units, without a decimal point, you would say '%8.0f' which would place volume in an eight character field with no decimal. So, the format string for the SORTPRINT would be: SORTPRINT('%s %7.2f %7.2f %7.2f %8.0f\n'); The '\n' at the end of the SORTPRINT format string is to start a NEW LINE after printing this line. Page 106 Input/Output Functions Column Headings For an example of controlling the printing of 'headings' in your TAS output, go to the section describing the pre-defined variable FIRST_TICKER. Using this variable, you can determine when to print a heading initially in your report. In addition, since all variables are initially set to zero before the first TICKER file is processed, you can use a variable to accu- late a "line count". You can test this variable and gener mu ate a new heading each time it is greater than the number of lines on your page (e.g. 66). An example of how to place a heading on each page of the report follows: IF FIRST_TICKER OR (LINE_COUNT > 65) THEN BEGIN LINE_COUNT = 0; WRITELN('YOUR REPORT HEADING WOULD GO HERE'); END; Then, each time you wrote a line in your script you would execute the statement: LINE_COUNT = LINE_COUNT + 1; ASCII File Functions AOpen Open ASCII file Usage: handle = AOpen(name,type) The AOpen function will open the file named for either reading name or writing, depending on the contents of the type parameter. If type is 'r', the file will be opened for reading. If type is 'w', it will be opened for writing. The handle value returned by the function is a number which is used to tell the other file functions which file you are referring to. You can have more than one file of this sort opened at the same Page 107 time. Example: Suppose you have a file named STOCK.DAT which contains three items per line. The first item is a security name, the second is a number of shares purchased, and the third is the purchase date. You could read each line and print it with the script below: StockName is a String; NumberOfShares is a Number; DatePurchased is a Number; hp = Aopen('STOCK.DAT','r'); While (AGet(hp,StockName,NumberOfShares, DatePurchased)) Begin WriteLn(StockName,NumberOfShares,DatePurchased); End AClose(hp); AClose Close ASCII file Usage: AClose(handle) The AClose function closes and releases the file which was opened with handle. See the AOpen description for an example. APut Put Line to ASCII file Usage: APut(handle,v1,v2,...vN) The APut function will put the variables v1,v2,...vN to the file whose handle was returned by an AOpen function. This function will only work if the file was AOpen'd for writing. Example: Suppose you want to create a ticker list from a script while generating some report or other scanning results. You only want to include those securities whose Close has crossed their 21 day moving average in your ticker list: Prolog Begin handle = AOpen('BUYLIST.TCK','w'); End; If Over(C,Mov(C,21,'E')) <= 0 Then APut(handle,Ticker); Epilog AClose(handle); AGet Get Line from ASCII file Usage: AGet(handle,v1,v2,...vN) The AGet function will read the variables v1,v2,...vN from the file whose handle was returned by an AOpen function. This function will only work if the file was AOpen'd for reading. In order for the AGet function to work correctly, you must pre- declare each variable prior to using it in the AGet function. This can be done by either assigning something of the correct type to it, or by declaring it (as shown in the AOpen example on page 108). Page 108 Input/Output Functions ASeek Locate Line in ASCII file Usage: ASeek(handle,s) looks for a record starting with the initial string value "s" in the file opened with handle "h" whose handle was returned by an AOpen function. This function will only work if the file was AOpen'd for reading. If the string "s" is found, the function returns 1, otherwise it returns 0. As an example of use, suppose you have a file that contains the ticker symbol and the P/E in a file called PE.DAT. Then, if you do Prolog handle = AOpen('PE.DAT','r'); If ASeek(handle,TICKER) = 1 Then Begin t : String; pe: Number; AGet(handle,t,pe); Writeln(t,pe); End; You will get a listing of ticker symbols and P/E's for those found in the file. Be sure to AClose the file in your Epilog. See the sample script AIO.TAS and AIO.DTA for a complete example. User Input Function Ask Get User Input Usage: Ask(p1,v1,p2,v2,...,pN,vN) The Ask function builds an input panel with prompt text p1,p2,...pN and gets input into variables v1,v2,...,vN. The Ask function returns -1 if the user pressed the ESC key while the input panel was displayed. As described in the AGet function above, you must pre-declare each variable prior to using it in the Ask function. This can be done by either assigning something of the correct type to it, or by declaring it (as shown in the AOpen example on page 108). Example: You want to write a script that can be used to check for 21 day exponential moving average crossovers, but you don't want to change the script each time you want to change either the moving average period or the moving average type. You can use the Ask function to get the period and type of moving average when you run the script. Page 109 Prolog Begin Period = 21; Type = 'E'; Ask('Enter Moving Average Period',Period, 'Enter Moving Average Type (S,E,W)',Type); End; If Close crossed above Mov(C,Period,Type) within 0 days Then WriteLn(Ticker,' is over ',Period,' Day Moving Average'); VMenu Vertical Menu Usage: VMenu(s1,s2,....sN) The VMenu function will create a vertical menu with the first line containing the string s1, the second line containing s2 and the n-th line containing the string sN . The function returns the line number selected, or -1 if the ESC key is pressed when the menu is presented. If you want to associate a "hot key" with a menu item, precede the "hot key" letter or number with an ampersand character. This will cause the following letter to be highlighted and will select that menu item if the letter is pressed. Example: The following will display a vertical menu asking for the type of study to run. If the user presses ESC, the script will stop. line = VMenu('&RSI Study', '&MOV Study', '&CCI Study'); if line < 0 then STOP; Page 110 Profit Test Statements Profit Test Statements Profit Test Statements are used to: Define which Technical Indicators are to be computed. Define BUY conditions Define SELL conditions Define STOP conditions See Page 41 for an explanation of how the price at which a transaction is executed is determined. The statements used to describe the situations above are described in the next 4 sections. PLOT statement: Define Technical Indicators The PLOT statement is used to create the formulas or indicators which will be used in the subsequent profit test. The PLOT statement is executed once per ticker symbol, and must be placed prior to any of the BUY/SELL/STOP WHEN conditions. The format of the PLOT statement is: PLOT stmt; where 'stmt' can be a single statement or a BEGIN..END block. For example, if your profit test is to test the Commodity Channel Index (CCI) for 14 days, you could say: CCI_ARRAY : ARRAY; { Define the cci array} PLOT CCI_ARRAY = CCI(14); Page 111 In the example, only one indicator is computed, so there was no need to use the BEGIN..END block. Suppose, however, that we want to incorporate Wilder's RSI in the profit test as well. Then we would say: CCI_ARRAY : ARRAY; { Define the cci array} RSI_ARRAY : ARRAY; { Define the rsi array} PLOT BEGIN CCI_ARRAY = CCI(14); RSI_ARRAY = RSI(14); END; { of PLOT statement} BUY WHEN - Define BUY Conditions The BUY WHEN condition causes the profit tester to 'buy' the stock if the condition is true. BUY WHEN expression; where 'expression' can be any combination of logical or relational operators. For example, using the last PLOT statement in the previous example, we will issue a BUY signal when the CCI rises above -100 and the RSI is less than 40: BUY WHEN cci_array OF YESTERDAY IS LESS THAN < -100 AND cci_array OF TODAY IS GREATER THAN -100 AND rsi_array IS LESS THAN 40; SELL WHEN - Define SELL Conditions The SELL WHEN condition causes the profit tester to 'sell' the stock if the condition is true. SELL WHEN expression; Page 112 Profit Test Statements where 'expression' can be any combination of logical or relational operators. For example, using the last PLOT statement in the previous example, we will issue a SELL signal when the CCI drops below 100 and the RSI is greater than 60: SELL WHEN cci_array OF YESTERDAY > 100 AND cci_array OF TODAY < 100 AND rsi_array OF TODAY IS GREATER THAN 60; STOP (LONG or SHORT) Condition The STOP LONG and STOP SHORT statements close a "long" position or a "short" position, respectively, by either selling or buying to cover an open position. To close out a long position (by selling), the statement is: STOP LONG WHEN expression; where 'expression' can be any combination of logical or relational operators. To close out a short position (by buying), the statement is: STOP SHORT WHEN expression; where 'expression' can be any combination of logical or relational operators. Adding a long stop to the example built in the prior sections, we could say that we want to issue a stop if, after having gone long, the CCI drops below -100 again. In that case, we could say: Page 113 STOP LONG WHEN cci_array < -100; TAS Profit Tester Functions The Profit Tester feature of TAS uses the following functions to indicate the buy/sell transactions controlled by a Profit Testing script. pt_buy() Buy the stock at the current closing price if not already held. If testing Short positions, buy to 'cover' the short sale. pt_sell() Sell the stock at the current closing price if it has been bought. If testing Short positions, sell the stock short. pt_stop(t) Issue either a Long Stop or a Short Stop. The parameter 't' is either 'L' for a Long Stop, or 'S' for a Short Stop. pt_price(t) Returns the share price at which the last OPEN transaction was executed. If there is currently no position held, then the value returned depends on the value of the parameter t. If t' is 'L', the value returned is 0. If t is 'S', the value returned is 9999999.0. The function is useful if you want to set a STOP based on the change in price. The parameter t is either 'L' for a Long Position, or 'S' for a Short Position. pt_setprice(p) Sets the price at which the next transaction will take place, where p is the price. Profit Test Phases - Advanced Use Only TAS runs the profit test in two phases. The first phase, called PLOT PHASE is when the script should compute the arrays to be tested during the next phase. This next phase is the TEST PHASE. This phase is entered for the data points of the ticker file. After all data points have been processed, the END PHASE indicator is set. Each 'phase' of the Profit Test process is indicated by a variable being equal to 1. Page 114 Profit Test Statements The two phases are analogous to the steps you might run in Metastock to do the Profitability Test. First, you would plot an indicator, moving average, or custom formula. This is similar to the 'PLOT PHASE' in TAS. Next, you would run the Profit Tester specifying your Buy/Sell conditions. Metastock then applies your Buy/Sell signals to each plotted point on the graph, proceeding left to right until it reaches the last day loaded. This is the 'TEST PHASE' in TAS. When the TEST PHASE is entered with the last day of the ticker file, a variable, called 'END_PHASE' is set to 1. Testing this variable will allow you to print out the results for the Profit Test. For each ticker, the script is entered once for the PLOT Phase, and then as many times as there are data points for the TEST Phase. If you use the PT_BUY, PT_SELL, PT_STOP, PT_PRICE functions, you will need to understand the different phases for the Profit Tester. However, if you use the BUY WHEN, SELL WHEN, STOP ... WHEN and PLOT forms of the Profit Test, you do not need to be concerned about the different Profit Tester phases, since the script generates the appropriate phase testing automatically. You should use the BUY, SELL and STOP WHEN statements to do your PROFIT TESTING. See RSIPT.TAS for an example. Page 115 GRAPH Functions The TAS GRAPH functions increase the power of TAS by making it possible to display the contents of any indicator, either builtin, or created by the user, in a graphical display. You can write a script that selects only those tickers with the conditions you are looking for, and when one of them is found, display a graph of the indicators and the stock price action. Up to 10 individual graphs with up to 10 indicators on each graph can be displayed at once with the GRAPH feature. Individual graphs can be assigned their own sizes relative to the other graphs on the screen, or each graph can be the same size as the other graphs. OPENGRAPH OPENGRAPH(numgraphs[,start,end]) This function prepares for numgraph graph windows to be displayed. The dates displayed are from quote start to quote number end. For example, to prepare to display 3 graphs of the last 50 days, you would say: OPENGRAPH(3,-50,0); The start and end values are optional, so you don't have to specify them. If they are not specified, the default is to display from the first to the last quote. SIZEGRAPH SIZEGRAPH(S1, S2,...Sn) where S1..Sn are the number of 'shares' of the display area each graph prepared by the OPENGRAPH function will get when shown. For example, as above, with 3 graphs to be displayed, if you want the first graph to have 2 times as much space as the second or third, you would say Page 116 GRAPH Functions SIZEGRAPH(2,1,1); Note that there must be as many parameters to the SIZEGRAPH function as the number in the first parameter of the OPENGRAPH function (numgraphs above). GRAPH GRAPH(a1,l1,a2,l2...,aN,lN) where a1 is the first array to be graphed, l1 is the legend (name to be displayed with) the graph of a1, a2 is the second array and l2 is the second legend. Each of the arrays and legends specified in the GRAPH command are graphed in the same window, one on top of the other. For example, to graph +DI, -DI and ADX on the same graph, you would say GRAPH(PDI(14),'+DI',MDI(14),'-DI',ADX(14),'ADX 14'); Simple as that. There is a special 'array' named '1' which represents the Price Bar Chart normally seen in charts. So, to plot the price bar chart, you could say GRAPH(1); DRAWLINE DRAWLINE(color,x1,y1,x2,y2,start,end) This function will draw a line from the point (x1,y1) to (x2,y2) starting at point start and ending at point end. The color parameter can be in the range from 0 (black) to 15 (white). Page 117 The following table lists the color codes that can be used with the DRAWLINE function. Color # Color Generated 0 BLACK 1 BLUE 2 GREEN 3 CYAN 4 RED 5 MAGENTA 6 BROWN 7 LIGHTGRAY 8 DARKGRAY 9 LIGHTBLUE 10 LIGHTGREE N 11 LIGHTCYAN 12 LIGHTRED 13 LIGHTMAGE NTA 14 YELLOW 15 WHITE Page 118 GRAPH Functions CLOSEGRAPH CLOSEGRAPH() The CloseGraph) function causes all the graphs since the last OpenGraph function to be displayed. It waits for you to hit a key to proceed. If you hit an ESC the graphing (and the script) stop completely. If you type the letter P at this point, the graphic screen will be printed to whatever device and device type you set up in your Printer Setup menu. If you have specified a Page Size other than Full, the program will wait until it has enough graphs to print a full page before actually doing any printing. Any other key will close the graph and go back to the regular TAS output display. PRINTGRAPH PRINTGRAPH() The PrintGraph() function will print the last screen of graphs drawn. In order to print successfully, you need to have filled in the Printer Setup menu (see page ). 21 Once the printing is complete, the graph screen is "closed" automatically, so you do not use the CloseGraph function. Graphics Text Control Functions TAS gives you extensive script based control over the presentation Page 119 of your graphic output. The following functions allow you to control text size, color, placement, font, direction, line styles, and straight line settings. Graph Color Values In some of the following functions, reference is made to graph color values. These values are named by built in constant values as follows: _BLACK , _BLUE, _GREEN, _CYAN, _RED, _MAGENTA, _BROWN, _LIGHTGRAY, _DARKGRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, _LIGHTRED, _LIGHTMAGENTA, _YELLOW, and _WHITE Graph Text Alignment Values Text alignment values used below are built in constants with the names below: For horizontal alignment _LEFT, _CENTER, _RIGHT For vertical alignment _TOP, _CENTER, _BOTTOM Annotate Annotate(s1,s2,s3,....,sN) The ANNOTATE function will place the strings {s1, s2, .. sN} on the previously drawn Graph in the lower left corner of the graph, with s1 at the top of the annotation, s2 below it, up to sN on the bottom line of the graph. HLine HlLine(y-value, color, linestyle) HLine draws a horizontal line on the previously drawn graph with the color and linestyle specified. The horizontal line's y-axis value is given by y-value. The linestyle can be a number from 0 to 32767, where the 0 is no line and 32767 is a solid line. The linestyle is a value, which when converted to hexadecimal format, indicates the number of pixels which are set in every 16 pixels group. VLine VLine(day_index, color, linestyle) The VLine function draws a vertical line at the day index specified by day_index, using the color value and linestyle specified. LineColors Usage: LineColors(c1,c2,c3,...,cN) The LineColors function will set the colors of lines drawn on a graph. Each array drawn by the Graph command will take the color given by the LINECOLORS i-th argument. See the BBAND.TAS script example for the use of the colors to set both the top and bottom Bollinger Bands to light red. LINECOLORS with no arguments will reset the colors to the default settings. Page 120 GRAPH Functions BGColor Usage: BGColor(color) The BGColor(color) function will set the background color of a graph to the color specified. TextColor Usage: TextColor(color) function will set the text color (legends, annotations, dates) of a graph to the color specified. TextAt Usage: TextAt(day,height,string) will print "string"on the graph at the day specified by "day" and the height specified by "height". TextDir Usage: TextDir(direction) The TextDir function will set the direction of subsequent text output according to the "direction" value: 0 = left to right 1 = bottom to top TextFont Usage: TextFont(fontId) function to set the text output font on graphs. Font types are: 0 8x8 bit mapped font 1 "Triplex" stroked font 2 Small stroked font 3 Sans Serif stroked font 4 Gothic stroked font TextAlign Usage: TextAlign(horizontal,vertical) where horizontal = _LEFT, _CENTER, _RIGHT vertical = _TOP, _CENTER, _BOTTOM This function will align text written with TextAt so that it is either left, center, or right aligned in the horizontal direction and aligned at the top, center or bottom in the vertical direction. The alignment for the TextAt function is around the point at which the text is to be written. TextSize Usage: TextSize(horizontal,vertical) The TextSize function takes two parameters, a horizontal width and a vertical height, expressed in 1/8'ths of "normal" size. For example, to set the text to be twice as wide and half as high, you would say TextSize(16,4); since 16/8'ths = 2 and 4/8'ths = 1/2. Page 121 GRAPH EXAMPLES Here is an example of a graph that shows how to draw a price graph with Bollinger Bands around it in the first (top) graph and the MACD indicator and its trigger in the bottom graph. opengraph(2); graph(bband_top,bband_bot,1); graph(macd(),'Macd',macdtrigger(),'Trigger'); closegraph(); The next figure shows a graph created by TAS using the following GRAPH commands: opengraph(2); sizegraph(2,1); graph(1,'PRICE', bbandt(20,2),'BBAND TOP', bbandb(20,2),'BBAND BOT', mov(c,21,'e'),'21DAY EMA', mov(c,200,'e'),'200DAY EMA'); graph(rsi(14),'RSI 14'); { show RSI } drawline(3,0,20,0,20); drawline(3,0,80,0,80); closegraph(); The first statement above, opengraph(2), tells TAS to create space on the screen for 2 graph areas. The second statement, sizegraph(2,1), says to give the top graph 2 "shares" of space and the bottom graph 1 share of space. This effectively gives the top graph 2/3 of the screen and the bottom graph the remaining 1/3 of the screen. The third statement graph(1,'PRICE', bbandt(20,2),'BBAND TOP', bbandb(20,2),'BBAND BOT', mov(c,21,'e'),'21DAY EMA', mov(c,200,'e'),'200DAY EMA') defines the values to be graphed in the first (top) graph. The first value to graph is the "price bar chart" which has a special indicator name of "1". Then, two Bollinger Bands, top and bottom, Page 122 GRAPH Functions are graphed . Finally, a 21 day Exponential Moving Average and a 200 day Exponential Moving Average are graphed. Each of these items to be graphed can be followed by a "legend" or title to be displayed on the graph in the color chosen for the line. The statement graph(rsi(14),'RSI 14') tells TAS to place a graph of Wilder's Relative Strength Index in the second (bottom) graph. The next two statements, drawline(3,0,20,0,20); drawline(3,0,80,0,80); tell TAS to draw a line in blue from the left of the graph (just drawn) to the right of the graph at height 20 and 80. This is just adding the 20/80 lines to the RSI graph for ease of recognition of crossings to overbought/oversold conditions. Page 123 Page 124 GRAPH Functions Page 125 TAS "POUND" (#) Commands TAS "POUND" commands are used to control special script processing. They must begin with a "pound sign" ('#') in the first column of the line, and they must be completed on the same line. DO NOT USE A SEMI-COLON to terminate a POUND command, since they are not TAS script language statements, but are TAS run settings. You should not put comments at the end of a POUND command either. "POUND" commands are executed by TAS only one time during the life of the script, as contrasted with other TAS script statements which are executed once for every ticker. OUTPUT_FILE Command You can direct the output of a script to a file by placing an #OUTPUT_FILE command in the script file. The #OUTPUT_FILE command must start in the first column of the line. It should be followed by the output file name surrounded by single quotes. If you want to direct your output to a PRINTER, for example, LPT1, you can use the #OUTPUT_FILE command, #OUTPUT_FILE 'LPT1' For example, #OUTPUT_FILE 'select.lst' would place the output text of the script into the file 'select.lst'. Appending to Output File If you want to APPEND, or add to, the end of the output file, you can do so by placing a plus (+) character at the end of the output file name. From the example above, #OUTPUT_FILE 'select.lst+' would place the output of the script at the end of file "select.lst". This feature will be most useful if you are running several scripts in succession and want to place the output from different scripts into one output file. Page 126 TAS "POUND" (#) Commands Suppressing TAS Report Heading In addition, if you want to suppress the headings that TAS normally puts out on its reports, you can do this with the OUTPUT_FILE command by placing the letter "N" after the file name (preceded by a space). MAX_QUOTES Command You can use the #MAX_QUOTES command to limit the number of quotes read into a script. This value must be less than the MAXIMUM QUOTES you specified in the TAS Configuration Menu. If it is less than the TAS Configuration Menu MAXIMUM QUOTES, it will override the quote count to read for the script in which it is contained only. The format of the #MAX_QUOTES command is: #MAX_QUOTES min max where min is the minimum number of quotes that the security file must have. max is the maximum number of quotes to read into TAS when this script is processed. SCAN_DATE Command You can use the #SCAN_DATE command to define the time frame you want to process. You can specify a beginning date, an ending date or both. The SCAN_DATE command enables you to start loading quotes from a specific date (the start date) and to stop loading quotes after a specific date (the end date). The format of the #SCAN_DATE command is: Page 127 #SCAN_DATE start_date end_date or #SCAN_DATE end_date Both start_date and end_date can be in the following format where yy is the year, mm is the month, and dd is the day : yymmdd ,e.g. 910302 for March 2, 1991 'mm/dd/yy' mm/dd/yy Some examples of the use of #SCAN_DATE are: #SCAN_DATE 910102 0 will start loading data on Jan 2, 1991 and load up to the last day in the file. #SCAN_DATE 910102 910915 will start on Jan 2, 1991 and load up to Sept 15, 1991. If there is no quote in the file for the start_date, the first date prior to the start_date will be loaded. If there is no quote in the file for the end_date,the first date prior to the end_date will be used. Either the start_date or the end_date may be zero, in which case, it means to load from the beginning or the end of the file without regard to date, but taking into account the MAX_QUOTES range. PROFIT_TEST Command The #PROFIT_TEST command informs TAS of the type of profit test you want to run, whether you want to test "LONG", "SHORT" or "BOTH" long and short positions, and the amount of "money" you want your position to start with. This command must be placed in the front of the TAS script, prior to any statements which do not begin with a # sign. The format of the #PROFIT_TEST command is: #PROFIT_TEST type money where 'type' is either LONG, SHORT or BOTH (for a "long" position test or a "short" position test, or a test of both Long and Short positions) and "money" is the amount of money with which to start the test for each symbol. Page 128 TAS "POUND" (#) Commands INDEX Command The #INDEX command can be used to load an "index" data array, such as the SP500, DJIA or another stock. It tells TAS to access the ticker symbol contained in the command and place its CLOSING PRICES into a Pre-defined Data Array named "INDEX". The format of the INDEX Command is: #INDEX 'ticker' where 'ticker' is the TICKER SYMBOL of the Index quote file. For example, if you had the SP 500 quotes in a file with a ticker name of "SP500", and you wanted to load it as the INDEX array, you would say #INDEX 'SP500' Later in the script, you could reference the array by the name of INDEX. This command must be placed in the front of the TAS script, prior to any statements which do not begin with a # sign. It also should follow any #MAX_QUOTES statement that is in the script. INCLUDE Command The #INCLUDE command will "include" another file into the current script as if that file were part of the script . Once the included file is read into TAS, the original script is continued. You can include up to 8 levels of includes, that is, the included file can contain a #include and that file can contain one, etc., up to 8 levels. Page 129 The format of the #include command is #INCLUDE filename where filename is the name of a file in the current directory. TITLE Command The #TITLE command is used to provide a "title" to a file. This title is shown when the File/List extended list display is created (see page 27) The #TITLE line should be no longer than 72 characters, and it must be the first line in the file. COMPRESSCommand The #COMPRESS command can be placed in a script to cause compression of the data by weekly, monthly, yearly or some number of data points. The format is #COMPRESS cfactor where cfactor is W, M, Y or some number. Page 130 TAS Script Examples TAS Script Examples Included with the TAS package are several sample .TAS script files. Check your directory after you install TAS to see the samples included. Putting Them Together If the script has the statements: todays_ma = mov(c,21,'E'); diff = CLOSE OF TODAY- todays_ma; if diff IS GREATER THAN 0 then writeln(TICKER, ' IS ABOVE 21 DAY EMA BY ',diff); else writeln(TICKER, ' IS BELOW 21 DAY EMA BY ',diff); The script will print out the ticker name followed by the message indicating whether the latest close is above or below the 21 day EMA, and by how much. In this particular example, let's take a closer look at what is go- ing on. In the first line, todays_ma = mov(c,21,'E'); we are computing the 21 day Exponential Moving Average of the Closing Price Array. Once computed, we are assigning the latest value of this moving average to the "variable" named 'todays_ma'. You could call it anything you want, but giving it a name that reminds you of what it contains is useful. If you wanted to keep the 21-day EMA in its own array. You could declare the variable as follows (before using it the first time): big_ma_array : ARRAY; This tells TAS that "big_ma_array" is an array of values, not just one value. So, if you now said: big_ma_array = mov(c,21,'E'); the contents of big_ma_array would be ALL of the Moving Average values up to the latest day. To refer to the value of the 21 day EMA yesterday, we would write "big_ma_array[-1]" where the "[-1]" refers to the contents of the array "-1" days from now (in other words, one day ago). If you wanted to refer to the 21 day EMA 10 days ago, it Page 131 would be "big_ma_array[-10]". If you wanted to refer to the latest day's 21 day EMA, it would be "big_ma_array[0]" (zero days ago). The next statement in the example is: diff = Close of Today - todays_ma; which assigns to the variable "diff" the value of the latest closing price, "Close of Today", minus the latest 21 day EMA as computed and assigned to the variable "todays_ma" in the previous statement. New High/New Low Example The following script is contained in file "NHNL.TAS". Page 132 TAS Script Examples Script Contents { NHNL.TAS- This script example will show the 52 week high and low for each ticker. If the current day's high is equal to the highest high or the current low is equal to the lowest low, then we have a probable new high or new low. It might also be the case that today's high or low is just equal to the previous high or low. Just to make the script slightly more interesting, we will also compute the "percentage off from high", a frequently used metric seen in financial tables. } Prolog begin writeln( ' - CURRENT - - 52 WEEK - OFF'); writeln( 'TICKER HIGH LOW HIGH LOW HIGH'); end; high_value = HHV(h,52*5); { compute high over 52 weeks } low_value = LLV(L,52*5); { compute low over 52 weeks } off_high_value = ((high_value - c) / high_value) * 100; write(TICKER,' ',h,' ',l,' ',high_value,' ',low_value, '\t',INT(off_high_value),'%'); if (high_value <= h) then { today's high is new high } write(' New High '); if (low_value >= l) then { today's low is new low } write(' New Low '); write('\n'); { end the line with a 'newline'} Script Output - CURRENT - - 52 WEEK - OFF TICKER HIGH LOW HIGH LOW HIGH ABX 21.875 21.375 24.750 15.875 13% AAPL 28.000 26.000 50.375 26.000 47% New Low ARIX 1.062 0.938 5.625 0.875 81% BP% 12.500 11.125 14.500 6.000 17% CMNT 2.312 2.188 3.500 2.063 33% GR 32.125 31.875 57.500 29.500 44% SWZ 12.125 11.750 17.500 10.875 32% LA 11.625 10.375 50.375 9.750 77% MXTR 5.625 5.250 16.500 5.250 66% New Low PCG 22.375 22.000 23.500 18.750 4% TX 61.625 60.125 68.500 49.875 12% UAL 110.000 99.000 286.750 87.250 64% Page 133 TICKER Symbol Processing The following example shows how you could create a special script to notify you when certain stocks had reached prices you had set. This script is in "LIMIT.TAS". Script Contents { limit.tas This is an example of using a TAS script to watch your stocks. It checks the ticker symbol against one of several which you might (and I do) own. If the current close (shown as 'c[0]' is greater than the limit for profit or less than the stop loss, a message is generated. } stop_loss = 0; sell_profit = 0; if ticker = 'aapl' then if c > 47 then sell_profit = 1; else if c < 41 then stop_loss = 1; if ticker = 'gr' then if c > 43 then sell_profit = 1; else if c < 38 then stop_loss = 1; if ticker = 'la' then if c > 27 then sell_profit = 1; else if c < 10 then stop_loss = 1; if stop_loss = 1 then writeln(ticker, ' has reached your STOP LOSS limit. SELL'); if sell_profit = 1 then writeln(ticker, ' has reached your Profit target. SELL'); Page 134 TAS Script Examples Directional Movement Example The following script is contained in file "DM.TAS". Script Contents #output_file 'dm.lst' { DM.TAS Wilder's Directional Movement Trading Example This script will indicate a BUY signal if the +DI(14) crosses above -DI(14) and ADXR > 25 a SELL signal if the -DI(14) crosses above +DI(14) and ADXR > 25 } { declare the +DI (Positive Directional Movement array} pdi_array : array; { declare the -DI (Negative Directional Movement array} mdi_array : array; pdi_array = pdi(14); { calculate +DI} mdi_array = mdi(14); { calculate -DI} adxr_14 = adxr(14); adx_14 = adx(14); dx_14 = dx(14); if first_ticker then writeln('TICKER ADXR DX ADX +DI -DI ACTION'); write(ticker,' ',int(adxr_14), int(dx_14), int(adx_14), int(pdi_array[0]), int(mdi_array[0])); action = ''; if (adxr_14 > 25) then { AVG DX Rate of Change > 25 } begin if (over(pdi_array,mdi_array) = 0) then action = '** BUY SIGNAL'; else if (over(mdi_array,pdi_array) = 0) then action = '** SELL SIGNAL'; end; writeln(action); Page 135 Script Output TICKER ADXR DX ADX +DI -DI ACTION AA 33 28 33 25 14 ALD 22 15 22 30 22 AXP 34 59 34 39 10 T 30 41 30 29 12 BS 26 42 26 32 13 BA 22 8 22 27 23 CHV 17 4 17 27 29 KO 27 49 27 32 11 DD 21 23 21 29 18 Modified "Binary Wave" The file "SELCT.TAS" contains a rather lengthy script which contains the logic for computing a 6 point "binary wave". The first 4 "points" of the wave are those described in the "MetaStock User's Manual" in Chapter 7, section 7.7.2 "Example Binary Waves". The final 2 points of the "binary wave" are included to show how you can extend the original example to compute additional indicators (Chaikin's Oscillator and Commodity Channel Index) which are used to further refine the selection. Since the file is large, it is not included in this documentation, but the file is included in the TAS package. Profit Test Example Using RSI(14) The TAS Script file 'RSIPT.TAS' shows a Profit Test using the 14-day RSI. It serves as a simple example of the kind of profit testing available with TAS. Script Contents (RSIPT.TAS) { RSIPT.TAS Page 136 TAS Script Examples RSI PROFIT TEST SCRIPT EXAMPLE This script will signal a SELL when the RSI(14) crosses under 'rsi_upper' and a BUY when RSI(14) crosses above 'rsi_lower'. } #PROFIT_TEST LONG 1000 { long positions with $1000} #MAX_QUOTES 300 { only read in 300 quotes } #OUTPUT_FILE 'RSIPT.LST' { assign output listing to rsipt.lst} RSI_VALUES : ARRAY; { array containing plotted points } RSI_UPPER = 75; { Upper range of RSI - point to SELL Change this if you want to test different value} RSI_LOWER = 50; { Lower range of RSI - point to BUY Change this if you want to test different value} PLOT BEGIN { This begins the "plot" of the RSI } RSI_VALUES = RSI(14); { COMPUTE THE RSI(14) PLOT } END; BUY WHEN RSI_VALUES[-1] < RSI_LOWER AND RSI_VALUES > RSI_LOWER; SELL WHEN RSI_VALUES[-1] > RSI_UPPER AND RSI_VALUES < RSI_UPPER; Script Output The following report shows the output of the Profit Tester for a single stock. Page 137 Technical Analysis Scanner (TAS 3.64) File Date : 05/08/90 Run Date : Wed May 29 22:28:00 1991 Script Name: RSIPT Ticker Name: T Amdahl (AMH) From 03/20/90 To 05/29/91 Initial Cash $ 1000.00. (Long Positions Only) Share Purchases use All Available Cash with NO Commissions |-----Current Trade-------| |-- Cumulative--| Date Action Shrs Price Points Cash Comm Profit Points Profit -------- ----- ----- -------- ------ ------ ----- ------- ------- ------- 05/09/90 Buy 70 14.250 0.000 2 0 0 0.000 0 05/22/90 Sell 70 15.625 1.375 1096 0 96 1.375 96 06/12/90 Buy 69 15.750 0.000 10 0 0 1.375 96 07/18/90 Sell 69 18.250 2.500 1269 0 172 3.875 269 09/07/90 Buy 97 13.000 0.000 8 0 0 3.875 269 Summary for AMH |--Trades-----| |-Runs-| Percent |---Maximum--| Total % Tot Win Los Stp Win Los Win Los Profit Loss Commn Profit Gain Long 2 2 0 0 2 0 100% 0% 269 0 0 269 27% Short 0 0 0 0 0 0 0% 0% 0 0 0 0 0% Closed 2 2 0 0 2 0 100% 0% 269 0 0 269 27% Open 1 1 0 0 1 0 100% 0% 315 0 0 315 32% Total 3 3 0 0 2 0 100% 0% 315 0 0 584 58% Summary for ALL SYMBOLS |--Trades-----| |-Runs-| Percent |---Maximum--| Total % Tot Win Los Stp Win Los Win Los Profit Loss Commn Profit Gain Page 138 TAS Script Examples Long 2 2 0 0 2 0 100% 0% 269 0 0 269 27% Short 0 0 0 0 0 0 0% 0% 0 0 0 0 0% Closed 2 2 0 0 2 0 100% 0% 269 0 0 269 27% Open 1 1 0 0 1 0 100% 0% 315 0 0 315 32% Total 3 3 0 0 2 0 100% 0% 315 0 0 584 58% Page 139 TAS Error Message TAS has extensive error checking features that attempt to detect and isolate errors as close to the source as possible. The following section is a list of the error messages that can be exhibited by TAS. The Error Message list is in alphabetic sequence, so you can look up the message by the first letter of the first word of the message. Most messages have an error number associated with them as well. This number should be used when communicating the problem to FlexSoft. For each error message, there are three sections, The first section is the actual text of the message including an error number (Ennn) , the second section is the cause of the message, and the third section is the recommendation, or action to resolve the error. At the end of the list of error messages is a list of Diagnostic Actions. These are described in the error message recommendation as Action Dx, where the x is a diagnostic action number. A Diagnostic Action is a sequence of steps necessary to resolve the problem or to gather and provide enough information for resolution by FlexSoft Technical Support. Error Messages E72,'(', number value or variable expected. Cause: In trying to decipher an arithmetic expression, TAS found a sequence where it expected to find either an expression in parentheses, a number or a variable. It found nothing it could make sense of. Recommendation: Examine the line where the error was flagged and correct the mistake. E68,')' expected. Cause: In trying to decipher an arithmetic expression, TAS found a sequence that is missing a right parenthesis. Recommendation: Page 140 TAS Error Message Examine the line where the error was flagged and correct the mistake. A Math Error (code ) has occurred while processing symbol in TAS Script File