Bar Replay and Backtesting

I am testing my strategy on EOD data but I do have IEOD(1 min) data.
Now the problem is that when I put two stop orders(one for profit taking and one for stop loss), then when I am backtesting using EOD data, the backtester has no way to know which price was "touched" first. Therefore, the results I am getting are not accurate.

Now when I turn on bar replay, it works fine when I select the range as "1 recent bar(s)". It runs on the currently played data which is ok. But I want backtest to run on the whole date range using bar replay. This way I can get more accurate backtest results.

But it looks like there is no way to do this. Is there anyway to do it?

To add some more context:

I am doing day trading in backtesting. The strategy operates on past daily data and makes decision on what to do on the current trading day.

Now there may be a way to use TimeFrame functions but it will unnecessarily make the code very complex. Since Amibroker already has a Bar Replay function, I thought it would be useful in backtesting too. But my initial probing suggests that it is only useful for Charts and Explorations.

I already know about MultiTimeframe support functions and I have visited that page several times when I am actually implementing strategies which need 1 minute timeframe data like intraday breakouts.

However, my strategy works on daily open prices and when you put two stop orders, it is not possible to know which executes first using EOD data without bar replay.

Using TimeFrame functions does not complicate, it simplifies! Otherwise, how else you would capture data of higher timeframes (Daily) from a lower intraday timeframe (in which you are backtesting).

It does complicate. Atleast for me, who I consider to have decent enough background in coding.
I have a code like this:
LLV(C < Ref(C, -1), 5) == 0
which checks if daily price has not been falling 5 days in a row.

I believe this internally translates to:

IF(C[0] < C[-1]) && IF(C[-1] < C[-2]) && ...... && IF(C[-4] < C[-5])

where index 0 is currently processed value and -n is n bar behind.

With timeframe compression, I would first get an array of prevDayClose but I can't just write:
LLV(prevDayClose < Ref(prevDayClose, -1), 5) == 0
because on all intraday bars....prevDayClose[-1 to -n] will refer to just that, the previous day close. Same value in all the intraday bars.

So to convert the above construct(checking daily closes for 5 days in a row), I have to create my own version of LLV which instead of just referencing previous array value, refers to the boundary conditions when the date changes. I have to similarly write custom code for all the several different conditions like this.

This definitely increases the complexity which could have been 100 times simpler if Bar Replay was allowed in backtesting. We all know that everything is possible given enough effort and time, but that is the reason we use AFL instead of C++ because we know that it makes things simpler.

Bar replay based backtesting is available in some different frameworks like backtrader(python-based). It was also my hope that its available in Amibroker since Bar replay is already there for Charting.

To alleviate any confusion. There is no "error" in my code or data as Cougar relates to:

Otherwise, your IEOD data is incorrect wherein the day's OHLC does not match with Exchange's EOD. So, the real issue is with "data" not bar-replay or backtester or timeframe functions.

The problem is simple. If you put two stop orders. Even though your code will work properly, but it is the nature of EOD data that we just have High/Low range and the backtester will just check to see if the profit order(first stop order) or the stop loss(second stop order) executes by checking if it within the price ranges.
In backtesting, this gets arbitary and it just depends on which condition is checked by Amibroker first, internally.
Bar replay very simply allows the backtester to simulate a real market using IEOD data on EOD bars. This is how we work during Live Trading in AFL.

Based on your writing above you are doing it incorrectly. Please consult AB manual.
You do not need to write your own LLV function and there is almost zero increased complexity.

Based on your description above your mistake is that you compress price array only and doing calculations on expanded price.
So apparently what you do right now (based on your description) is something like this one:

prevDayClose = TimeFrameGetPrice("C", inDaily, -1);// previous day close
cond = LLV(prevDayClose < Ref(prevDayClose,-1), 5) == 0;// calculation on expanded prices - INCORRECT

But that's not correct because then cond does what you describe... it compares same prices intraday (if being minimum 5 bars in the day) as it operates on expanded prices in that case.

