OMNIQUANT SRIPT REFERENCE 5. OMNIQUANT SCRIPT IN ACTION –SAMPLE FUNCTIONS Introduction The following examples of script are meant to accelerate the learning curve of a user new to OQS. Follow them consecutively and, even though these fuctions are already written, take the time to re-write them through the macro editor and employ their use yourself. Before long, OQS will become second nature and the power of infinite analytic capability will be at your fingertips. 5.1. SIMPLE FUNCTIONS In this case, a simple function is that in which a simple manipulation of feed variables is done by algebraic means. No historical analysis is required. In addition to range, other functions of this type include percent of range and true range. Range Function The following function is meant to display the range on the day. The calculation for range we will use is relatively simple, (high-low). Since both of these variables are provided by a real-time feed, it is a simple matter for us to employ this calculation in an OQ script. First, define the function #DEF double range() The ‘#DEF’ prefix is common to all OQS functions, it lets OQS know that the following bit of text will be a function definition. The ‘double’ lets OQS know that the function will return a double, which is a floating point number, or, more simply, a number with some numbers after the decimal point (Example 12.34), as opposed to an integer, which refers to a whole number (Example 1234). We know we need the function to return a double, because we will be probably be subtracting two doubles since the highs and lows of a security are rarely whole numbers. After the return designation, the name of the function (with any applicable inputs) is entered. At this point, you are probably asking,”Hey, I need to subtract the low from the high, aren’t those inputs?”. Well, luckily for you, OQS can easily get your feed variables without you having to pass them through the function definition. In fact, any variable in the file, ACVAR.PRG is globally available to OQS, which means OQS can grab it at any time. Generally the function inputs will correspond to certain arguments of a function that a user might like to set, 5 - OmniQuant Script in Action –Sample Functions Page 21 script2.doc 24-Jul-06 OMNIQUANT SRIPT REFERENCE such as the number of time-periods in a moving average. This is, of course, explained in more detail below. Okay, now that we have defined the function, let’s enter some calculations. #DEF double range() return=high-low Voila! We have our range, All there is left to do now is enter ‘range’ as the value function in the column editor, use it as a function in a .DTL page, or just keep it in the back of our mind, knowing now that anytime we need the range, we just type in ‘range’. Perhaps that one was a bit easy for you, now let’s move onto an extension of this function. Percentage of Range Function This function will take range one step further. Namely, we want to know what percentage of today’s range the last traded price was. We know the range includes high and low, in addition, we will also need the last traded price (which is, conveniently, ‘last’), so we can compare it to them. First, function definition: #DEF double prange() Again, the output variable is a double because the percentage of the daily range will most likely be a decimal. Now for the math: #DEF double prange() return=100*((last-low)/(high-low)) The preceding script expresses the distance away from the low as a percentage of the range. Note the use of parentheses. This ensures the correct order of operations for the calculation. TrueRange Function The ‘True Range’ of a security is the greatest of the following three values. • • • High – Low Yesterday’s Close – Low (For this to be greatest, yesterday’s close would have to be greater than today’s high) High – Yesterday’s Close (For this to be greatest, yesterday’s close would have to be less than today’s low) The best way to approach the construction of any new function is step by step. First, we should define the function 5 - OmniQuant Script in Action –Sample Functions Page 22 script2.doc 24-Jul-06 OMNIQUANT SRIPT REFERENCE #DEF double truerange() Easy enough, we know from the last function that we don’t need to enter the feed variables as inputs. This, however, brings up an important question. Which feed variables do we want to use? Well, two of them we’ve seen before, High and Low but will OQS recognize Yesterday’s Close? Sadly, the answer is no. This is where the user will need to have a bit of an awareness as to which variables in ACVAR.PRG correspond to which data. Some of them are obvious, high and low being prime examples. However, some are not. For example, yesterday’s close is tucked away in ACVAR as prev (a mnemonic for previous close). So now we know which variables we need. Let’s put the calculations for the three values we need to compare in the function. #DEF double a=high b=prev c=high truerange() – low – low – prev We’ve made the problem a bit simpler now. Which is biggest? A,b, or c?. For this we will need to use an if-then conditional structure (section 3.5.1 of this manual). After reading through 3.5.1, we now know the correct syntax to use to employ this structure. We will also need to use relational operators < and > which mean less than and greater than respectively (section 3.4.3). Let’s implement. #DEF double truerange() a=high – low b=prev – low c=high – prev if a > b then if a > c then return=a endif else if b>c then return=b else return=c endif end if Can you follow the logic? In English, the code can be read as follows (understanding what a,b and c represent): If a is greater than b and if a is greater than c then the return must equal a. Otherwise (else), since we already know now that b is greater than a, if b is greater than c then b must be the greatest so return b, otherwise b is greater than a and c is greater than b so c must be the greatest, return c. 5 - OmniQuant Script in Action –Sample Functions Page 23 script2.doc 24-Jul-06 OMNIQUANT SRIPT REFERENCE We’ve introduced several new concepts in that last step. In addition to the conitional if-then structure, we’ve also showed how you can ‘nest’ such structures. For example the if-then within an if-then. This serves the same purpose of an and operator, since both must be true to get into the second if-then structure. Also, perhaps you’ve also notice how I’ve indented certain parts of the code. This is purely for aesthetics and readability. It doesn’t matter to the script engine where the code is, as long as it’s in the correct order. However, the new user should get into the habit of indenting and commenting his/her code for the purposes of readability and future modification. There it is, the True Range function. Let’s move onto time-series functions. 5.2. TIME-SERIES FUNCTIONS In this treatment, a time-series function will be that which, in some way utilizes time-series data. OQS has access to cached data of OPEN, HIGH, LOW, CLOSE, and VOLUME. The default setting permits access to the last 500 data points of several time resolutions (1 min, 3 min, 5 min, 10 min, 15 min, 30 min, 1 hour, 1 day, and 1 week). The following samples will introduce not only the use of time-series data, but also techniques involving dimensioned variables. Simple Moving Average A simple moving average is a running average of the last n data points. Every time a new data point of a certain time period is update, the average updates. Moving averages have several uses in determining strength and weakness. Define the function: #DEF double average(no a[50],in b) Notice the return is, as usual, a double. Unusually, the inputs here are different. Notice the dimensioned variable and the integer b. The dimensioned variable is meant to represent the particular time series data intended to be averaged (OPEN, HIGH, LOW, CLOSE, or VOLUME) while the integer b will represent the amount of time periods of the average. That way, the same script can serve several purposes. Now to define the average: #DEF double average(no a[50],in b) For i%=0 to b-1 s=s+a[i%] next return=s/b Notice now the use of the for-next control structure, or loop as well as the definition of the integer I using the % command. As i updates, the user’s dimensioned array sums and then that sum is divided by the time periods to 5 - OmniQuant Script in Action –Sample Functions Page 24 script2.doc 24-Jul-06 OMNIQUANT SRIPT REFERENCE obtain an average. It’s the straightforward architecture of OQS that allows this abbreviated form. Accumulation Distribution The following is an accumulating function that takes advantage of the fact that a dimensioned variable holds its previous values as it updates. The function follows: #DEF accum(no a,no b,no z) dim c[2] if c[1]=0 then c[1]=z endif c=c[1] c=c+b a=c #DEF accdist(no a) a=accum((((CLOSE-LOW)-(HIGH-CLOSE))/(HIGH-LOW)) *VOL,(((CLOSE-LOW)-(HIGH-CLOSE))/(HIGH-LOW))*VOL) As can be seen, the accumulation distribution function has been split up into two separate functions. The first is the function accum, which is an abstract accumulation function. The dimensioned variable c[] in accum stores it’s previous value, which is the sum of b to that point. This essentially works as a for next loop since this function will be called for every available data point in history (the omniQuant default setting is 500). The accdist function then calls accum from within. The first mathematical expression before the comma is the b argument, the second is the z argument which, from closer examination of the accum function, is the initialization value. It should also be noted that these functions are defined differently than those above. That is because they use distinct function definition syntax unique to omniQuant. It makes no functional difference, however, as the other methods would be just as valid. 5 - OmniQuant Script in Action –Sample Functions Page 25 script2.doc 24-Jul-06
© Copyright 2024