The following code for a risk parity based paired switching approach was used for a comment on SeekingAlpha:
https://seekingalpha.com/article/3979846-safeguard-equity-portfolio-one-etn-xvz#comment-72444752
Hope this helps,
JW
/* --- RiskParity_PairedSwitching_v1.afl ---
**
** model re-balances TQQQ/UST based on Risk Parity
** trading at the close of every month/quarter/year
** apply with monthly data
**
** version: June 7, 2016
*/
// --- start of code ---
// --- backtester settings ---
SetOption( "CommissionAmount", 0.00 );
SetOption( "InitialEquity", 100000 );
SetTradeDelays( 0, 0, 0, 0 );
SetOption( "MaxOpenLong", 2 );
SetOption( "MaxOpenPositions", 2);
SetOption( "AllowPositionShrinking", True );
SetBacktestMode( backtestRegular );
// --- inputs ---
frequency = ParamList( "Rebalance Frequency:", "Monthly|Quarterly|Annually" );
// --- set lot size ---
RoundLotSize = 0.0001;
// --- detect tradelist ---
wlnumber = GetOption( "FilterIncludeWatchlist" );
watchlist = GetCategorySymbols( categoryWatchlist, wlnumber );
// --- init ---
sumVol = sumPosValue = 0;
// --- position allocation routine ---
if ( Status( "stocknum" ) == 0 )
{
StaticVarRemove( "pos*" );
StaticVarRemove( "ret*" );
StaticVarRemove( "vol*" );
StaticVarRemove( "sum*" );
for ( i = 0; ( symbol = StrExtract( watchlist, i ) ) != ""; i++ )
{
SetForeign( symbol );
ret1m = ROC( Close, 1 );
RestorePriceArrays();
// --- volatility ---
//
// --- match for Excel's STDEV.P ---
vol = StDev( ret1m, 12 );
//
// --- port to Excel's STDEV.S ---
vol = sqrt( vol ^ 2 * 12 / 11 );
//
// --- annualization ---
vol = vol * sqrt( 12 );
sumVol = sumVol + vol;
StaticVarSet( "ret1m" + symbol, ret1m );
StaticVarSet( "vol" + symbol, vol );
}
StaticVarSet( "sumVol", sumVol );
for ( i = 0; ( symbol = StrExtract( watchlist, i ) ) != ""; i++ )
{
vol = StaticVarGet( "vol" + symbol );
sumVol = StaticVarGet( "sumVol" );
posValue = 1 / ( vol / sumVol );
sumPosValue = sumPosValue + posValue;
StaticVarSet( "posValue" + symbol, posValue );
}
StaticVarSet( "sumPosValue", sumPosValue );
for ( i = 0; ( symbol = StrExtract( watchlist, i ) ) != ""; i++ )
{
posValue = StaticVarGet( "posValue" + symbol );
sumPosValue = StaticVarGet( "sumPosValue" );
posSize = 100 * posValue / sumPosValue;
StaticVarSet( "posSize" + symbol, posSize );
}
}
// --- get values and ranks for Momentum ---
symbol = Name();
ret1m = StaticVarGet( "ret1m" + symbol );
vol = StaticVarGet( "vol" + symbol );
posSize = StaticVarGet( "posSize" + symbol );
sumVol = StaticVarGet( "sumVol" );
// --- rebalance ---
if ( frequency == "Monthly" )
{
rebalance = 1;
holdbars = 1;
}
if ( frequency == "Quarterly" )
{
rebalance = Month()%3 == 0;
holdbars = 3;
}
if ( frequency == "Annually" )
{
rebalance = Month()%12 == 0;
holdbars = 12;
}
// --- trade logic ---
Buy = rebalance + posSize > 0;
Sell = 0;
Short = Cover = 0;
BuyPrice = Close;
SellPrice = Close;
// --- set position sizes ---
PositionSize = -PosSize; // "-" sign for spsPercentOfEquity
// --- exit at EoM for rebalancing ---
ApplyStop( stopTypeNBar, stopModeBars, holdbars, exitatstop = 0 );
// --- exploration filter ---
ExploreFilter = ParamToggle( "ExploreFilter", "LastBarInTest|All", 1 );
if ( ExploreFilter )
Filter = 1;
else
Filter = Status( "LastBarInTest" );
// --- sort for exploration only (not on backtest) ---
if ( Status( "actionex" ) == actionExplore )
{
SetSortColumns( 2, 1 );
ColorRet = IIf( ret1m > 0, colorLime, colorRed );
AddColumn( Close , "Close (current)", 1.2 );
AddColumn( Ref( Close, -1 ), "Close (prior)" , 1.2 );
AddColumn( ret1m , "ret1m%" , 3.3, 1, ColorRet );
AddColumn( vol , "Vol (Y%)" , 3.3 );
AddColumn( posSize , "PosSize (%)" , 3.3 );
AddColumn( sumVol , "SumVol (Y%)" , 3.3 );
}
// --- save portfolio equity ---
_PortfolioName = ParamStr( "~~~PortfolioName", "~~~RP" );
SetCustomBacktestProc("");
if( Status("action") == actionPortfolio )
{
bo = GetBacktesterObject();
bo.Backtest();
AddToComposite( bo.EquityArray,
_PortfolioName, "X",
atcFlagDeleteValues | atcFlagEnableInPortfolio );
}
// --- end of code ---