# How to do pair switching logic in AFL?

Hi All -
I would like to code a simple pair switching strategy in AFL but not sure how to do. I appreciate if any one can provide a sample or pointers. I am new to AFL and below is the code I could come up so far.

System Rules:
If Close > 40 Bar MA then exit from Pair Symbol and Buy current symbol.
If Close < 40 Bar MA then exit current symbol and Buy Pair Symbol.
Pair Symbol = IEF ; WatchList = SPY, MDY, IJH

Code:

``````// Overall Settings
SetOption("InitialEquity",					100000		);
SetOption("MinShares",						100 		);
BuyPrice = SellPrice = ShortPrice = CoverPrice = Open;

// Detect watchlist & Set Position Size.
wlnumber		= GetOption( "FilterIncludeWatchlist" );
watchlist		= GetCategorySymbols( categoryWatchlist, wlnumber );
numAssets		= StrCount( watchlist, "," ) + 1;
PositionSize = 100/numAssets;
SetPositionSize(PositionSize,				spsShares 	);

// System Rules:
// If Close > 40 Bar MA then exit from Pair Symbol and Buy current symbol.
// If Close < 40 Bar MA then exit current symbol and Buy Pair Symbol.
// Pair Symbol = IEF ; WatchList = SPY, MDY, IJH

pairSymbol = "IEF";
if( Name() !=  pairSymbol)
{
m = MA( Close, 40 );
Buy = Cross( Close, m );
Sell = Cross( m, Close );
}
if(Name() == pairSymbol)
{
// ???
}``````

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;

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;
}

Buy       = rebalance + posSize > 0;
Sell      = 0;
Short     = Cover = 0;
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();
_PortfolioName, "X",
atcFlagDeleteValues | atcFlagEnableInPortfolio );
}

// --- end of code ---
``````
9 Likes

Thanks. I don’t see anything that helps but will read a second time during the week.

Is your goal to use 1/3 of your equity for SPY, MDY, and IJH when they are above their 40-day MA, and to put all unused equity into IEF? So for example, if SPY and MDY both close below MA(C,40), then you would have ~33.3% of your equity in IJH, and ~66.6% of your equity in IEF?

@TrendXplorer

very nice piece of code and interesting link to the SA article.
And I like also your very clear and easy to read coding style.

Did you do additional tests on other pairs (I saw the screencast for QQQ-IEF)?

1 Like

@beppe

Actually I did, for TQQQ and UST see two comment earlier 2 Likes