Incorrect formula, was: Inconsistent Open, High, Low, Close, Volume (OHLCV)

Background - I am new to Amibroker AFL programming. But have experience programming VB Net & DB Programming. Using latest download of Amibroker Professional Version 6.20.1 Feb 17 2017.

Aim - I want to analyse stocks in real time in one minute bars (via TimeFrameSet(in1Minute)). OHLCV values are available through Amibroker.

Problem - If I am browsing StockABC in the Charting Window I get one set of OHLCV values. On the other hand if I am browsing StockDEF in the Charting Window I get another set of OHLCV values.
Code Snippet

	TimeFrameSet(in1Minute);
	for( iCount=0; iCount <= GiStocksCount; iCount++)
	{
		StocksExtract(iCount);
		if (SetForeign(GStrStocksCurrent, True) ==1)
		{
			f_Open = O[BarCount-1];
			f_High = H[BarCount-1];
			f_Low = L[BarCount-1];
			f_Close = C[BarCount-1];
			f_High = H[BarCount-1];
			f_Volume = V[BarCount-1];
		}
	}

Note: All the above variables get one set of data if I am browsing (say) "StockABC" in the main Charting Window. The results are different if I am browsing another stock (say) "StockDEF" in the main Charting Window.

Another observation - If I am browsing "StockAFL" in the Charting Window. At the same time trying to access OHLCV of the same "StockAFL" in AFL Code. I do not get correct results. The OHLCV data is of the previous stock. I am using SetForeign(GStrStocksCurrent, True) to rotate between stocks.

Solution? Is there a configuration I am missing. Or other initialization needing attention. Any help/pointers would be greatly appreciated. Thank you.

@TheWord, as you probably already discovered, in general, when you use SetForeign(), to execute your code in an Analysis tab you should set the Pad&Align reference symbol (from the BackTester Settings dialog/General tab) to avoid any potential issue caused by data holes (search the forum for "missing data pad").

While the side effects of not using Pad&Align in Analysis are well known, for some reason it may be less evident that something analog also happens when you run some code directly from a chart formula that is invoking SetForeign().

In this case, the current symbol (the one displayed in the main chart) is behaving like the reference "Pad & Align" symbol in the Analysis mode.

This means that if you "main" symbol has a longer or shorter data history of the other symbol/s that you are evaluating via Foreign in your code the BarCount of the foreign ticker/s is "aligned"(padded or shortened as needed) to the "reference" (the symbol in the chart).

To better understand the matter, please, take a look at this screenshot:
immagine

In this chart tab, the upper pane shows the "main" symbol (for which in my database I have a long data history).

The lower pane uses a SetForeign() function to display another (fake) ticker that has only some recent data but was not updated in the last few days.

As you can see, both the "BarCount" labels display the same value based on the main chart visible bars (QuickAFL in my configuration is enabled).

But the last "true" bar of the Foreign symbol IS NOT corresponding to the "BarCount-1" bar: the foreign array is "padded" with additional "missing bars", where all the OHLC values are the same - based on the last valid Close - but the corresponding Volume is set to zero
(This is true for AB version >= 4.90 - see the default fixup parameter.)

The last "true" values of the foreign symbol are the ones displayed in following the screenshot taken from the "Quote Editor*.

immagine

So, to avoid unexpected "alignment" issues in the main chart (and for the Analysis in the Pad & Align settings), you should always try to select a main/reference symbol with no data holes, updated to the most current date/time and ideally with the longest data history in your database.
(This will avoid issues like reported here or here).

To locate a specific bar on foreign arrays you could rely on timestamps (DateNum(), TimeNum(), DateTime()) and/or conditions that combined with proper functions like ValueWhen, etc. will allow you to identify a specific bar index.

Since you are new to AmiBroker, I suggest spending a reasonable amount of time searching and examining the code examples that employ these functions to use the AFL Function Reference to get additional information (study the code samples and read the comments too).

Finally, note that I did not mention the TimeFrameSet() function.
Its usage in your code snippet seems unneeded since you are not using/mixing data calculated from other timeframes. (This is a subject that I think it is better to tackle when you have some solid understanding of the basics).

So, for my explanation and chart examples, I did not use it. I simply set the correct interval in the user interface.

8 Likes

Thank you Beppe for your detailed reply. All the detailed explainations with screen shots are truly incredible & much appreciated. Thank you.

  1. You have made the concept of padding absolutely clear. Padding is essential because some stocks may not be traded for several minutes. These un-traded minutes will form 'data holes'. And need to be padded to create meaningful data. As suggested, now I am using the stock with the most details as my main Charting symbol. This is giving me consistent results. Thank you.

  2. Also thank you for bringing to my notice the Quotations Editor. Till your post I did not know the existence of this beast. I had never been there .. never done that. And never knew this tool even existed. This is a great tool for cross-checking data against AFL code. It is painstakingly slow to check bar data in the Charting Window. Not any more .. with the Quotations Editor.

  3. Yes I am new to AmiBroker .. and the TimeFrameSet function has caused me much grief. I put this function inside a for loop. TimeFrameSet() is a slow function and probably runs in its own dedicated thread (I am guessing here). Inside a for loop the function would be called several times before the first call had even finished. The side effect was that it would shut down AmiBroker intermittently. And I had no idea where the bug was. Traced it to TimeFrameSet(). I am not using multiple timeframes. As you have correctly pointed out, it should not be in my code at all. This is an advanced option. Thank you.

  4. Lastly, I am also taking your suggestion to learn more about AmiBroker and AFL. With my little knowledge and understanding I am only beginning to grasp its true potential. Its a great platform. Well worth to spend time and learn its internal gears. Thank you.

1 Like

You should not call TimeFrameSet in a loop. There is NO reason to do so. First read http://www.amibroker.com/guide/h_understandafl.html

All loop invariant code must be outside of any loops. This is not visual basic. This is vector processing. All bars processed at once.

1 Like

Mr. Tomasz, your personally answering to my post is much appreciated. What an honor! Thank you.

Also many thanks for building a Robust, Versatile, Efficient, Dependable, Easy to use, Exceedingly Responsive & Programmable platform. This certainly gives me an edge over others in the stock markets. I am only beginning to grasp the true potential of this remarkable software. Thank you.

2 Likes