Australian (ASX) Stock Market Forum

Amibroker FAQ

You can save project files (which are not ABS but APX files. ABS files save backtest settings only). Those APX files save your AFL and all your analysis settings (backtest and analysis toolbar settings) to a whole project.


Thanks Trash - I am slowly getting there. Again your suggestion on the apx is a good solution.

After reading https://groups.yahoo.com/neo/groups/amibroker/conversations/topics/177728 I now know how to launch the apx from within Amibroker.

So problem solved.

Thanks again for your patience
 
I would like to have backtest parameter setting to default to trade at next day open.

Greetings --

Whatever values are set using the Settings dialog will be overwritten by assignments made using statements in the afl program.

I recommend:
1. Control settings using afl (rather than the Settings dialog) whenever possible.
2. Pick a meaningful point in time from which to make calculations and issue signals. It should be a time when all the required information is available, the order can be placed, and the desired price can be calculated.

It can be confusing when the code uses SetTradeDelays with delays other than zero, Refs that use previous values, and orders that will be executed at a time that is different than the time the orders are generated.

Best,
Howard
 
Greetings --

Whatever values are set using the Settings dialog will be overwritten by assignments made using statements in the afl program.

No, it's not correct. If i.e. backtestRotational is used in AFL then trade prices and trade delays of AFL code will not override what has been set in settings dialog. So there are exceptions.
 
hello,

I'm trying to implement double stop with:
- exit with SellPrice on Close after x bars
- exit with SellPrice on TP

Often positions are closed too early and with incorrect price. My short self-documentary code:
//*************************//
SetOption("ActivateStopsImmediately",False);
SetTradeDelays(0,0,0,0);

MyBuy = C > Ref(C,-5);
HoldDays = 10;

HowManyBarsLastTrade= BarsSince(MyBuy);
TP = Ref(C,-HowManyBarsLastTrade)+40;
SellOnClose = HowManyBarsLastTrade>= HoldDays;

Buy = MyBuy;
Sell = (H > TP OR SellOnClose) AND HowManyBarsLastTrade> 0;

Buy = ExRem (Buy, Sell);

BuyPrice = C;

If (SellOnClose[BarCount-1] == true)
SellPrice = C;
else
SellPrice = TP;
//*************************//

Thanks for prompts :)
 
hello,

I'm trying to implement double stop with:
- exit with SellPrice on Close after x bars
- exit with SellPrice on TP

Often positions are closed too early and with incorrect price. My short self-documentary code:
//*************************//
SetOption("ActivateStopsImmediately",False);
SetTradeDelays(0,0,0,0);

MyBuy = C > Ref(C,-5);
HoldDays = 10;

HowManyBarsLastTrade= BarsSince(MyBuy); example -- 11 bars since MyBuy
TP = Ref(C,-HowManyBarsLastTrade)+40; example -- close price 11 bars ago (buyprice) plus 40 = future bar 29 close price
SellOnClose = HowManyBarsLastTrade>= HoldDays; example -- day is greater than or equal to 11 since MyBuy

Buy = MyBuy; -- any close price that the close is greater than a close 5 days ago
Sell = (H > TP OR SellOnClose) AND HowManyBarsLastTrade> 0; high price is greater than future bar 29 close price or high price is greater than day 11 (not possible)

Buy = ExRem (Buy, Sell);

BuyPrice = C;

If (SellOnClose[BarCount-1] == true)
SellPrice = C;
else
SellPrice = TP;
//*************************//

Thanks for prompts :)

I am an amateur and this is how I read it. A high price cannot be greater than a bar number and the future bar close price remains in the future.
 
hello,

I'm trying to implement double stop with:
- exit with SellPrice on Close after x bars
- exit with SellPrice on TP

Often positions are closed too early and with incorrect price. My short self-documentary code:
//*************************//
SetOption("ActivateStopsImmediately",False);
SetTradeDelays(0,0,0,0);

MyBuy = C > Ref(C,-5);
HoldDays = 10;

HowManyBarsLastTrade= BarsSince(MyBuy);
TP = Ref(C,-HowManyBarsLastTrade)+40;
SellOnClose = HowManyBarsLastTrade>= HoldDays;

Buy = MyBuy;
Sell = (H > TP OR SellOnClose) AND HowManyBarsLastTrade> 0;

