I have written my first complicated (for me) strategy and I would appreciate any comments that might make it more crisp, compact or better written. I started with the GTAA code from TrendXplorer. I added code to sum the volatility of the top N assets and adjust the position size based on the inverse of the asset's volatility percentage.
It seemed as though I needed the nested loops to check if an asset would be bought and then add its volatility and do that fir each bar but maybe that was more complex than necessary. Also I get a divide by zero warning even though I check for s zero divisor but maybe that expected.
Anyway any suggestions would be appreciated.
Jim
/* TAA-IV - Tactical Asset Allocation w/inverse volatility
**
** My rotational straegy based on the ROC with the position size based on inverse voltility
** based on code from TrendXplorer
** I used symbols SPY, IJR, TLT, EEM, VEA, IEF
*/
// --- begin of code ---
// --- inputs ---
Frequency = ParamList( "Rebalance Frequency:", "Monthly|Bi-Monthly|Quarterly|Annually", 0 );
ROClookback = Param( "ROC lookback (m):", 5, 1, 24, 1 );
VolLookback = Param( "Vol Lookback", 3, 1, 12, 1);
MaxPos = Param( "Max Positions", 3, 1, 6, 1);
// --- detect tradelist ---
Wlnumber = GetOption( "FilterIncludeWatchlist" );
Watchlist = GetCategorySymbols( categoryWatchlist, wlnumber );
// --- backtester settings ---
SetBacktestMode( backtestRegular );
SetOption( "CommissionAmount", 0.00 );
SetOption( "InitialEquity", 100000 );
SetTradeDelays( 0, 0, 0, 0 );
SetOption( "MaxOpenLong", MAxPos );
SetOption( "MaxOpenPositions", MaxPos );
SetOption( "AllowPositionShrinking", True );
SetOption( "AllowSameBarExit", True );
SetOption( "ReverseSignalForcesExit", False );
SetOption( "HoldMinBars", 1 );
SetOption( "ExtraColumnsLocation", 1 );
RoundLotSize = 1;
// --- detect period ends ---
MonthEnd = Month() != Ref( Month(), 1 );
BiMonthEnd = Month()%2 == 0 AND MonthEnd;
QuarterEnd = Month()%3 == 0 AND MonthEnd;
YearEnd = Month()%12 == 0 AND MonthEnd;
// --- init rebalancing frequency ---
if ( Frequency == "Monthly" ) Rebalance = MonthEnd;
if ( Frequency == "Bi-Monthly" ) Rebalance = BiMonthEnd;
if ( Frequency == "Quarterly" ) Rebalance = QuarterEnd;
if ( Frequency == "Annually" ) Rebalance = YearEnd;
Rebalance = Rebalance OR Status( "LastBarInTest" );
// --- init values ---
Value = SumVol = PosPct = Vol = InvVol = 0;
// --- asset selection and capital allocation routine ---
if ( Status( "stocknum" ) == 0 )
{
StaticVarRemove( "*itemScore*" );
StaticVarRemove( "vol*" );
StaticVarRemove( "pospct*" );
for ( i = 0; ( symbol = StrExtract( Watchlist, i ) ) != ""; i++ )
{
SetForeign( Symbol );
// --- calculate ROC ---
Value = ROC( Close, ROCLookback);
RestorePriceArrays();
// --- volatility ---
//
// --- match for Excel's STDEV.P ---
Vol = StDev( Value, VolLookback );
//
// --- port to Excel's STDEV.S ---
Vol = sqrt( Vol ^ 2 * VolLookback / (VolLookback - 1) );
//
// --- annualization ---
// vol = vol * sqrt( VolLookback );
StaticVarSet( "vol" + symbol, Vol );
StaticVarSet( "itemScore" + symbol, Value );
}
// perform ranking
StaticVarGenerateRanks( "rank", "ItemScore", 0, 1224 ); // normal rank mode
// add up the top N ranking stock's inverse volatility
for( i = 1; i < BarCount; i++ )
{
for ( j = 0; ( Symbol = StrExtract( Watchlist, j ) ) != ""; j++ )
{
Vol = StaticVarGet( "vol" + Symbol );
InvVol = 1 / Vol;
Value = StaticVarGet( "itemScore" + Symbol );
rank = StaticVarGet( "rankItemScore" + Symbol );
if( rank[i] <= MaxPos )
{
SumVol[i] = SumVol[i] + InvVol[i];
}
//not sure why this generate a warning since i check for non-zero values
PosPct = IIf( SumVol == 0, 0, 100 * ( InvVol / SumVol));
StaticVarSet( "pospct" + Symbol, PosPct );
}
}
}
// read ranking
Symbol = Name();
Rank = StaticVarGet ( "rankItemScore" + Symbol );
PosPct = StaticVarGet ( "pospct" + Symbol );
PosPct = IIf( Rank > MaxPos, 0, PosPct);
SetPositionSize( PosPct, spsPercentOfEquity);
Buy = Rank <= MaxPos;
Sell = 1;
if (status( "action" ) == actionExplore)
{
value = StaticVarGet ( "ItemScore" + symbol );
Vol = StaticVarGet ( "vol" + symbol );
AddColumn ( Close, "close" );
AddColumn ( Value, "value" );
AddColumn ( Rank, "rank" );
AddColumn ( SumVol, "SumVol" );
AddColumn ( Vol, "Vol" );
AddColumn ( PosPct, "PosPct" );
AddColumn ( Ref(DateTime(), -ROCLookback), "Prev Date", formatDateTime );
AddColumn ( Ref(Close, -ROCLookback), "Priv Close" );
Filter = 1;
SetSortColumns( 2, 4 );
}