Australian (ASX) Stock Market Forum

Amibroker FAQ

I'm not sure if this is possible in Amibroker- maybe someone has already done it - but I have this idea for a trailing stop that protects profits and also reacts to market filter (like the WTT filter). For example say you enter a trade, the stop loss is by default 40%. If the index closes below the MA it tightens up to 15%. But when your trade hits a certain profit level, like 25%, the stop loss tightens right up or resets, and will exit the trade if price declines by 5% from any high. Does anyone have a code that can do this or similar? I just can't for the life of me understand looping for anything more than the most basic applications.
 
@wasp I like your idea and I have come up with the following that can be tested more thoroughly by yourself or others.

It is based on the 2 stage trail stop that I have posted up previously so now we have a 3 stage trail stop

I have used wide settings just to make it easy to see the change over and these can be changed on lines 51 - 53 in the code

Initial Stop Level = 50% - Yellow​
Index Stop Level = 30% - Red​
Profit Level Reached (25% - Line 36) = 15% - Aqua​

These levels / colours can be viewed in the weekly chart below

1603537625984.png

Hopefully you can do a bit more testing to verify the logic but looks OK to me so far.

Code:
SetForeign("$xao.au"); // Replaces current stock code with XAO

IndexFilter = Close > MA(Close,10);  // Basic moving average test
//Plot( Close, "$XAO", colorGrey40, styleLine | styleLeftAxisScale ); // Plot XAO close price
//Plot( MA(Close,10), "$XAO MA", colorPink, styleLine | styleLeftAxisScale ); // Plot XAO Moving Average
IndexFilterHealthy = IIf( IndexFilter == 1 , colorGreen, Null );
    Plot( 1, "Index Healthy", IndexFilterHealthy, styleOwnScale| styleArea| styleNoLabel,-.5, 100);

RestorePriceArrays();

maxpos = 10; // maximum number of open positions
SetOption("InitialEquity", 100000 ); // set initial equity = 100K
SetOption( "MaxOpenPositions", maxpos );
SetPositionSize( 100 / maxpos, spsPercentOfEquity );
ATH = Prec (IIf( H > Ref(Highest(H),-1), H , Ref(Highest(H),-1)), 2); // Returns ATH Value for chart

// Standard buy / sell system

period = 20; // number of averaging periods
m = EMA( Close, period ); // exponential moving average

Buy = Sell = 0;
Short = Cover = 0;

Buy = Cross( Close, m ); // buy when close crosses ABOVE moving average

// Profit Level

ProfitStopLevel = 0;
ProfitStopSell = 0;

for( i = 0; i < BarCount; i++ )
{
    if( ProfitStopLevel == 0 AND Buy[i] )
    {
        ProfitStopLevel = BuyPrice[i] * 1.25 ;
    }
    else Buy[i] = 0;

    if( ProfitStopLevel > 0 AND Close[ i ] > ProfitStopLevel)
   {
      ProfitStopSell[ i ] = 1;
   
    }
}



// Trailing Stop loop

TrailStopPercent =  1 - 50/100; // Normal Trail Stop set @ 50 % nice and loose
IndexStopPercent =  1 - 30/100;  // Index Trail Stop set @ 30 % now tighter due to index filter mood change
ProfitStopPercent = 1 - 15/100; // Profit Trail Stop set @ 15 % profit level reached and stop tightens

StopLevel = IIf( ProfitStopSell, ProfitStopPercent, IIf(IndexFilter == 0, IndexStopPercent, TrailStopPercent)); // Selects which value to use in trailing stop

trailARRAY = Null;
trailstop = 0;
TrailStopSell = 0;

for( i = 1; i < BarCount; i++ )
{
   if( trailstop == 0 AND Buy[ i ] )
   {
      trailstop = High[ i ] * StopLevel [ i ] ;
   }
   else Buy[ i ] = 0;

   if( trailstop > 0 AND Close[ i ] < trailstop)
   {
      TrailStopSell[ i ] = 1;
      SellPrice[ i ] = trailstop;
      trailstop = 0;
    }
       
   if( trailstop > 0 AND TrailStopSell [i] == 0)
   {  
      trailstop = Max( High[ i ] * StopLevel [ i ], trailstop );
      trailARRAY[ i ] = trailstop;
   }
}