Buy = ExRem (Buy, Sell);

BuyPrice = C;

If (SellOnClose[BarCount-1] == true)
SellPrice = C;
else
SellPrice = TP;
//*************************//

Thanks for prompts :)


Your entire code is just wrong.
Btw as for n-bar stop and profit target stop there is Applystop function.
 
Your entire code is just wrong.
Btw as for n-bar stop and profit target stop there is Applystop function.

Thanks trash for suggestion to use Applystop. Basing on https://www.amibroker.com/guide/afl/applystop.html
I coded as below and now it looks that it works.

Code:
MyBuy = C > Ref(C,-5);
HoldDays = 10;

Buy = MyBuy ;
HowManyBarsFromBuy= BarsSince(Buy)+1;
SellOnClose = HowManyBarsFromBuy > HoldDays;
Sell = SellOnClose ;

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

BuyPrice = C;
SellPrice = C;

ApplyStop( stopTypeProfit , stopModePoint, 40, ExitAtStop = 1 );
ApplyStop( stopTypeNBar, stopModeBars, HoldDays, ExitAtStop = 0 );
 
hello,

I'm trying to implement double stop with:
- exit with SellPrice on Close after x bars
- exit with SellPrice on TP

Often positions are closed too early and with incorrect price. My short self-documentary code:
//*************************//
SetOption("ActivateStopsImmediately",False);
SetTradeDelays(0,0,0,0);

MyBuy = C > Ref(C,-5);
HoldDays = 10;

HowManyBarsLastTrade= BarsSince(MyBuy);
TP = Ref(C,-HowManyBarsLastTrade)+40;
SellOnClose = HowManyBarsLastTrade>= HoldDays;

Buy = MyBuy;
Sell = (H > TP OR SellOnClose) AND HowManyBarsLastTrade> 0;

Buy = ExRem (Buy, Sell);

BuyPrice = C;

If (SellOnClose[BarCount-1] == true)
SellPrice = C;
else
SellPrice = TP;
//*************************//

Thanks for prompts :)

Code:
//*************************//
SetOption( "ActivateStopsImmediately", False );
SetOption( "AllowSameBarExit", False );

SetTradeDelays( 0, 0, 0, 0 );

HoldDays = 10;
amount = 40 /* * TickSize */; // profit target

BuyPrice = C;
Buy = Ref( C > Ref( C, -5 ), -0 );

SellPrice = C;
Sell = 0;
Short = Cover = 0;

ApplyStop( stopTypeNBar, stopModeBars, HoldDays, priority = 1 );
ApplyStop( stopTypeProfit, stopModePoint, amount, exitatstop = 1, False, 0 );
 
I have been exploring historical backtest using code that Tomasz Janeczko posted from here http://www.amibroker.com/kb/2014/09/30/gen-backtest-from-a-file/

I have made a number of modifications for my own purposes.

I have found an issue in my testing that a share acquired through a rights issue, issued at $4.20, will only reflect a price in the OHLC range. This particular share had a low of $5.58 on the issue date and in my backtest report reflects $5.58 as my buy price and not the true buy price of $4.42.

Is there a way to override the OHLC parameters to have this reflect the true buy price?

Code:
file = "C:\\TEMP\\trades.csv"; // change this to real location of your data 
dt = DateTime();

// signal-based backtest, redundant (raw) signals are NOT removed,
// MULTIPLE positions per symbol will be open if BUY/SHORT signal is 'true' for more than one bar and there are free funds
// Sell/Cover exit all open positions on given symbol, Scale-In/Out work on all open positions of given symbol at once.
SetBacktestMode( backtestRegularRawMulti ); 


