Suppose I have a chart with three panes. The top pane uses top.afl, the middle uses middle.afl and the bottom uses bottom.afl. Am I correct in assuming that top.afl will execute first, middle.afl second and bottom.afl last? I ask because I need to pass (static) variables created in middle.afl to bottom.afl, so order of execution is critical. Incidentally, I would really prefer not to use #include! Thank you very much.
No, the assumption is incorrect.
In multithreading program like AmiBroker things work in parallel so all three panes execute independently and simultaneously
Only if you turned off multithreading (not recommended) you would get fixed sequence.
But you still can write static variables in one pane and read them in other pane with multithreading turned on because static variables are thread-safe.
Hi Tomasz - it could not be easier! Thanks so much for your quick and extremely helpful response. And of course a huge thank-you for your truly extraordinary platform.
@RobertJay - you’re welcome
Being a newcomer who would like to learn AFL properly and having designed multithreaded processors and software for a living, this issue of order of execution is interesting to me.
Please consider the sample AFL. The exact buy and sell rules are uninteresting but please note that they are bracketed by a StaticVarAdd and _TRACE pair on before and afer.
if (Status("stocknum") == 0) StaticVarSet("x", 100); StaticVarAdd("x", 1); _TRACE("AT: #1: " + LastValue(Foreign("~~~Equity", "C")) + " " + StaticVarGet("x") + " " + Name()); Buy = Cross(Close, EMA(Close, 50)); Sell = Cross(EMA(Close, 50), Close); StaticVarAdd("x", 1); _TRACE("AT: #2: " + LastValue(Foreign("~~~Equity", "C")) + " " + StaticVarGet("x") + " " + Name());
When I run this as a portfolio backtest on the sample Data database that came prepackaged with AB, I get the output shown:
The final equity across all symbols for the portfolio is supposed to be $36035.37. That is correctly computed and output when the first _TRACE statement is executed for stock AA. That statement precedes the buy and sell rules in program order. How can ending portfoli equity be already computed before the buy and sell rules? Furthermore, the first _TRACE statements for all the other symbols in the portfolio have yet to execute!
This seems to defy the concept of sequential consistency which I would have assumed to apply to AFL. Please advise since we need an ordering model to reason about code. Thank you!
Saving some time...
There is no magic about it.
~~~Equity is a physical symbol being part of your DB and is updated at the end of backtest. Foreign function calls that artificial symbol.
The reason that it is showing your expected result at start already is that it's the
~~~Equity result of previous run of backtest. You have simply run the same backtest code before looking at it via Trace. So the result was saved already in DB (database) before running subsequent BT of same rules and settings.
Do a new test but this time before running backtest delete the
~~~Equity in Symbols window (right click symbol -> and "Delete")
Then run backtest again with Trace window open and you will see that Equity result will show ZERO all the way till the end of backtest. Why is that? Because it does not exist yet. It will be saved after BT (backtest) being finished.
Then run backtest a second time and it will show result of Equity of previous BT run.
Quote from manual:
Efficient use of multithreading
Accessing ~~~Equity symbol
Using Foreign("~~~Equity", "C" ) makes sense only to display chart of the equity of the backtest that has completed . It is important to understand that new Analysis window supports multiple instance, and therefore it can not use any shared equity symbol, because if it did, multiple running backtest would interfere with each other. So New Analysis has local, private instance of all equity data that is used during backtesting and only AFTER backtesting is complete, it copies ready-to-use equity data to ~~~Equity symbol. This means that if you call Foreign("~~~Equity", "C" ) from within the formula that is currently being backtested, you will receive previous backtest equity, not current one.
So as always everything is correct and as expected.
As aside another quote from upper help file link:
Efficient use of multithreading
To access current equity, you need to use custom backtester interface. It has "Equity" property in the backtester object that holds current account equity. If you need equity as an array there are two choices, either collect values this way:
Thank you @fxshrat. I have verified that your diagnosis is correct and that ~~~Equity is computed at the end after all threads have computed the buy and sell. It is a relief to know that sequential consistency holds.
@alpha1 quite frankly I find it extremely offending that people even consider the possibility that I did not do my job well. You come as a newcomer being here for less than 2 weeks and instead of questioning yourself and reading the docs, you start to question 25+ years of my work. Really that's offending. I have earned Ph.D from computer science 25 years ago, designed dozens of professional systems (not only AmiBroker) on many systems (including embedded) and I am proud with my work. In the world of bloated software written by amateurs, my work is a pinnacle of perfection, compactness and speed.
Thanks to @fxshat for saving me from dealing with such nonsense over and over again and quoting relevant parts of documentation.
My apologies if I offended you. Suggesting that you had not done your job well was the furthest thing from my mind when I wrote the request for help. I can see AB is a fantastic platform. I said as much on another thread two days back.
Finally, my mistake for not reading the Multithreading chapter carefully. The chapter is titled "Efficient use of multithreading" and I did not realize that it addresses issues of correctness besides issues of efficiency.