The vast majority of AFL functions operate on single security prices. The are two exceptions from this rule provided by RelStrength() and Foreign() functions. These two functions allow you to use other security prices in the AFL formula. Although these functions are very useful for things like relative performance charts, they are not so useful for tasks requiring prices of all securities (or a large number of securities) because one would need to type several hundreds of Foreign() function calls to do so. Moreover this approach would require listing all the ticker names within the formula which makes the formula tight to particular market. We obviously need completely different approach...
Just imagine if we were able to store the results of calculations performed
on single security somewhere and then use those partial data to generate some
multiple security indicator. You may say that one can create the exploration,
then export the results to the CSV file, then load it into Excel and then perform
the calculations there. It would work (in some cases) but you have to agree
that the solution is not nice.
This is the area where AddToComposite function can help.
Bascially the concept behind AddToComposite is that we run our formula (using Scan feature) through a group of symbols performing some calculations. We will compute some multiple security statistics and store the results in the artificial ticker created using AddToComposite function.
2.3 The solution
The key to the solution is the following algorithm:
When the above procedure is repeated over a group of symbols our composite ticker will contain the sum of results of individual symbol calculations.
Step 2 described above is implemented entirely inside AddToComposite function:
|SYNTAX||AddToComposite( array, "ticker", "field", flags = atcFlagDefaults )|
Allows you to create composite indicators with ease.
possible field codes: "C" - close , "O" - open, "H"
- high, "L" - low, "V" - volume, "I" -
open interest, "X" - updates all OHLC fields at once, "1"
- aux1 field, "2" - aux2 field
AddToComposite function also detects the context in which it is run
|EXAMPLE||AddToComposite( MACD() > 0, "~BullMACD", "V");
graph0 = Foreign("~BullMACD", "V");
(now you can use the same formula in scan and indicator)
AddToComposite function opens up a huge variety of interesting applications. The following examples will help you understand what you can do with AddToComposite function.
Let's say we want to create custom index (average of prices of multiple tickers). With AddToComposite function you can do this fairly easy:
/* AddToComposite statements are for analysis -> Scan */
/* add Close price to our index OHLC fields */
AddToComposite(Close, "~MyIndex", "X" );
/* add one to open intest field (we use this field as a counter) */
AddToComposite( 1, "~MyIndex", "I" );
buy = 0; // required by scan mode
/* this part is for Indicator */
graph0 = Foreign( "~MyIndex", "C" )/Foreign( "~MyIndex", "I" );
You should use above the formula in the Analysis -> Scan mode (over the group of symbols of your choice). This will create "~MyIndex" artificial ticker that will contain your index.
Shortly this formula just adds Close price to OHLC fields (the "X" field stands for all OHLC) of our artificial ticker ~MyIndex. Additionally we add "1" to "I" (open interest) field - effectivelly counting the number of symbols scanned. We can use symbol count later on to divide the sum of prices by the number of symbols included ( the last line of the formula above ).
In the second example we will show how to calculate the indicator that shows the number of symbols meeting certain criterion. In this example this would be RSI less than 30 (oversold condition), but it can be anything you like.
So the first line of our formula will be:
values = rsi() < 30;
This will store "true" in the values array for all date points when RSI is less than 30. Then we add regular AddToComposite part:
buy = 0; // do not generate signals
AddToComposite( values, "~MyComposite", "V" );
If we run the formula using "Scan" function of the Analysis window the result would be an artificial symbol "~MyComposite" filled with quotations. The Volume field of those quotes will contain the number of symbols meeting our criterion (RSI<30) in the population of scanned symbols.
You can easily see the chart of this new "indicator" using the following custom formula:
graph0 = foreign("~MyComposite", "V");
High values of this "indicator" show that most of the symbols in the analysed group are oversold. This usually happens before a great rise of the whole market. We just created market-wide oversold detector!
In the third example I will show you how to use the same technique to count the number of open positions of your trading system. This is useful if you want to know how big account would you need to trade your system following all the trades. Our formula will be very similar to the one before.
First we should have our original trading system formula:
/* Your original formula here */
/* In this example this is simple macd/signal crossover system)
buy = cross( macd(), signal() );
sell = cross( signal(), macd() );
/* the following line uses Flip function to get "1" after the buy signal and reset it back to "0" after sell appears. */
in_trade = flip( buy, sell );
AddToComposite( in_trade, "~OpenPosCount", "V" );
We use "~OpenPosCount" artificial ticker to store the results. Again we should run just Scan of the formula and the "~OpenPosCount" ticker would become available.
graph0 = foreign( "~OpenPosCount", "V");
after running the back-test to see the chart of the number of open positions of your system.
For mode details on composites check "Introduction to AddToComposite" (122KB PDF) by Herman van den Bergen.
Please note that to update any composite ticker (for example after adding/editing quotes) you should run "Scan" again.
The idea was originally presented in the 12/2001 issue of AmiBroker tips newsletter. Special thanks to Mr. Dimitris Tsokakis for very constructive discussions that allowed creation and enhancements of this idea.