//
// Initialize variables
SetOption("InitialEquity",200000);
SetTradeDelays (0,0,0,0);
Buy = Sell = possize = 0;
SetOption("CommissionMode",2);/* set commissions AND costs as $ per trade*/
SetOption("CommissionAmount",6.00); /* commissions AND cost */
//
fh = fopen( file, "r" );
//
if( fh )
 {
     while( ! feof( fh ) )
     {
         line = fgets( fh );
         // get the ticker symbol from the file
         sym = StrExtract( line, 0 );
         // if ticker matches current symbol
         if ( Name() == sym )
         {
             // extract data from line of text
             trade = StrExtract( line, 1 );
             trade_datetime = StrToDateTime( StrExtract( line, 2 ) );
             price = StrToNum( StrExtract( line, 3 ) );
             shares = StrToNum( StrExtract( line, 4 ) );
             //
             if ( trade == "Buy" )
             {
                 newbuy = dt == trade_datetime;
                 Buy = Buy OR newbuy; // combine previous buy signals with new
                 BuyPrice = IIf( newbuy, price, BuyPrice );
                 possize = IIf( newbuy, shares, possize );
             }
             //
             if ( trade == "Sell" )
             {
                 newsell = dt == trade_datetime;
                 Sell = Sell OR newsell; // combine previous sell signals with new
                 SellPrice = IIf( newsell, price, SellPrice );
             }
         }
     }
     //
     fclose( fh );
 }
 else
 {
     Error( "ERROR: file can not be open" );
 }
//
SetPositionSize( possize, spsShares );
 
I have been exploring historical backtest using code that Tomasz Janeczko posted from here http://www.amibroker.com/kb/2014/09/30/gen-backtest-from-a-file/

I have made a number of modifications for my own purposes.

I have found an issue in my testing that a share acquired through a rights issue, issued at $4.20, will only reflect a price in the OHLC range. This particular share had a low of $5.58 on the issue date and in my backtest report reflects $5.58 as my buy price and not the true buy price of $4.42.

Is there a way to override the OHLC parameters to have this reflect the true buy price?

Code:
file = "C:\\TEMP\\trades.csv"; // change this to real location of your data 
dt = DateTime();

// signal-based backtest, redundant (raw) signals are NOT removed,
// MULTIPLE positions per symbol will be open if BUY/SHORT signal is 'true' for more than one bar and there are free funds
// Sell/Cover exit all open positions on given symbol, Scale-In/Out work on all open positions of given symbol at once.
SetBacktestMode( backtestRegularRawMulti ); 


//
// Initialize variables
SetOption("InitialEquity",200000);
SetTradeDelays (0,0,0,0);
Buy = Sell = possize = 0;
SetOption("CommissionMode",2);/* set commissions AND costs as $ per trade*/
SetOption("CommissionAmount",6.00); /* commissions AND cost */
//
fh = fopen( file, "r" );
//
if( fh )
 {
     while( ! feof( fh ) )
     {
         line = fgets( fh );
         // get the ticker symbol from the file
         sym = StrExtract( line, 0 );
         // if ticker matches current symbol
         if ( Name() == sym )
         {
             // extract data from line of text
             trade = StrExtract( line, 1 );
             trade_datetime = StrToDateTime( StrExtract( line, 2 ) );
             price = StrToNum( StrExtract( line, 3 ) );
             shares = StrToNum( StrExtract( line, 4 ) );
             //
             if ( trade == "Buy" )
             {
                 newbuy = dt == trade_datetime;
                 Buy = Buy OR newbuy; // combine previous buy signals with new
                 BuyPrice = IIf( newbuy, price, BuyPrice );
                 possize = IIf( newbuy, shares, possize );
             }
             //
             if ( trade == "Sell" )
             {
                 newsell = dt == trade_datetime;
                 Sell = Sell OR newsell; // combine previous sell signals with new
                 SellPrice = IIf( newsell, price, SellPrice );
             }
         }
     }
     //
     fclose( fh );
 }
 else
 {
     Error( "ERROR: file can not be open" );
 }
//
SetPositionSize( possize, spsShares );

Add
Code:
SetOption( "PriceBoundChecking", False );
 
Scan
this starts the signal scan mode - AmiBroker will search through defined range of symbols and quotations for buy/sell signals defined by your trading rules.If one of the buy/sell conditions is fulfilled, AmiBroker will display a line describing when and on which symbol the signal has occurred. Next AmiBroker proceeds to the end of the range so multiple signals on single symbol may be generated.
Explore
this starts an exploration mode when AmiBroker scans through database to find symbols that match user-defined filter. The user can define output columns that show any kind of information required.

Have never understood why when I explore with "Buy" as the filter, the results are different from scan. The above quote from the Ami. docs. states that scan searches using the buy/sell criteria while the exploration uses a defined filter. I use the same filter criteria in explore, "Buy".

