Problem with User Function in Portfolio explorations

I need to create user functions for use in portfolio explorations/backtests/etc.

I decided to write a simple EMA user function to test. My code is included below. My problem is that my user function in exploration only returns the EMA values for the first symbol in the portfolio and not from all symbols. If I use the AB EMA function, the emas for all symbols in the portfolio are returned in exploration. How do I get all symbols returned in my user function exploration? Is a loop over symbols required? Or what?

I tried to write simple AFL array code instead of loops:

"Result = betaref(Result,1) + alpArray; "

But I got an error: "Not Initialized". I don't know how to initialize in this coding approach?

Which is the recommended coding method?

Thank you.

function emaT(array, emaN)
	alp = 2/(1+emaN); // alpha
	beta = 1 - alp;
	Result[0] = array[0];
	for( i=1; i<BarCount; i++ )
			Result[i] = beta*Result[i-1] + alp*array[i];
	return Result; 
BuyPrice = Close; 
SellPrice = Close; 
PosQty = 1;
SetOption( "MaxOpenPositions", PosQty ); 
SetOption("WorstRankHeld", PosQty);
SetPositionSize(100/PosQty,spsPercentOfEquity); // invest 100% of equity in single security 
EMAValue = emaT(C,10); 
Filter = 1;

  1. User functions work the same as built-in function and surely would work on ALL symbols, if only you change "Apply to:" setting to ALL symbols. Recommended reading: How do I debug my formula?

  2. alpArray is NOT assigned to anywhere in your code, only alp so you have missing asterisk (*) and that is why you getting error

  3. array code is just EMA(array, emaN ), or AMA( array, 2/(1+emaN) )

  4. the fact that you wanted to use Ref() means that you don't understand how AFL works, recommended reading and Doubt when using self referencing

Thank you for your answer.

  1. With the excellent help of a very knowledgeable local AB user, my problem has been solved. As others may have this insidious problem, the solution was to disable the pad and align (with SPY). As the standard AB EMA function worked, it seems obvious that the standard code checks for nulls.
  2. I had extensively read the references you provided prior to coding. In particular, the AMA function. I want to code 2nd and 3rd order iir filters with both poles and zeros. The reason I used the ref() function is because my interpretation of AB documents is that the AMA() only works for standard 1st order ema (no zero). Am I correct? Do you have more information and/or documentation to illustrate?
  3. This algorithm has been coded in Excel/VBA with an external C# dll for portfolio async/await data download and portfolio optimization. The dll optimization does not use multicore/multithreading code. But the dll optimization runs faster than my AB code with the standard AB 1st order EMA function (no loops, I think).
  4. My understanding of your documentation is that loop code will run slower. So I am very interested in understanding AFL array coding to get better performance. Additional guidance on information and documentation to achieve better AB performance with array coding will be appreciated.

Thank you.


Perhaps these links can be of help?

The built in AmiBroker IIR filter,

Code for an article by John Ehlers that introduces his Universal Oscillator that is based on filtering two-day price momentum using second-order infinite impulse response (IIR) filter

Code for another article that has an example of using the built-in IIR function


As @portfoliobuilder wrote, you should just use IIR function for efficient implementation of 2nd and 3rd order filters. And yes pad and align will place Null for nonexisting data at start. That is why it is important to use techniques described here: How do I debug my formula? . Running exploration in many times is eye opening.

1 Like