Convert Metastock indicator to AFL

I am using the following Metastock indicator to plot a Swing Chart:

If( HIGH > Ref(HIGH,-1) AND LOW > Ref(LOW,-1), HIGH, If( HIGH < Ref(HIGH,-1) AND LOW < Ref(LOW,-1), LOW, PREV))

I would like to convert this indicator to AFL.

Once this is done, we need to use create buy and sell triggers above / below earlier swing high / low.

@mmshah you need to learn how to use the Immediate IF function. Look through all the examples on this forum and in the User Library listed in the User Guide.

https://www.amibroker.com/guide/afl/iif.html

Make a few attempts and if you get stuck show the forum your attempts and where you are having a problem.

@mmshah
Self-referencing

This has been covered in my post: Doubt when using self referencing

The code presented in original post in this thread is typical example when people don't understand how to write proper vector code. Metastock PREV is classical example of wrong idea being used in even worse way. MS PREV is evil. It causes entire formula to be wrapped in implicit loop causing re-execution that many times as there are bars in the data This makes it run N-times slower where N is number of bars. Even with small 65000 bar limit that MS has it makes it really slow.
That is why AmiBroker does not have PREV. Instead AmiBroker gives you the opportunity to use proper, explicit loops and avoid unncessary re-execution of part that don't need to be re-executed. With explicit loop you just put things that are really necessary.

BUT.... in this particular case, you don't need any loops and you don't need PREV in MS.

What MS formula tried to do is to return High if current high and low are greater than yesterdays' one and low if current high and low are lower and Otherwise keep previous value.

The keyword is "keeping previous value". Any code that is doing that can be implemented using ValueWhen().

Once you think it over even in Metastock you do NOT need to use PREV to implement such thing. And the formula presented is classic example of wrong brute force inefficient coding.

One should approach it more elegantly using ValueWhen which is much faster in both Metastock and AmiBroker:

H1 = Ref( H, -1 );
L1 = Ref( L, -1 );

Up = H > H1 AND L > L1;
Down = H < H1 AND L < L1;

// give High on "up" bars, Low on "down" bars, keep previous value otherwise
result = ValueWhen( Up OR Down, IIF( Up, High, Low ) );

This formula gives same result but it runs at least 100x faster than PREV based.

Note also that for clarity I used temporary variables and meaningful variable names so formula is self-explanatory.

11 Likes

Thanks Tomasz. I added the Plot function and the afl is working fine.

I will try and add Buy and Sell functions and this should work well for buying and selling above / below the earlier swing.

Tomasz....In case of an Outside Bar, the swing chart plot which you gave does not work.

When we have an Outside bar, and if the earlier plot is at the High of the earlier bar, than the high of the Outside Bar needs to be taken into account and value of the high of the Outside bar used for the Outside Bar.

Likewise, if earlier to the Outside Bar, we have a plot of Low, than the Low of the Outside Bar needs to be shown in the current bar (Outside Bar).

Tomasz, thank you for your above post and other similar ones. They are really invaluable for amateur coders (like me) who always strive to improve their coding skills. Such posts should be also closely studied by professional coders who (comparing to you) in many cases shouldn't be even called professionals. It's a shame that many of them create poorly designed, bloated software and as a result - in extreme cases we (users) are adviced to buy powerful machines just to be able to open simultaneously a few charts with streaming data...

Those posts should be gathered in a special place and such collection might serve as the appendix to the manual. I also strongly encourage you to consider taking some measures to publish them officially (after editing and supplementing with selected articles from AB Knowledge Base) under the working title: The Compendium of Efficient Coding :wink: That might be (apart from AmiBroker itself) your another legacy left for the coding and investing community all around the world, serving as a source of inspiration by showing the right path.

At the same time I'm aware of the fact, that (at least for now) you might not want to disclose too much proprietary information, because it is your competitive advantage and you are not interested in making your (lazy and less knowledgable competition) life easier :slight_smile:

Regards

5 Likes

I have made some changes to the AFL. Need some more help. How do I scan for breakouts above the earlier swing high or swing low? Here are the changes that I have made:

_SECTION_BEGIN("Price Chart");
bgTop = ParamColor("BgTop", colorBlack);
bgBot = ParamColor("BgBottom", colorBlack);
SetChartBkGradientFill( bgTop ,bgBot, colorBlack);

pStyle = ParamList("Price Style", "Candle|Solid Candle|Bar|Line|Heikin-Ashi",2);
cBull = ParamColor("Price Bull", colorBrightGreen);
CBear = ParamColor("Price Bear", colorRed);
cLine = ParamColor("Price Line", colorLavender);

Plot (EMA(Close,200), "", colorBrightGreen,styleNoLabel |styleThick |styleDashed);


_SECTION_BEGIN("Magnified Market Price");
FS=Param("Font Size",30,30,100,1);
GfxSelectFont("Arial", FS, 900, italic = False, underline = False, True );
GfxSetBkMode( colorOrange );
GfxSetTextColor( ParamColor("Color",colorYellow) );
//Hor=Param("Horizontal Position",800,800,800,800);

Hor=Param("Horizontal Position",20,20,500,20);
Ver=Param("Vertical Position",50,50,250,50);
GfxTextOut(""+C,Hor , Ver );
YC=TimeFrameGetPrice("C",inDaily,-1);
DD=Prec(C-YC,2);
xx=Prec((DD/YC)*100,2);
GfxSelectFont("Arial", 12, 700, italic = False, underline = False, True );
GfxSetBkMode( colorWhite );
GfxSetTextColor(ParamColor("Color",colorYellow) );
GfxTextOut(""+DD+" ("+xx+"%)", Hor+5, Ver+45 );
_SECTION_END();



SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}}- {{INTERVAL}} {{DATE}} O= %g, H= %g, L= %g, C= %g (%.1f%%) V= " +WriteVal( V, 1.0 ) +"\n{{VALUES}}", O, H, L, C,

SelectedValue( ROC( C, 1 )) ));

ThisStyle = styleCandle;
ThisTitle = "";

_O=O; _C=C; _H=H; _L=L;

ThisColor = IIf( _C>_O, cBull, IIf(_C<_O, CBear, CLine));


switch (pStyle )
{

case "Solid Candle":
SetBarFillColor( ThisColor );
break;


case "Bar":
ThisStyle = styleBar;
break;

case "Line":
ThisStyle = styleLine;
ThisColor = cLine;
break;


case "Heikin-Ashi":
_C = (O+H+L+C)/4;
_O = AMA( Ref( _C, -1 ), 0.5 );
_H = Max( H, Max( _C, _O ) );
_L = Min( L, Min( _C, _O ) );

ThisColor = IIf(_C >= _O,CBull, CBear);
SetBarFillColor( ThisColor );

ThisColor = IIf(_C >= _O,cLine, cLine);
ThisTitle = "Heikin-Ashi";
break;

default:
SetBarFillColor( ThisColor );
ThisColor = cLine;

break;

}

PlotOHLC( _O, _H, _L, _C, ThisTitle, ThisColor, ThisStyle);
GraphXSpace = 8;

_SECTION_END();

_SECTION_BEGIN("Swing Chart");
H1 = Ref( H, -1 );
H2 = Ref( H, -2);
H3 = Ref( H, -3);
L1 = Ref( L, -1 );
L2 = Ref( L, -2 );
L3 = Ref( L, -3 );

Up = H > H1 AND L > L1 OR ( H1 > H2 AND L1 > L2 AND (H > H1 AND L < L1)) OR ( H2 > H3 AND L2 > L3 AND (H1 > H2 AND L1 < L2));
Down = H < H1 AND L < L1 OR ( L1 < L2 AND H1 < H2 AND (L < L1 AND H > H1)) OR ( L2 < L3 AND H2 < H3 AND (L1 < L2 AND H1 > H2));

// give High on "up" bars, Low on "down" bars, keep previous value otherwise
result = ValueWhen( Up OR Down, IIf( Up, High, Low ) );

Plot(result, "swing",colorWhite,styleLine |styleThick);
_SECTION_END();