Is there a simple explanation please?
 
Have never understood why when I explore with "Buy" as the filter, the results are different from scan. The above quote from the Ami. docs. states that scan searches using the buy/sell criteria while the exploration uses a defined filter. I use the same filter criteria in explore, "Buy".

Is there a simple explanation please?

To get long entry and exit signals like in Scan the correct Filter in Exploration is

Code:
Filter = Buy OR Sell;

If you just filter "Buy" then quite obviously you get only entry signals.
 
To get long entry and exit signals like in Scan the correct Filter in Exploration is

Code:
Filter = Buy OR Sell;

If you just filter "Buy" then quite obviously you get only entry signals.
Code:
Filter = Buy; 
AddColumn(IIf(Buy, C, 0), "Buy", 1.3, IIf(Buy, colorBlue, 0));
Filter = Sell; 
AddColumn(IIf(Sell, C, 0), "Sell", 1.3, IIf(Sell, colorDarkRed, 0));


This is what I had but when I change it to "Filter = Buy OR Sell" and chop the "Filter = Sell" then the scan and exploration are the same. Thank you for the guidance.
 
Code:
Filter = Buy; 
AddColumn(IIf(Buy, C, 0), "Buy", 1.3, IIf(Buy, colorBlue, 0));
Filter = Sell; 
AddColumn(IIf(Sell, C, 0), "Sell", 1.3, IIf(Sell, colorDarkRed, 0));


This is what I had but when I change it to "Filter = Buy OR Sell" and chop the "Filter = Sell" then the scan and exploration are the same. Thank you for the guidance.

Code:
period = 20; // number of averaging periods 
m = MA( Close, period ); // simple moving average
Buy = Cross( Close, m ); // buy when close crosses ABOVE moving average
Sell = Cross( m, Close ); // sell when closes crosses BELOW moving average

Buy = Ref( Buy, -0 );
Sell = Ref( Sell, -0 );

BuyPrice = SellPrice = Close;

if( Status( "action" ) == actionExplore )
{
	Filter = Buy OR Sell;
	AddColumn( IIf( Buy, BuyPrice, Null ), "Buy", 1.3, colorBlue );
	AddColumn( IIf( Sell, SellPrice, Null ), "Sell", 1.3, colorDarkRed );
}
 
Trouble Calculating σ of Expectancy in the Custom Backtest Report

Hey All,

I have been trying to add the standard deviation of expectancy (avg. profit % per win/loss) to the backtest report by using built-in metrics found at the bottom of https://www.amibroker.com/guide/a_custombacktest.html but I have not found an easy way to calculate it.

