The previous example was easy because in step 4, the loop translated
directly into a single indicator. Next we ask: What
if the loop we want to convert does not logically represent
an existing indicator? At first glance it may appear
as though we are out of luck, but that is actually not the case!
To illustrate this, we will now convert the following EasyLanguage
formula containing a loop:
Inputs: MP((H+L)/2);
{The output of CyclePeriod() doesn't matter for this example,
it simply represents a period value that varies from bar-to-bar}
periods = CyclePeriod(MP, .18, .1, 1.1);
temp = 0;
For count = 0 to periods - 1 begin
temp = temp + count * (MP[count]);
End;
output = temp / (periods) * (periods+1) / 2;
Notice the difference here from the last example: the term inside
the loop uses "count" instead of "(periods - count)".
Step 1.) Separate the loop into as many individual loops
as possible, and convert each loop separately.
This loop cannot be separated further.
NOTE: It is often times helpful to include calculations outside
of the loop (for example, the last line in the formula above)
when trying to convert a loop. This last step is usually a division
that calculates an average or something similar. As you saw
in the last example, this can be very important for step 3,
because it results in output that represents a common indicator.
However, there will be other times when it will help to ignore
any extra calculations after the loop. You may find it helpful
to try it both ways.
Step 2.) If the loop uses a "varying" (non-constant)
counter variable, replace it with a constant, preferably a small
number, like 3 or 5 (here we use 4).
Inputs: MP((H+L)/2);
periods = 4;
temp = 0;
For count = 0 to periods - 1 begin
temp = temp + count * (MP[count]);
End;
output = temp / 10;
Step 3.) Create an equivelant function in Metastock for the
static version of the loop (i.e., a loop with a constant counter).
By using algebraic substitution and stepping through the loop,
we can see that this "static version" of the loop in Metastock
can be computed as follows:
output := ( MP() + 2*Ref(MP(),-1) + 3*Ref(MP(),-2)
+ 4*Ref(MP(),-3) ) / (4+3+2+1);
Step 4.) Analyze the logical output of the formula and try
to convert it into existing Metastock indicators.
In the last example, this step was fairly easy, but in most
cases, it is the most difficult step. When the resulting formula
does not represent an "end" indicator, like a WMA,
you must think of clever ways to combine indicators to create
a formula. This is usually best accomplished by trying to use
low-level functions like the Sum() function, and Moving averages,
and sometimes the Ref() function. Ultimately, we
believe that the best way to accomplish this step is by analyzing
this example and others as they will be posted in the future,
as the knowledge base grows.
It may help to notice that this indicator could be described
as a "Inverse" Weighted Moving Average, since the coefficients
for the average (1,2,3,4) go in the reverse direction of a WMA
(4,3,2,1). This may be helpful in determining that the formula
DOES NOT match an existing indicator. By this we mean that neither
Metastock nor ASI has an "Inverse" WMA function. However,
it may or may not be helpful for you to think of the indicator
in these logical terms when trying to create a solution using
existing indicators. Sometimes it may be better to only think
of the algebra and programming at hand, instead of what the
indicators mean. We suggest that you experiment and use whatever
technique comes naturally to you. Also, the steps we take and
the end solution are not unique; there may be other ways of
solving this problem.
For this example, which is one of the more difficult
loop examples we could find, we came up with the following
solution:
The goal in this stage is to use successive equalities
to represent the static loop from step 3 in terms of existing
Metastock Indicators.
We start with this formula we will call A1:
A1 := 5 * ExtFml("ASI.Sum",MP(),4);
Which is equivelant to A2:
A2 := 5*MP() + 5*Ref(MP(),-1) + 5*Ref(MP(),-2)
+ 5*Ref(MP(),-3);
Next, we have formula B1:
B1 := 10 * ExtFml("ASI.WMA",MP(),4);
which is equivelant to B2:
B2 := 10 * ( 4*MP() + 3*Ref(MP(),-1) +
2*Ref(MP(),-2) + Ref(MP(),-3) ) / (4+3+2+1);
Now if we subtract formula B2 from from A2 and divide the result
by 10 (or 4+3+2+1), we get:
output := MP() + 2*Ref(MP(),-1) + 3*Ref(MP(),-2)
+ 4*(MP(),-3) / (4+3+2+1);
Notice that this result is an exact match to the formula
from step 3!
Finally, if you subtract B1 from A1 and divide the result by
10, we get:
output := (5 * ExtFml("ASI.Sum",MP(),4)
- 10 * ExtFml("ASI.WMA",MP(),4)) / 10;
This is the final solution to step 5, since we have expressed
the solution in terms of existing indicators. This allows us
to use adaptive inputs to these indicators (step 6) instead
of the traditonal static ones.
Step 5.) Compare the output from Steps 3 and 4, and make
sure they are equal.
We have shown here that results are logically the same, but
you should always test the formulas in Metastock to assure that
they are equivelant.
Step 6.) Finally, replace the calls to fixed-period Metastock
indicators with calls to the ASI functions, and replace the
fixed length with the original "variable loop counter"
function.
{ periods should match the output of the
CyclePeriod() function in the original EasyLanguage formula}
periods := ExtFml("ADSI.CyclePeriod", MP(), .18, .1, 1.1);
output := (ExtFml("ASI.Sum",MP(),periods) - (periods/2)*ExtFml("ASI.WMA",MP(),periods))
/ (periods/2);
|