5. O Q S

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