For instance, I tried taking the Standard Error of the equity line divided by the average equity of the portfolio then multiplied by sqrt(# of trades). I also tried modifying the Sharpe Ratio [SR = (annualized return - risk free return)/σ of returns] but the values compared to what excel got were far off from what was expected.

I know how to calculate standard deviation by hand and in excel but it is giving me trouble trying to calculate it for the custom backtest report. Is there an easier way to calculate the σ than trying to find it by modifying the built-in metrics provided? I looked around but was not able to find anything specifically on the topic. Any help would be greatly appreciated.

If it helps, here’s part of the code I was using before I started making erroneous calculations:

SetCustomBacktestProc( "" );
if ( Status( "action" ) == actionPortfolio )
{ bo = GetBacktesterObject();
bo.Backtest(); // run default backtest procedure
st = bo.GetPerformanceStats( 0 );
Expectancy = st.getvalue("Allavgprofitlosspercent");
QtyTrades = st.GetValue("allqty");
AvgBars = st.getvalue("AllAvgBarsHeld");
CAR=st.getvalue("CAR"); RAR=st.getvalue("RAR");
SR=st.getvalue("sharperatio");
StdEr = st.getvalue("standardError");
FiEq = st.getvalue("endingcapital");
StdDev = ??
Variance = StdDev^2;
SE = StdDev/(QtyTrades^(1/2));
bo.AddCustomMetric("Expectancy (%)", Expectancy);
bo.AddCustomMetric("StdDev", StdDev);
bo.AddCustomMetric(“tTest”, expectancy*sqrt(QtyTrades)/StdDev);
}

Thanks for the help,
Dave
 
I'd like to calculate the daily returns of a system that trades a portfolio of stocks.

Initially I thought I'd use the close price for each trade, close to close in the custom backtester, but have since come to think using equity change might be better at measuring it as it is portfolio level, again close to close.

My latest attempt at code is:

Code:
SetCustomBacktestProc("");
if(Status("action") == actionPortfolio)
{
 dateStart = Status("rangefromdate");
 dateEnd = Status("rangetodate");
 
 bo = GetBacktesterObject();
 bo.backtest();
 
 dt = DateNum();
 eq = bo.EquityArray();
 eqDaily = 0; 
 for (i = 1; i < BarCount; i++)
  {
  eqDaily[dt[i]] = eq[i];
  }
 eqDaily[dateStart] = GetOption("InitialEquity");
 eqDaily[dateEnd] = eq[BarCount];

 for (i=dateStart; i<= dateEnd; i++)
  {
  bo.addcustommetric("Daily P/L", 100*(eqDaily[i]/eqDaily[i-1] - 1));
  }
 bo.ListTrades(); 
}

Some help elsewhere was provided as:
Code:
Setforeign ("~~~EQUITY"‎);

Ret = c/ ref (c, -1) - 1;

//Ret*= 100‎:

Neither of these work though. I get the error: "The results file can not be open for writing."

Any help appreciated.

Ato
 
It doesn't work because your codes are completely wrong or are missing stuff.
Your 1st one is total nonsense code.
2nd one is missing restore.

Code:
// daily return output to report 
// one of billions of solutions by trash
// https://www.aussiestockforums.com/forums/showthread.php?t=1679&page=119&p=873761&viewfull=1#post873761

// Note: output to report file gets generated/updated on second click on "Backtest" button 
// since Equity symbol gets written to database on harddrive first during 2nd phase of BT.

Setforeign( "~~~EQUITY" );
cl = Close;//TimeFrameGetPrice( "C", inDaily, 0 );
refcl = TimeFrameGetPrice( "C", inDaily, -1 );
ret = ( cl / refcl - 1 ) * 100;
RestorePriceArrays();

dt = DateTime();
EOD = Day() != Ref( Day(), 1 );
bir = Status( "barinrange" );

SetCustomBacktestProc("");
// Now custom-backtest procedure follows
if( Status( "action" ) == actionPortfolio ) {
    bo = GetBacktesterObject(); // Retrieve the interface to portfolio backtester
    bo.Backtest();

    bo.AddCustomMetric( "Daily %P/L:" );
    for( i = 0; i < BarCount; i++ ) {
        if( EOD[i] && ret[i] != 0 && bir[i] )            
            bo.AddCustomMetric( DateTimeToStr( dt[i] ), ret[i] );
    }
}
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

// some dummy system

SetPositionSize( 25, spsPercentOfEquity );

period = 20; // number of averaging periods 
m = MA( Close, period ); // simple moving average
Buy = Cross( Close, m ); // buy when close crosses ABOVE moving average
Sell = Cross( m, Close ); // sell when closes crosses BELOW moving average
 
Short = Cover = 0;

As aside... not sure why you need extra large letters
icon5.gif

Do you think readers are blind? Certainly your way rather is an attempt to make readers blind by causing eye cancer.
 
Hello trash

Thank you for the reply, and code! Much kudos to you, and much obliged myself /bow

I seem to get an error with the code you posted though. When I click Backtest, an error message appears, to which I click the Try to Continue button. Then I need to click on the red square stop button. Then the error message: "The results file can not be open for writing." appears. The code works fine, in that the daily p/l is listed at the bottom of the Report. However, no additional columns are added to the Backtest Analysis (just the default values as normal). Also, the Report Explorer doesnt seem to work. If you have any ideas, I would again be most appreciative. I did some google searching and it seems like those errors are said to occur when Excel or Word is open, but I had neither of these open when running the backtest.

Yes, I'm very sorry for the large font! I posted the original message on a device with a very small screen, and it was more for my own benefit than anyone else's. I checked on my desktop and it is indeed rather large! O_O I would edit it back to normal size, but there doesnt seem to be an edit function on previous posts. Sorry about that.

Anyway, thanks again for the help. It is sincerely appreciated.

Ato
 
Top