Sell = TrailStopSell OR Cross( m, Close ); // sell when closes crosses BELOW moving average

Buy = ExRem(Buy,Sell);
Sell = ExRem(Sell,Buy);


// plots price chart and trail stop
SetChartBkColor (colorBlack); // color of outer border
SetChartBkGradientFill(colorBlack, colorBlack);
SetChartOptions( 1, chartShowDates, chartGridMiddle, 0, 0, 0 );
_N(Title = StrFormat("{{NAME}}" + " - {{FULLNAME}} " + " - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%), ATH %g, Vol " +
   WriteVal( V, 1.0 ), O, H, L, C, ( ROC( C, 1 )), ATH));
Plot( C, "Price", colorDefault, styleBar );
//Plot( m, "MA 20", colorAqua, styleLine );

InTrade = Flip(Buy,Sell); // used to turn off trail stop plot
Plot( IIf(InTrade, trailARRAY, Null),"trailing stop level", IIf( ProfitStopSell, colorAqua, IIf(IndexFilter == 0, colorRed, colorYellow )), styleLine, Null, Null, 0, -1, 1);



// Plots buy and sell signals

PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorGreen, 0, L, Offset=-40);
PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorLime, 0,L, Offset=-50);
PlotShapes(IIf(Buy, shapeupArrow, shapeNone),colorWhite, 0,L, Offset=-45);

PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorRed, 0, L, Offset=-60);
PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorOrange, 0,L, Offset=-70);
PlotShapes(IIf(Sell, shapeUpArrow, shapeNone),colorWhite, 0,L, Offset=-65);

SetSortColumns( 10 );
Filter = Buy OR Sell;
signalcolor = IIf(Buy,colorGreen,IIf(Sell,colorred,colorGrey40));
AddColumn( IIf( Buy, 'B', 'S' ), "Signal", formatChar, colorWhite, signalcolor);
AddColumn(Close,"Close",1.2); // current bar close
AddColumn(High,"High",1.2); // Current bar high
AddColumn(trailARRAY,"TS Value",1.2); // Based on % of High ( high select )
AddColumn(100*(1-StopLevel),"Stop %",1.2); // displays which % value we are using depending on index filter
AddColumn(IndexFilter, "Index Filter Active",1,
    IIf( IndexFilter, colorGreen, colorRed),
    IIf( IndexFilter, colorGreen, colorRed), 80);
 
@wasp I like your idea and I have come up with the following that can be tested more thoroughly by yourself or others.

It is based on the 2 stage trail stop that I have posted up previously so now we have a 3 stage trail stop

I have used wide settings just to make it easy to see the change over and these can be changed on lines 51 - 53 in the code

Initial Stop Level = 50% - Yellow​
Index Stop Level = 30% - Red​
Profit Level Reached (25% - Line 36) = 15% - Aqua​

These levels / colours can be viewed in the weekly chart below

View attachment 113650

Hopefully you can do a bit more testing to verify the logic but looks OK to me so far.

Code:
SetForeign("$xao.au"); // Replaces current stock code with XAO

IndexFilter = Close > MA(Close,10);  // Basic moving average test
//Plot( Close, "$XAO", colorGrey40, styleLine | styleLeftAxisScale ); // Plot XAO close price
//Plot( MA(Close,10), "$XAO MA", colorPink, styleLine | styleLeftAxisScale ); // Plot XAO Moving Average
IndexFilterHealthy = IIf( IndexFilter == 1 , colorGreen, Null );
    Plot( 1, "Index Healthy", IndexFilterHealthy, styleOwnScale| styleArea| styleNoLabel,-.5, 100);

RestorePriceArrays();

