Skip to content

Multi-Timeframe AFL

There is a particular kind of backtest that looks wonderful and is worth nothing. It buys a share on Monday because “the weekly trend is up”, and the number it used to decide the weekly trend was up did not exist until Friday. Nothing in the formula announces this. AmiBroker raises no error. The equity curve simply looks better than any equity curve has a right to look, and the reason is buried in one optional argument.

This part is about writing multi-timeframe formulas that are not that. It is short — three lessons and two projects — and almost all of the difficulty sits in a single idea: a higher-timeframe value has to be attached to the right base-interval bar, and there is more than one way to attach it.

AmiBroker’s Multiple Time Frame support is six functions. You will meet five of them here: TimeFrameSet() and TimeFrameRestore() to switch the built-in price arrays to a longer interval and back; TimeFrameCompress() and TimeFrameExpand() to move a single array between intervals; and TimeFrameGetPrice() to read another interval’s open, high, low, close or volume in one call. The sixth, TimeFrameMode(), belongs with tick and volume bars and is introduced where those are, in the real-time parts.

Along the way you will meet the machinery that makes multi-timeframe work either reliable or irreproducible: the leading-Null layout of a compressed array, Warning 509, the interaction with QuickAFL, and the database settings that decide where one week ends and the next begins.

TimeFrameExpand() has an argument called mode. Its documented default, expandLast, places a completed period’s value on that period’s last bar. The alternative, expandFirst, places it on the period’s first bar — and the official documentation says in as many words that using expandFirst on anything other than the period’s open “may look into the future”, because it lets you know on Monday what the high of the whole week turned out to be.

A great deal of published multi-timeframe AFL has this backwards. Lesson 3 works through exactly why the documentation is right, with a weekly-high example you can reproduce in five minutes on your own data, and gives you a procedure for settling the question on any formula rather than arguing about it.

Daily end-of-day data for a handful of liquid symbols, which is what Part 3 set up. No real-time feed, no intraday database and no Professional edition: every formula in this part compresses daily bars into weekly bars, which the Standard edition does as happily as the Professional one. If you do have intraday data, everything here transfers unchanged to 5-minute bars inside an hourly context — the arithmetic of compression does not care which two intervals you pick, only that the one you compress to is the longer of the two.

You should be comfortable with the material in Part 8 and Part 9: arrays, the fact that one line of AFL produces one value per bar, and Ref(). Part 12’s Exploration workflow is used heavily, because an Exploration table is the fastest instrument available for finding out what a formula is really doing.

Both projects end with a proof, not a demonstration. Each one ships with a deliberately broken switch in its Parameters dialog, so that you can confirm your audit catches a formula you already know to be wrong before you trust it on one you do not. A test that has never failed is not evidence that the thing being tested is sound; it is evidence that the test has not been shown to work.

That habit — build the check, then verify the check has teeth — is worth more than the two indicators you will take away from this part. It reappears in Part 30, where the same reasoning is applied to survivorship bias, dividend adjustment and the other ways a backtest quietly learns things it should not know.

Part14 of 36Level3 — AFL DeveloperPages5Estimated time3.1 hours

0 / 5 lessons in this part completed