No, that really is all there is to it. In fact, on closer inspection I found that this code produces exactly the same results:
[font=Courier New]HH = Highest(H, iPeriods);
if H = HH or Dynamic_R = 0 then Dynamic_R = HH;
LL = Lowest(L, iPeriods);
if L = LL or Dynamic_S = 0 then Dynamic_S = LL;
[/font]
I was curious how this cool indicator works, so I analyzed it rather thoroughly. Here's how I got the code reduced to this:
Code: Select all
I have copied TRO's slick Dynamic_SR indicator here and pulled out just the
code for calculating Dynamic_R:
PrevDynamic_R = Dynamic_R ;
oExtremeVal = Extremes( H, iPeriods, 1, Dynamic_R , oExtremeBar ) ;
If Dynamic_R <> H
and Dynamic_R < PrevDynamic_R
then if PrevDynamic_R <> 0
then Dynamic_R = PrevDynamic_R;
First, simplify by replacing the call to Extremes() with a call to Highest()
PrevDynamic_R = Dynamic_R ;
Dynamic_R = Highest( H, iPeriods); // highest high
If Dynamic_R <> H
and Dynamic_R < PrevDynamic_R
then if PrevDynamic_R <> 0
then Dynamic_R = PrevDynamic_R;
Next, take a look at the compound 'If' statement. Since there are no 'else'
statements, the assignment at the end of the second 'If' only gets carried
out if the condition in the first 'If' AND the condition of the second 'If'
are true. So we can simplify to a single 'If' statement like this:
variables: Dynamic_R(0), PrevDynamic_R(0);
PrevDynamic_R = Dynamic_R ;
Dynamic_R = Highest( H, iPeriods); // highest high
If Dynamic_R <> H
AND Dynamic_R < PrevDynamic_R
AND PrevDynamic_R <> 0 then Dynamic_R = PrevDynamic_R;
Let's think about what's going on here. First the current value of
Dynamic_R is stored in a temporary location called PrevDynamic_R. Then
the highest high is assigned to Dynamic_R. Then a condition is tested,
and if found to be true, Dynamic_R is set back to it's previous value,
PrevDynamic_R. I'm going to substitute variables here and show a simplified
version of this calculation. Substituting PR for PrevDynamic_R,
DR for Dynamic_R, HH for Highest(H, iPeriods):
PR = DR;
DR = HH;
if DR <> H AND DR < PR AND PR <> 0 then DR = PR;
So DR is going to retain its previous value if the 'if' condition is true. This
implies that DR will be set to HH only when the 'if' condition is false:
(DR <> H AND DR < PR AND PR <> 0) = FALSE
So we could write the if statement like this:
if (DR <> H AND DR < PR AND PR <> 0) = FALSE then DR = HH;
But there is a problem. The condition in the 'if' statement used the
modified values of DR and PR from the two assignments right before the
'if' statement. We can fix this by substituting HH for DR and DR for PR
and eliminating those two assignments. So the whole shebang boils down to:
HH = Highest(H, iPeriods);
if (HH <> H AND HH < DR AND DR <> 0) = FALSE then DR = HH;
Rearranging a bit:
HH = Highest(H, iPeriods);
if ((H <> HH) AND (DR > HH) AND (DR <> 0)) = FALSE then DR = HH;
If EasyLanguage had a unary logical inversion operator, also known as a 'not'
operator, we could write this code like this:
HH = Highest(H, iPeriods);
if NOT((H <> HH) AND (DR > HH) AND (DR <> 0)) then DR = HH;
Here's where we pull an old trick out of the computer science hat. We want
to calculate the logical inverse of that condition. I'm going to apply
De Morgan's theorem ( !(A AND B AND C) = !A OR !B OR !C, where ! is
logical inverse or 'NOT') to the 'if' condition to get this new version:
HH = Highest(H, iPeriods);
if (H = HH) OR (DR <= HH) OR (DR = 0) then DR = HH;
Note that I have replaced the ANDs with ORs and logically inverted each of
the three terms. It becomes obvious here that the term 'DR = 0' is only true
the first time the code is run and DR has been initialized to 0. (My deepest
sympathies to you if you have trades that achieve this value otherwise.) Being a
simpleminded fellow I pulled that out and did the initialization separately:
if (DR = 0) then DR = Highest(H, iPeriods);
HH = Highest(H, iPeriods);
if (H = HH) OR (DR <= HH) then DR = HH;
Now I've got this thing down to the level where I can figure out what it does.
I'll rewrite it using the original variables:
if (Dynamic_R = 0) then Dynamic_R = Highest(H, iPeriods);
HH = Highest(H, iPeriods);
if (H = HH) OR (Dynamic_R <= HH) then Dynamic_R = HH;
So Dynamic_R is set to the highest high of the last iPeriods if either
the current high is equal to the highest high OR if the current value of
Dynamic_R is less than or equal to the highest high.
Now let's give this some thought. When does the second part of the 'if'
condition actually do anything? In other words, when can Dynamic_R be less
than the highest high of the last iPeriods? If you think about it, if
Dynamic_R is less than HH, you must be at a new local high, which means
that the 'H = HH' part of the condition is going to be true as well. You
could look at it like this: the 'H = HH' term allows Dynamic_R to drop down
to a new local high after the series has dropped down and started coming back
up. The 'Dynamic_R <= HH' term causes the output to rise with an increasing
input series. But the 'H = HH' term also applies in that case, so the
'Dynamic_R <= HH' term is redundant and can be removed:
if (Dynamic_R = 0) then Dynamic_R = Highest(H, iPeriods);
HH = Highest(H, iPeriods);
if (H = HH) then Dynamic_R = HH;
Thinking about this some more, and being a geek who worries about the tiniest
inefficiencies, it would make sense to place the initialization code back into
the 'if' statement. The 'Dynamic_R = 0' condition has to be evaluated every
time we pass through the code above. If we write the code like this:
HH = Highest(H, iPeriods);
if H = HH or Dynamic_R = 0 then Dynamic_R = HH;
and if the EasyLanguage compiler has a feature known as 'logical subexpression
short-circuit evaluation', it will not perform the '(Dynamic_R = 0)'
comparison if the 'H = HH' part of the expression is true.
So that's how I got this. The argument works the same for Dynamic_S but with
the inequalities reversed.
Of course, I wouldn't trust that code unless I tested it, so that's what I did. I wrote an indicator that calculates Dynamic_R both ways and then plots the values from your method. If the method I show above is different it plots that out in a different color. The .eld is attached.
I've seen indicators like this in the ads in trading magazines for proprietary trading systems. They're used for setting stop loss orders. Analyzing the code has given me more insight into how they work. Your thoughts?
- Jim