maxpos = 10; // maximum number of open positions
SetOption("InitialEquity", 100000 ); // set initial equity = 100K
SetOption( "MaxOpenPositions", maxpos );
SetPositionSize( 100 / maxpos, spsPercentOfEquity );
ATH = Prec (IIf( H > Ref(Highest(H),-1), H , Ref(Highest(H),-1)), 2); // Returns ATH Value for chart

// Standard buy / sell system

period = 20; // number of averaging periods
m = EMA( Close, period ); // exponential moving average

Buy = Sell = 0;
Short = Cover = 0;

Buy = Cross( Close, m ); // buy when close crosses ABOVE moving average

// Profit Level

ProfitStopLevel = 0;
ProfitStopSell = 0;

for( i = 0; i < BarCount; i++ )
{
    if( ProfitStopLevel == 0 AND Buy[i] )
    {
        ProfitStopLevel = BuyPrice[i] * 1.25 ;
    }
    else Buy[i] = 0;

    if( ProfitStopLevel > 0 AND Close[ i ] > ProfitStopLevel)
   {
      ProfitStopSell[ i ] = 1;
  
    }
}



// Trailing Stop loop

TrailStopPercent =  1 - 50/100; // Normal Trail Stop set @ 50 % nice and loose
IndexStopPercent =  1 - 30/100;  // Index Trail Stop set @ 30 % now tighter due to index filter mood change
ProfitStopPercent = 1 - 15/100; // Profit Trail Stop set @ 15 % profit level reached and stop tightens

StopLevel = IIf( ProfitStopSell, ProfitStopPercent, IIf(IndexFilter == 0, IndexStopPercent, TrailStopPercent)); // Selects which value to use in trailing stop

trailARRAY = Null;
trailstop = 0;
TrailStopSell = 0;

for( i = 1; i < BarCount; i++ )
{
   if( trailstop == 0 AND Buy[ i ] )
   {
      trailstop = High[ i ] * StopLevel [ i ] ;
   }
   else Buy[ i ] = 0;

   if( trailstop > 0 AND Close[ i ] < trailstop)
   {
      TrailStopSell[ i ] = 1;
      SellPrice[ i ] = trailstop;
      trailstop = 0;
    }
      
   if( trailstop > 0 AND TrailStopSell [i] == 0)
   { 
      trailstop = Max( High[ i ] * StopLevel [ i ], trailstop );
      trailARRAY[ i ] = trailstop;
   }
}

Sell = TrailStopSell OR Cross( m, Close ); // sell when closes crosses BELOW moving average

Buy = ExRem(Buy,Sell);
Sell = ExRem(Sell,Buy);


// plots price chart and trail stop
SetChartBkColor (colorBlack); // color of outer border
SetChartBkGradientFill(colorBlack, colorBlack);
SetChartOptions( 1, chartShowDates, chartGridMiddle, 0, 0, 0 );
_N(Title = StrFormat("{{NAME}}" + " - {{FULLNAME}} " + " - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%), ATH %g, Vol " +
   WriteVal( V, 1.0 ), O, H, L, C, ( ROC( C, 1 )), ATH));
Plot( C, "Price", colorDefault, styleBar );
//Plot( m, "MA 20", colorAqua, styleLine );

InTrade = Flip(Buy,Sell); // used to turn off trail stop plot
Plot( IIf(InTrade, trailARRAY, Null),"trailing stop level", IIf( ProfitStopSell, colorAqua, IIf(IndexFilter == 0, colorRed, colorYellow )), styleLine, Null, Null, 0, -1, 1);



// Plots buy and sell signals

PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorGreen, 0, L, Offset=-40);
PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorLime, 0,L, Offset=-50);
PlotShapes(IIf(Buy, shapeupArrow, shapeNone),colorWhite, 0,L, Offset=-45);

PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorRed, 0, L, Offset=-60);
PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorOrange, 0,L, Offset=-70);
PlotShapes(IIf(Sell, shapeUpArrow, shapeNone),colorWhite, 0,L, Offset=-65);

