Need to reference Amibroker Price array inside backtester

It appears that inside the backtester object where the block "if (Status("action") == actionPortfolio)" starts, all AFL price arrays information (O, C, H, L, etc) are not available, AFL functions are of course available if I want to use them. I would like to store these price array information into, inside and through the backtester object, because I want to use these information to calculate, say, the Van Tharp stop loss risk amount (R) in variable distance (not a straight line percentage constant distance stop loss which would be relatively easy to implement) inside a closed trade object where I need to reference High, Low prices in AFL price array so I can calculate this variable stop loss amount accurately and show it in the analysis window plus later on use it for other calculations. Therefore, I need to code the line trade.AddCustomMetric("OneR Risk amount", whatever the amount turns out to be);. I tried filling up a custom array outside the backtester, and then try to see if I can see these array elements inside the backtester, I can. However, if I setup an array of the same size as the price array and then fill the price array into this new price-copied array to see if I can see the prices inside the backtester via the price-copied array, this time I cannot (it appears Amibroker is still referencing the original price array even from the price-copied array, almost as if referring to it by reference). So my question is, is there a way to freeze the price array information into the price-copied array by using some sort of AFL function such as "copy by value function", freeze it, and then use it inside the backtester. Thanks.

There are plenty of ways to get price information during Phase 2 of a backtest. One is to use static variables, as you've already mentioned. Just make sure to include the ticker symbol as part of the static variable name so that you can retrieve symbol-specific data from the CBT, such as:

StaticVarSet(Name()+"AvgPrice", (O+H+L+C)/4);

The trade object also has a GetPrice method that can be used to retrieve a specific price from a specific bar, for example:

pClose = trade.GetPrice(bar,"C");

In addition, you can use Foreign() and SetForeign inside the CBT, though you should do this sparingly as these are time-consuming calls that will slow down your backtest if you call them indiscriminately.

Moderator comment: should NOT use Foreign and definitelly NOT SetForeign() inside custom backtest code because "current" symbol in CBT is and must be Equity and doing SetForeign is big no-no. Recommended ways is using trade.GetPrice or StaticVarGet

4 Likes

Wondering if someone can help me here.
In my trading system I want to limit my position size to ensure that the turnover of a share (ma(c*v,20) is at least 50 times the turnover of my position size.

I have used van tharp position sizing to calculate my position size, using my initial stop value and entry price, or 5% of my equity, whichever is smaller. See below:

FT3_RiskPerShare = FT3_InitialStopMultiple * Ref(ATR(14),-1); // The initial stop loss width is X times the previous day's ATR
FT3_PctSize = FT3_PercentRiskPerTrade * BuyPrice / FT3_RiskPerShare; // Set the % risk per share value
ApplyStop(stopTypeLoss,stopModePoint,FT3_RiskPerShare,2,False); // Set the initial stop loss on the chart and exit next bar on open if it is touched by the low of the day

PositionScore = (C-Ref(C,-FT3_PositionScoreLookback))/Sum(abs(C-Ref(C,-1)),FT3_PositionScoreLookback); // Give highest priority to the stocks that are moving the most smoothly

switch(FT3_SelectBacktestStyle) // This switches between the position sizing models depending on the backtest style selected at the top of this system file
{
case 1:
SetOption("InitialEquity", FT3_EquityForBacktesting);
SetPositionSize(Min(FT3_MaximumExposurePerTrade,FT3_PctSize),spsPercentOfEquity); // Calculate the position size for backtest based on percent of equity
break;
case 2:
SetOption("InitialEquity", FT3_EquityForUnconstrainedCapital);
SetPositionSize(1000, spsValue); // Calculate the position size for constant $1000 per trade
break;
case 3:
SetOption("InitialEquity", FT3_EquityForUnconstrainedCapital); // NOTE: This is not a mistake - This is set to a high number so you don't miss any signals
SetPositionSize(Max(500,(Min(FT3_EquityForPositionSizingFT3_MaximumExposurePerTrade/100,FT3_PctSizeFT3_EquityForPositionSizing/100))), spsValue); // Calculates the position size based on your current equity for position sizing taking into account minimum ASX purchase size
break;
}

However I also want to limit entries to be position sized at 1/50th of the turnover (MA(cv,20)) to make sure I'm only entering positions that are liquid enough.
I have added this code calling the custom backtester, but it is getting tripped up on my use of an array in the backtester -> I am referencing the MA(c
V,20) -> can anyone help me store the turnover in the backtester as a variable so I can call it in.

My backtester code is:
//==================================================================================================================================//
// Set custom backtester to limit entries to 1/50th of daily turnover over the past 20 days
//==================================================================================================================================//

SetCustomBacktestProc("");

if (Status("action") == actionPortfolio)
{
bo = GetBacktesterObject(); // Get backtester object
bo.PreProcess(); // Do pre-processing (always required)

for (i = 0; i < BarCount; i++)	//  Loop through all bars
{
    for (sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) )
    {	
        if (sig.IsEntry()) // entry signal
		{
			eq=bo.Equity;
							
			if(sig.PosSize*50 > MA(C*V, 20)) sig.PosSize=(1/50)*MA(C*V,20);
		
							
			
		}	
    }	
    
    bo.ProcessTradeSignals( i );	//  Process trades at bar (always required)
}	  
  
bo.PostProcess();	//  Do post-processing (always required)

}

thanks in advance

When posting the formula, please make sure that you use Code Tags (using </> code button) as explained here: How to use this site.

Using code button

Code tags are required so formulas can be properly displayed and copied without errors.

Thanks Tomasz, my first post, I was wondering about that!
Catsup

The answer is in the post you responded to. Calculate turnover during Phase 1, store it in a symbol-specific static variable, and retrieve it during Phase 2 (CBT).

2 Likes

Examples are in the Knowledge Base:

You should either use trade.GetPrice() or StaticVarGet. Do NOT use SetForeign.

In your specific example, you should do all calculations in first phase, calculate your LIMIT already in first phase and store in static variable then use StaticVarGet in CBT to retrieve that limit calculated earlier . Exactly as shown in the Knowledge Base.