[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Hunting for faster EL code



PureBytes Links

Trading Reference Links

{[Was: Re: Message pops up say can't divide by zero.}

Dans un courrier daté du 28/08/98 04:22:10  , vous avez écrit :

<< Robert,
 
 This indicator was written by me about a year ago for an article in
 Futures that discussed the Bollinger bands indicator (Nov. -97). It
 normalizes the price to fluctuate around zero, with the upper
 Bollingerband set to 100 and the lower band to -100, for easier
 interpretation.
 
 Alternative (and much better) code:
 
 {Indicator name: $%B}
 Input: Price(C), Length(18), SDev(2);
 Vars: Upper(0), Lower(0), Where(0);
 Upper = 100 * (Price - $Lowerband(Price, Length, SDev));
 Lower = $Upperband(Price, Length, SDev) - $Lowerband(Price, Length,
 SDev);
 If Lower <> 0 Then
 	Where = ((Upper / Lower) - 50) * 2;
 Plot1(Where, "Where");
 Plot2(100,"Upper");
 Plot3(-100,"Lower");
 
 {Function name: $Lowerband}
 Input: Price(NumericSeries),Length(NumericSimple),SDev(NumericSimple);
 $Lowerband = Average(Price, Length) - StdDev(Price, Length) * SDev
 
 {Function name: $Upperband}
 Input: Price(NumericSeries),Length(NumericSimple),SDev(NumericSimple);
 $Upperband = Average(Price, Length) + StdDev(Price, Length) * SDev
 
 Thomas Stridsman
 Futures magazine 
>>

So, this is interesting.

First, the B% oscillator is a very appealing one that I sometimes use
(filtered) as an input to some AI program that I do not want to   shameless
fuzzy self  promote here.

Thomas Stridsman's B% implementation above is correct, and the -100 +100
rescaling produces a better reading because recentering around 0.
 In this sense, it behaves like Lambert's CCI, rather than Wilder's RSI.

The point that I want to highlight here is the obvious need to learn to
simplify the code, in a general manner, and not only this ne that I take as an
example.
I could have done this one many others posted here, but this one covers
interesting simplification possibilities.


Suppose that you want to use %B in a system and run te TS optimiser, the
fastest code will produce the fastest optimisation.
For sake of clarity , I'll code the indicator above with the original TS
functions:

STEP0:

{Indicator name: $%B}
Input: Price(C), Length(18), SDev(2);
Vars: Upper(0), Lower(0), Where(0);
Upper = 100 * (Price -BollingerBand(Price, Length, -SDev));
Lower =BollingerBand(Price, Length, SDev) -BollingerBand(Price, Length,-SDev);
If Lower <> 0 Then
	Where = ((Upper / Lower) -50) * 2;
Plot1(Where, "Where");
Plot2(100,"Upper");
Plot3(-100,"Lower");
plot4(value0,"BB1");

[
The only difference is that we use the same  TS function for Bollinger bands,
but it do not simplify yet anything.

Inputs: Price(NumericSeries), Length(NumericSimple), SDev(NumericSimple) ;
BollingerBand = Average(Price,Length) + (SDev * StdDev(Price,Length)) ;
]

STEP1:
______
A close examination of $B% shows that we use this BollingerBand  function
three times.
So we call three times the same code that also contains the same sub  EL  user
functions:
-StdDev
-Average.
(Used also three time in the BollingerBand code and a fourth in the  $B% code
for the average).


STEP2 : Simplifying for the StdDev multiple case:
_________________________________________
This is why I had said that understanding  ALL  of the  EL functions is so
important.
BBands are calculated from an average with   STddev added or substracted from
the average (using a coefficient, usually 2).
So, calling a code with several BBands  to produce a single result can be
simplified:
I'll put this directly to an user fuction BB1 that you will be able to call. 
This do not simplify by itself, but the code of the UF is now simplified, and
you will see later why I use an user function (BB1, below).

==================================================
input:price(numericseries), length(numeric), coeff(numeric);
value1=average(price,length); {<========= light bulb must flash here}
value2=stddev(price,length);  {<========= light bulb must flash here}
value3=value1-coeff*value2;
if value2<>0 then begin
 BB1=100*(price-value3)/(coeff*value2)-100;
end;

==================================================
If you call BB1 from an indicator, it will produce the same result than the
$B% original  indicator code.
But it uses only :
One  StdDev instance instead of 3, so it will run faster


STEP3
_______
There is better to do.
Knowing and understandind all the functions is important,and the glaring proof
is below.
We just spare 2 StdDev function in step2.
We could have been to evaluate this improvement by knowing was was  StdDev
doing.
So, let's open the StdDev code:

==================================================
inputs : Price(NumericSeries),Length(NumericSimple);
vars    : SumSqr(0),Avg(0),Counter(0);

if Length <> 0 
then begin
	Avg = Average(Price,Length); {<========= light bulb must flash here}
	SumSqr = 0;
	for counter = 0 to Length - 1 
	begin
		SumSqr = SumSqr + (Price[counter]-Avg) * (Price[counter]-Avg);
	end;
	StdDev = SquareRoot(SumSqr / Length);
end
else 
	StdDev = 0;
==================================================
What could we see here ?
Surprise: we use the same average calculation than in the original code
(already calculated).
We need to modify the User function to make it run faster, by avoiding the
twin average calculation:

First, we will use the StdDev code  directly in the user function, then apply
it to BB1 (becomes BB2)
Then perform some basic maths to get the simplest way to calculate BB2
(below). Et voilà.

==================================================
input:price(numericseries), length(numeric), coeff(numeric);
vars    : SumSqr(0),Avg(0),Counter(0),xstddev(0);

if Length <> 0 
then begin
	Avg = Average(Price,Length);
	SumSqr = 0;
	for counter = 0 to Length - 1 
	begin
		SumSqr = SumSqr + (Price[counter]-Avg) * (Price[counter]-Avg);
	end;
	xStdDev = SquareRoot(SumSqr / Length);
end
else 
	xStdDev = 0;


if XstdDev<>0 then begin
BB2=100*(price-Avg+coeff*xStdDev)/(coeff*xStdDev)-100;
end;
==================================================

BB2 calls now only one average instead of 2 and distracts it  to its profit
from the Stddev code.
This one will run now faster than BB1.


STEP4:Conclusion.
________________

No need to be a genius to understand this.
It's only knowkledge and knowing what we do when coding.
TS is a good program that can  be enhanced, but the user can also enhance it
with some homework.

In fact, I have made unnecessary steps to me.
My first tought would to remove the average from the redundant hidden Stddev
directly because I already knew that this function used the same Average
function than the one used for the center of Bollinger band.
So, I would have directly jumped to step3.
I explained the steps in detail for those who are not familiar with the
concept.

If solving this king of problem is of interest to you, you can subscribe to TS
Express that posts a similar problem to the readers in almost every issue. The
complete collection is a gold mine for people wanting to shorten their EL
code,and an excellent exercise to try to solve the problem posted (you cannot
better learn than  by suffering during  the search phase).

I also propose  a yearly and expensive unlimited  EL support addressing any
kind of question regarding to TradeStation programming.

More details on my (well known as) self promoted web site.

(If someone do not know it, please drop an  E-Mail to:
 http://www.sirtrade.com, and I'll give you back  the URL of my web site).
Link to TS Express is also available there.

Sincerely,

-Pierre Orphelin