SetSortColumns( 10 );
Filter = Buy OR Sell;
signalcolor = IIf(Buy,colorGreen,IIf(Sell,colorred,colorGrey40));
AddColumn( IIf( Buy, 'B', 'S' ), "Signal", formatChar, colorWhite, signalcolor);
AddColumn(Close,"Close",1.2); // current bar close
AddColumn(High,"High",1.2); // Current bar high
AddColumn(trailARRAY,"TS Value",1.2); // Based on % of High ( high select )
AddColumn(100*(1-StopLevel),"Stop %",1.2); // displays which % value we are using depending on index filter
AddColumn(IndexFilter, "Index Filter Active",1,
    IIf( IndexFilter, colorGreen, colorRed),
    IIf( IndexFilter, colorGreen, colorRed), 80);
I can't wait to try this out. @Trav. thank you so much for the time and effort you've put into this
 
OK I'm back home from work and thought that I would have a play with the above to see if it made any difference to my CAM Weekly strategy (fixed position size), which has the 2 stage trail stop.

Process followed

1. Record existing system parameters - % Winners, Profit $, CAR etc
2. Include the Profit stop into system to create a 3rd trail stop level and optimize parameters **
3. Optimize all stops together ( 3 in total ) plus the profit level

Step 1

Backtest report saved

Step 2

** After incorporating the profit code into my CAM Weekly I found that there was an issue with the code above and I had to delete one line.​
line # 38 - else Buy = 0;

Once I did that I optimized the Profit Level and the ProfitStopPercent​
Profit Level was 1.25 or 25%​
ProfitStopPercent was 15%​
Best Optimized Values for my system but overall the modification had no benefit.​
Profit Level was 1.11 or 11%​
ProfitStopPercent was 3.5%​

Step 3

Best Optimized Values for my system but overall the modification had no benefit.​

Profit Level was 1.11 or 11%​
ProfitStopPercent was 3.5%​
Trail Stop 1 - 21​
Trail Stop 2 - 15​

Summary

So in this case there was no edge which did surprise me. Maybe this idea would be better for a daily system, which is a bit more responsive? something else to test ( it never stops ) also this system just uses a percent profit and obviously you could use a risk based approach as well.

I would be interested to see if anyone else has similar results or did this approach make a difference to your system.

* note that I only have the Norgate Gold package
 
Maybe this idea would be better for a daily system
OK, so I couldn't resist and incorporated the profit stop code into my CAM Daily system and it did make a difference, although marginal.

So the original stops were

TrailingStop1 = 22%
TrailingStop2 = 10%

and the after settings

TrailingStop1 = 25%
TrailingStop2 = 19%
Profit Level = 10%
ProfitStopPercent = 8.5%

Gains in system over 5 years

Net Profit = +8%
Winners = +0.27%
Max DD = +2.5%
CAR/MDD = +0.3

and a smoother equity curve,

Left - Profit Stop / Right Original

1604141738432.png

1604141576481.png

So as I said some minor gains and in my opinion worth keeping.

The above is just an example so please DYOR.
 
updated loop code for the above (Line 27)

Code:
// Profit Level

ProfitStopLevel = 0;
ProfitStopSell = 0;
ProfitLevel = 1.2;

for( i = 1; i < BarCount; i++)
{
    if( ProfitStopLevel == 0 AND Buy[i-1] )
    ProfitStopLevel = BuyPrice[i] * ProfitLevel;
    
    if( ProfitStopLevel > 0 AND Close[i] < ProfitStopLevel)
   {
      ProfitStopSell[i] = 1;
      ProfitStopLevel = 0;
   }
   else
      ProfitStopSell[ i ] = 0;
}
 
@Trav. Enjoying the thread. I'm not an Amibroker back tester, although skate's systems are making think about it. I've been wondering how Amibroker handles a trade in a stock code that becomes suspended. A recent example is AJM, say we bought after that beautiful high volume bullish bar with the blue arrow. How would this result appear in the back test trade results? In real life, the money is unavailable and is probably a wipe out.

