PureBytes Links
Trading Reference Links
|
Stefan,
Thank you ofr your valuable post.
Just one note: there are also other functions
that allow recursive-type calculations.
Cum() is excellent example and it makes OBV re-implementation
much easier:
addvol = IIF( Close > Ref( Close, -1 ), Volume,
IIF( Close < Ref( Close, -1 ), -Volume, 0 ) );
/* cumulative sum is simple */
obvreplacement = CUM( addvol );
Also other functions use indirectly previous value.
For example your
foo_today = Max(foo_yesterday,anothervalue).
in AFL is called: Highest( array ), HighestSince( condition, array )
Anyway nice article.
Best regards,
Tomasz Janeczko
amibroker.com
----- Original Message -----
From: <elstephel@xxxx>
To: <amibroker@xxxxxxxxxxxxxxx>
Sent: Wednesday, October 02, 2002 12:41 AM
Subject: [amibroker] a JScript replacing Metastocks PREV
> Hello,
>
> Some newbies in this group (like me) have problems accessing past
> data. Normally one would use the Ref() function of AFL, but this
> doesn't work from within a definition like follows:
>
> foo_today = func(foo_yesterday, anothervalue1, anothervalue2,...)
>
> The workaround offered in these cases is the usage of the AMA2
> function of AFL, since there is no PREV function like in
> Metastock. Unfortunately the AMA2 function is not sufficient in
> some cases, but - thanks to JScript and VBScript in AB - there is
> an other way. In this text I want to decribe, how referencing past
> data from within a functions definition can be done by using
> JScript. I will explain it using two examples, a on balance volume
> and a ATR based trailing stop.
>
> Assumed you know the definiton of the OBV: How would you code it in
> AFL? Simply writing OBV()? Right, but we cannot learn anything
> from that, so let's get on to the next possibility using the AMA2
> function:
>
> OBV = AMA2(Volume,IIf(Close>Ref(Close,-1),1,IIf(Close<Ref(Close,-
> 1),-1,0)),1);
>
> This function works as follows: The Volume is firstly multiplied
> with an factor (+1,-1 or 0) depending on the close price change.
> The result is added to the yesterdays OBV value (which is
> multiplied before with the "1" on the far right). But this
> yesterdays OBV value is not "known" anyhow to the AMA2 function, it
> is again calculated by evaluating the first two arguments of the
> AMA2 function but therfore the OBV of the preceding day is needed.
> So this calculated as well and so on.... This way the AMA2
> function recalculates the OBV from the last bar back to the first.
> (For an in depth explaination of the AMA2 function please refer to
> the AB help files.)
>
> Ok, this construction works, but honestly, this looks a bit
> strange, because the On Balance Volume has nothing to do with an
> "Adapting Moving Avarage". Well, its a workaround like so many in
> AB. It's not easy to see for a newbie.
>
> Here comes, how this calculation can be done using JScript: In
> JScript it is possible calculate the OBV values using a "for" loop
> from the first to the last bar. This is the opposite direction of
> how it's calculated by the AMA2 function. This difference is not
> importend in this OBV example but can be very crucial (see 2nd
> example). Please read the comments in the following code:
>
> //ON BALANCE VOLUME with JScript
>
> EnableScript("jscript");
>
> <%
>
> //Close and Volume are required to calculate the OBV
> //transfer Volume and Close from AFL into JScript
> Vol = VBArray(AFL("Volume")).toArray();
> Clo = VBArray(AFL("Close")).toArray();
>
> //create an empty OBV-Array and initiate the first value
> jsOBV = new Array();
> jsOBV[0]=Vol[0];
>
> //calculating OBV-Data in a loop
> for(i=1;i<Clo.length;i++){
>
> if(Clo[i]>Clo[i-1]){
> jsOBV[i]=jsOBV[i-1]+Vol[i];}//adding Volume to yesterdays OBV
> else{
> if(Clo[i]<Clo[i-1]){
> jsOBV[i]=jsOBV[i-1]-Vol[i];}//substracting Volume from
> yesterdays OBV
> else{
> jsOBV[i]=jsOBV[i-1];}//OBV not changed
> }
> }
>
> //transfer jsOBV back to AFL
> AFL("myOBV")= jsOBV;
> %>
>
> Plot(myOBV,"myOBV",colorRed,styleDots+styleNoLine);
> Plot(OBV(),"OBV",colorBlue,styleLine);
>
> Attached you find a picture of this AFL code. the blue line is the
> plot of the AFL-OBV() function, the red dots were calculated using
> JScript.
>
> Yes, you are right: the code is very long and it makes no sense
> creating the OBV that way. This was only to show you the general
> principle of coding recursive functions: (1) Create an (empty)
> array, (2) [optional] initiate the first value and (3) run a loop
> to calculate the remaining values of the array. The point is, that
> this methology is more powerful than using the AMA2 function
> because the calculation is done from the first to the last bar.
> This direction makes it possible that a value is calculated based
> on the REAL preceding value (not so in AMA2).
>
> AMA2 can (and should) be used for "ordinary" calculations like +-
> */. But try to use it in the following formula:
>
> foo_today = Max(foo_yesterday,anothervalue).
>
> I was not successful but that was part of my attempt to create ATR
> based trailing stops. I wanted them to be calculated as follows.
> Initially the distance from the close price to the stop should be
> say 3*ATR(9): Close+3*ATR(9) for the short stop and Close-3*ATR(9)
> for the long stop. The short stop will only be shifted towards
> lower prices, except it gets broken by the close price. Vice versa,
> the long stop will only be increased, except it gets broken by the
> close.
>
> I think it is impossble to code that in "pure" AFL. (I'd be curious
> to see the opposite proven. Anyone?) The reason, I think, is that
> there are two comparing conditions to be included in the AMA2
> function: was the stop of yesterday broken? and is the todays stop
> higher/lower than yesterdays? So my approach was using JScript.
> Please read the comments in the following code:
>
> //ATR BASED STOPS with JScript
>
> EnableScript("jscript");
>
> //first the raw stop functions are defined
> //based on ATR-depending distance to the close price
> multiplier = 3;
> Len = 5;
> range = multiplier*ATR(Len);
> rawlongstop=C-range; //raw long stop
> rawshortstop=C+range; //raw short stop
>
> //two JScript functions for the stops are defined
> <%
> //function for the longstop
> function f_longstop(rawstop,baseprice,Length){
>
> //"importing" the AFL functions into JScript
> Len = AFL(Length);
> Ls=VBArray(AFL(rawstop)).toArray();
> bp = VBArray(AFL(baseprice)).toArray();
>
> //the stop is calculated in the loop
> for(i=Len+1;i<Ls.length;i++){
> if(bp[i]>=Ls[i-1]){Ls[i]=Math.max(Ls[i],Ls[i-1]);}
> }
>
> return Ls;
> }
>
> //function for the shortstop
> function f_shortstop(rawstop,baseprice,Length){
> //"importing" the AFL functions into JScript
> Len = AFL(Length);
> Ss=VBArray(AFL(rawstop)).toArray();
> bp = VBArray(AFL(baseprice)).toArray();
>
> //the stop is calculated in the loop
> for(i=Len+1;i<Ss.length;i++){
> if(bp[i]<=Ss[i-1]){Ss[i]=Math.min(Ss[i],Ss[i-1]);}
> }
>
> return Ss;
> }
> %>//End of JScript
>
> //call the JScript functions to create the AFL stop arrays
> script = GetScriptObject();
> longstop = script.f_longstop("rawlongstop","Close","Len");
> shortstop = script.f_shortstop("rawshortstop","Close","Len");
> //End of stop calculations
>
> //A simple trading system is included
> //to color the price plot. Since it is a trend following system,
> //it will cause losses in non trending markets.
> //Please don't apply.
> Buy=C>Ref(shortstop,-1);
> Sell= C<Ref(longstop,-1);
>
> Buy=ExRem(Buy,Sell);
> Sell=ExRem(Sell,Buy);
>
> Short=Sell;
> Cover=Buy;
>
> poslong=Flip(Buy,Sell);//position is long
> posshort=Flip(Short,Cover);//position is short
>
> Plot(shortstop,"ShortStop",colorLightOrange,styleDots+styleNoLine);
> Plot(longstop,"LongStop",colorBlue,styleDots+styleNoLine);
> Plot(C,"Close",IIf(poslong,colorGreen,IIf
> (posshort,colorRed,colorBlack)),styleBar);
>
>
> Attached you find a image of that code applied. The price bars were
> colored green and red indicating the long or short market
> position. The orange dots represent the short stop, wich is only
> applied if the price bars are red. Vice versa the blue dots
> represent the long stop that gets only applied in the long position
> (green).
>
> Again, the two JSCript functions follow the above mentioned basic
> principle: first the arrays were defined (Ls=... and Ss=...). The
> Initiation was already done by the preciding AFL code
> (rawlongstop=... and rawshortstop=...), so there was no need to do
> it again in the JScript section, and second the loops were run to
> create the remaining data.
>
> Finally pretty easy. In addition, I was really surprised by the
> execution speed. I expected it to be a bit slower because of the
> JScript sections in the code, but it was not. Just a mouse click
> and it is there even with long histories (^DJI back to 1930).
>
> I hope that I could show you an other way to prgramm recursive
> formulas in AB. Give the scripting languages a try, they make AB
> very powerful.
>
> Best regards,
>
> Stephan
>
>
> Post AmiQuote-related messages ONLY to: amiquote@xxxxxxxxxxxxxxx
> (Web page: http://groups.yahoo.com/group/amiquote/messages/)
>
> Check group FAQ at: http://groups.yahoo.com/group/amibroker/files/groupfaq.html
>
> Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
>
>
|