But you should rather use TimeFrameSet/Restore and then expand (read about expand modes in addition) after calculation.

tmfrm = inDaily;
expandmode = expandLast;
TimeFrameSet( tmfrm );
	// calculation on compressed price
	myvar = LLV(C<Ref(C,-1), 5) == 0;
	//myvar2 = ...;
	//etc.
TimeFrameRestore();
// expanding after being finished
myvar = TimeFrameExpand( myvar, tmfrm, expandmode );
//myvar2 = TimeFrameExpand( myvar2, tmfrm, expandmode );

Or

tmfrm = inDaily;
expandmode = expandLast;
DC = TimeFrameCompress(C, tmfrm);// compressed price
myvar = LLV(DC<Ref(DC,-1), 5) == 0;// calculation on compressed price
// expanding after being finished
myvar = TimeFrameExpand( myvar, tmfrm, expandmode );

Then LLV calculates on compressed price only and result gets expanded after that.

Further AB manual consultations:
https://www.amibroker.com/guide/afl/timeframeset.html
https://www.amibroker.com/guide/afl/timeframerestore.html
https://www.amibroker.com/guide/afl/timeframecompress.html
https://www.amibroker.com/guide/afl/timeframeexpand.html

2 Likes

@Cougar

Hey, I have seen that for some reason you have withdrawn your post. Anyways, I thank you for your reply.
You also mentioned, as I remember that "Allow mixed EOD/Intraday Data" should be unchecked. Can you let me know why it may be helpful?
I understand that intraday 1 minute timeframe data is different than EOD data. I read somewhere that when we compress 1 minute data into EOD, it wouldn't exactly match the EOD data we download later from the exchange. This is due to stray ticks during opening and closing.
I believe the reason you mentioned is something to do with that?

Regards.

Mixed EOD/Intraday doesn’t actually mix data as you think.

What it does is for some data sources, it will request intraday data which may only go back say 200 days, but then also request more EOD data if it exists.

For instance(not exact numbers here) IQFeed has minute data back to 2007 but EOD data to 1975. It will download minute data until 2007 then look to download Daily data back to 1975. They won’t overlap.

1 Like

My previous post that I deleted was this:

Then do not mix EOD and IEOD quotes in the database. From File > Database settings > Intraday settings > Uncheck "Allow mixed EOD/Intraday data". Remove all the EOD quotes from the Database. Keep only IEOD (1 min) data and use TimeFrame functions to Compress/Expand appropriately.

Using TimeFrame functions does not complicate, it simplifies! Otherwise, how else you would capture data of higher timeframes (Daily) from a lower intraday timeframe (in which you are backtesting).

When you have IEOD data, you can always compress it to form EOD, then Expand it to the lower intraday timeframe in which you are backtesting.

This guide Multiple Time Frame support in AFL explains it all.

Otherwise, your IEOD data is incorrect wherein the day's OHLC does not match with Exchange's EOD. So, the real issue is with "data" not bar-replay or backtester or timeframe functions.

To that you wrote:

The reason to delete the post was because, what I wrote stood no meaning to you, since, you had already visited and understood "Multi-Timeframe support functions". fxshrat has now generously showcased the same Timeframe functions which are vividly explained in the Multi-Timeframe functions guide.

You're most welcome. I respect that!

No. I meant what is written in the guide. Quoting from there:

Allow mixed EOD/Intraday data - it allows to work with database that has a mixture of intraday and EOD data in one data file. If this is turned on then in intraday modes EOD bars are removed on-the-fly and in daily mode EOD bars are displayed instead of time compressed intraday or if there is no EOD bar for corresponding day then intraday bars are compressed as usual.

This mode works in conjunction with new versions of plugins that allow mixed data. As of June 2008 Mixed mode is now supported by IQFeed plugin, eSignal plugin (1.7.0 or higher) plugins only. Mixed mode allows intraday plus very long daily histories in one database.

1 Like