ajm3110.PNG
 
@peter2 good question mate, and I have had a look at this and will try to explain what I have found, but there is gaps in my knowledge and the help files in AmiBroker whilst contain all the relevant information can be hard to interpret (for me anyway)

In the example below I have a buy signal on the CAM weekly chart for the 19/6/2020 and would have entered the following bar at open as shown by the white square.

1604178241215.png

Now I checked the symbol information and noticed that there is no delisting date ** as it is suspended, so AmiBroker back test will think that the stock is still active and will trade it as per the entry below, leaving us with an Open Long trade.

1604178836050.png

1604178457579.png


** delisting date - If this existed then Norgate has some functions that you can include into your logic which enables you to exit the trade in a back test.​
1604177426299.png
Now back to your question again.

My settings in AmiBroker has the 'Pad and align all data to reference symbol' ticked as I reference a foreign ticker in my code for an Index Filter and with this 'ON' the trade is no longer taken in the back test

1604184073331.png

Pad and align to reference symbol
When this is turned on, all symbols' quotes are padded and aligned to reference symbol. Note: by default this setting is OFF. Use responsibly. It may slowdown backtest/exploration/scan and introduce some slight changes to indicator values when your data has holes and holes are filled with previous bar data. The feature is intended to be used when your system uses general market timing (generates global signals based on data and/or indicators calculated using Foreign from 'reference' symbol) or when you are creating composites out of unaligned data. Note: if reference symbol does not exist, data won't be padded.


WHY ?

I honestly can't provide you with the answer. I have spent some time trying to figure this out this morning but I can't see the correlation between the Pad and Align setting and the back test settings. My only thought is that the system try's to synchronize both sets of data ( AJM and XAO ) and when it can't do this due to AJM data stopping on the 7/8/2020 then AmiBroker will not take the trade in the back test.

Maybe one of the other AB users can chip in here and provide their thoughts, but at this stage with the Pad and Align feature turned on the system will not take the last trade on the 19/6 but will take the previous trades as shown below.

1604185231914.png

Hopefully this helps answer you question.

Cheers

Trav
 
AJM didn't trade from mid Jan through to the start of March. If you select pad and align, amibroker copies the full OHLC information forward from the last bar.

The Norgate plugin handles padding differently. From their website:
The Norgate Data plugin takes a different approach to date padding. When used, if there are no trades on a given date the previous Close (only) is copied to the OHLC fields of the padded day and the Volume is set to zero.

Maybe the Amibroker padding is changing your indicator values enough that you get no signals? I just ran a quick test using a very basic entry of a High greater than the High of the last 5 bars. I get an open position regardless of whether I select pad and align in the Amibroker settings.
 
To chime in on the other part of the question. As Trav said, once Norgate adds AJM to their list of delisted codes, you can tell Amibroker what to do with the delisted security for backtesting purposes. The Norgate website recommendation is to tell the backtester to sell two days prior to delisting. But this gets all your money back at that closing price. I'm sure you could program it to sell at a closing price of $0 to be on the cautious side. Admittedly I've never done this and just keep it in mind that backtesting is going to be off by some amount due to this.

Until Norgate puts it in their delisted list, backtesting shows the trade as open with the value being based on the last closing price on record.
 
Maybe the Amibroker padding is changing your indicator values enough that you get no signals? I just ran a quick test using a very basic entry of a High greater than the High of the last 5 bars. I get an open position regardless of whether I select pad and align in the Amibroker settings.
@Lone Wolf that's interesting mate. I still get a buy on the chart which is basically checking all my conditions for entry but the back test chooses not to enter for some reason even though it should.

I do have the default settings from Norgate which should override the AB OHLS method.

1604213178921.png

Maybe it is one of those mysteries? but definitely worth being aware of and of course never trust those bloody back test results as I should have been retired by now. :roflmao::roflmao::roflmao:
 
