A Simple TAA System

This is a simple tactical asset allocation system I wrote in Amibroker AFL as a framework for further development. There are still some bugs – some of the statistics don’t calculate properly for one – but it works more or less as intended.

When I get the time I’ll write about the difficulties of creating a system which is truly agnostic about future market behavior when all the building blocks are mired in the past and unavoidably riddled with assumptions.

Excuse the horrible WordPress reformatting, use some common sense to choose your own parameter values, and have fun!

//TAA ETF Moving Average System with trailing stops
//Fully invested regardless the number of open positions
//Trades once a month, but uses daily data and evaluates stops daily

//strategy parameters/////////////////////////////////////////////////
malen = Param(“ma length”,21,21,252,21);
//malen = Optimize(“ma length”,21,21,252,21);

//execution/trade management parameters///////////////////////////////////////////////
stopperc = Param(“stop %”,2,2,20,1);
//stopperc = Optimize(“stop %”,2,2,20,1);
redelay = Param(“rentry delay”,21,21,126,21);
//redelay = Optimize(“rentry delay”,21,21,126,21);
RoundLotSize = 1;
BuyPrice = C;
dom = Param(“day of month”,1,1,21,1);  //day of month to calculate scores
//dom = Optimize(“day of month”,1,1,21,1);
tradedelay = Param(“trade delay”,0,0,5,1);  //days to delay trading after calculation
//tradedelay = Optimize(“trade delay”,0,0,5,1);

//Portfolio parameters and options///////////////////////////////
Maxposition = Param(“max positions”,1,1,15,1);
//Maxposition = Optimize(“max positions”,1,1,15,1);
Mindiff = Param(“Min diff to rebalance”,.005,0,.10,.0025);
//mindiff = Optimize(“Min diff to rebalance”,.005,0,.10,.0025);
SetOption(“InitialEquity”, 100000);
SetPositionSize(100/Maxposition, spsPercentOfEquity);
SetOption(“UsePrevBarEquityForPosSizing”, True);

//Determine trading day//////////////////////////////////////////////
MonthChange = Month() != Ref( Month(), -1 );
Rebalance = IIf(BarsSince(MonthChange==1)==dom,1,0);

//Rotational trading parameters////////////////////////////////////
PositionScore = IIf (C>MA(C,MAlen), C/MA(C,MAlen), 0);  //If above moving average, rank by % above the moving average
AddToComposite( IIf(PositionScore !=0,1,0) , “~TAAPosCount”, “X”, atcFlagDefaults = 15);  //create artificial security to track number of positive scores
RawCount = Ref(Foreign(“~TAAPosCount”,”C”),-tradedelay);  //Must use count from calculation day to get proper results
PosCount = IIf(RawCount>Maxposition,Maxposition,RawCount); //Final count used for position sizing

//Custom Backtest Procedure/////////////////////////////////////////////////
SetOption(“UseCustomBacktestProc”, True);
if (Status(“action”) == actionPortfolio)
bo = GetBacktesterObject();
bo.PreProcess(); // Initialize backtester
for (bar=0; bar < BarCount; bar++)  //loop through all bars
bo.handlestops(bar);  //For daily stops this is outside the day of month loop
if (rebalance[bar]==1)  // test for day of month to trade
CurEquity = bo.Equity;
if (poscount[bar] !=0)
PositionSize = 1/PosCount[bar] * CurEquity;
for (pos = bo.GetFirstOpenPos(); pos; pos = bo.GetNextOpenPos()) //loop through open postions and rebalance to remain fully invested
posval = pos.GetPositionValue();
diff = posval – PositionSize;
price = pos.GetPrice(bar, “C”);
if (abs(diff[bar])>Mindiff*posval AND abs(diff[bar]) > price AND diff[bar]>0) // do scale outs first
bo.ScaleTrade(bar, pos.symbol, False, price, abs(diff[bar]));
if (abs(diff[bar])>Mindiff*posval AND abs(diff[bar]) > price AND diff[bar]<0)  // do scale ins
bo.ScaleTrade(bar, pos.symbol, True, price, abs(diff[bar]));
} //for scale in/out loop
} //for trading day loop
} //for bar loop
bo.PostProcess(); // Finalize backtester