I do have the default settings from Norgate which should override the AB OHLS method.

I'm not sure how to test it, but I feel the backtest will use the OHLC method and what you see on the chart will be whatever you select in the Norgate plug-in. If you have no padding selected you won't see the missing bars on your chart. In cases like this where the stock hasn't traded for over a month, that will make the backtested data significantly different to what you see on the chart.

I've never really considered this. Thanks to @peter2 for raising the question.
 
Hello Respected Team,

I am working on an Amibroker RSI Based Exploration. I need to tweek the exploration in such a way that, it should pick

If Index is = 34959 current price to pick

exploration to show ITM OTM and ATM

34900 CE
34800 CE
34700 CE
34600 CE

34900 PE
35000 PE
35100 PE
35200 PE
35300 PE

and pick respective Close rates from strike prices (Foreign Price)

Strike prices in following format

INDEX-WK-34900C-I
INDEX-WK-34900P-I

Also Filter Strike Prices on exploration if the RSI >60 of the strike prices.
 
Hi Guys
I been thinking about joining this site for some time but havent got around to it.
Today is the day!

Ive got an Amibroker AFL question which i cant figure out, hopefully someone more experienced has the right answer.

What im trying to achieve is set a Max Stop loss and a Trailing Stop Loss at the 10 day Low before the entry candle. Ive tried ref(Low,-10) but that just keeps updating after every new candle. Ive tried this and it doesnt do what i need. I need to be able to plot both stops so i can visually see if its doing what i need.

hopefully someone has an answer.
Thanks

https://www.amibroker.com/kb/category/analysis/backtest-analysis/stops-backtest/
 
Hi Guys
I been thinking about joining this site for some time but havent got around to it.
Today is the day!

Ive got an Amibroker AFL question which i cant figure out, hopefully someone more experienced has the right answer.

What im trying to achieve is set a Max Stop loss and a Trailing Stop Loss at the 10 day Low before the entry candle. Ive tried ref(Low,-10) but that just keeps updating after every new candle. Ive tried this and it doesnt do what i need. I need to be able to plot both stops so i can visually see if its doing what i need.

hopefully someone has an answer.
Thanks

https://www.amibroker.com/kb/category/analysis/backtest-analysis/stops-backtest/
Doing this sort of logic referencing the buy price/day and proceeding bars will probably require use of looping. Its not that hard to figure out if you've done any programming before. It gives great flexibility for your logic and will allow you to plot the stops as well.




The Formula Editor also includes some "Snippets" to get you started including trailing stop syntax:

1619085285125.png
 
Doing this sort of logic referencing the buy price/day and proceeding bars will probably require use of looping. Its not that hard to figure out if you've done any programming before. It gives great flexibility for your logic and will allow you to plot the stops as well.




The Formula Editor also includes some "Snippets" to get you started including trailing stop syntax:

View attachment 123153
Thanks qldfrog i was hoping it wasnt going to involve looping but it it what it is. I think i just need to decrement the 10 day period within the loop so it always counts ten days. Ill work on it and let you know how i go. Thanks again.
 
You might get someone have a go at the code for you from time to time, but its almost better in the long run to have a go first then ask for help. No question is too silly :)
 
I'm having some confusion with my watch list data. I'm using Amibroker with Norgate ASX Platinum.
When I run an exploration 05/04/21-09/04/21 weekly periodicity over the All Ords, I receive 499 results however when using All Ords past & current I receive 827. I think I may have missed something fundamental but I thought the two explorations should return the same number of tickers?

As a test I'm using the following exploration code:
Code:
Filter = 1;

AddColumn(Close,"Close",1.5);

Apologies if this is really dumb, however would appreciate any thoughts.

Cheers
 
Thanks qldfrog i was hoping it wasnt going to involve looping but it it what it is. I think i just need to decrement the 10 day period within the loop so it always counts ten days. Ill work on it and let you know how i go. Thanks again.
Credit to Newt, not me?
 
Top