6.2 Strategy Implementation

The final step is implementing this strategy to create a signal. Let’s begin by reading in the aggregate indicator and return files to our R studio workspace.

x <- mat.read(indicator.file) # GET ACTIVE/PASSIVE INDICATOR C:\\EPFR\\monthly\\ActPasSector-US-monthly.csv
y <- mat.read(ret.file)  # GET TOTAL RETURN INDEX C:\\EPFR\\returns\\PsuedoReturns-Sector-US-daily.csv

Before the data is ready, we will first need to apply the mat.daily.to.monthly() function to ensure that the return data is correctly indexed by month, as mentioned previously (help: ?mat.daily.to.monthly()).

y <- mat.daily.to.monthly(y, T)

Now, we will need to ensure that the data structure in \(x\) and \(y\) are completely aligned, having the same column names in the same order. Below we will subset the columns of \(x\) to use the same sectors, in the same order as \(y\).

x <- as.matrix(x[, dimnames(y)[[2]]]) # LINE UP INDICATORS WITH RETURNS         

* Note: subsetting can also be done when creating the indicator and return files

6.2.1 Moving Sum of Indicator

Next, we set up a variable for our lookback period. This variable will be the window of time across which we smooth the signal for each country. The lookback period we choose for our demonstrations is 12 months.

lookback <- 12 # LOOKBACK (IN MONTHS)               

Now, using the function from the library('EPFR.r'), called compound.flows() we compute the moving sum of our signal over the trailing lookback period for each sector.

x <- compound.flows(x, lookback, T) # COMPUTE MOVING SUM
CDisc CStpls Engy Fins HCare Indls Tech Matls Telco Utes REst FinsExREst
202201 -0.7156276 -3.125668 -0.9110936 -0.1612643 0.7458485 0.4150336 -0.0528877 -0.8602142 13.83616 -5.061333 -7.300732 1.477671
202202 -0.6835107 -3.150278 -0.8738219 -0.1801454 0.7784470 0.4498826 -0.0339342 -0.9024594 13.76228 -5.126640 -7.300896 1.465128
202203 -0.6527746 -3.131600 -0.8590385 -0.2299449 0.8278040 0.4885882 -0.0236669 -0.9417546 13.69471 -5.135598 -7.278306 1.414010
202204 -0.6246197 -3.117799 -0.8779855 -0.2713483 0.8958192 0.5136460 -0.0101432 -1.0076511 13.46132 -5.139532 -7.247421 1.379699
202205 -0.5895009 -3.091071 -0.9465558 -0.2888459 0.9546409 0.5523154 -0.0025015 -1.0194861 13.05166 -5.119721 -7.202301 1.368803
202206 -0.5606572 -3.059903 -1.0011090 -0.3213590 1.0281215 0.5902327 -0.0017198 -1.0372759 12.56834 -5.085358 -7.162568 1.340906

6.2.2 Total Return Index

We will now convert our percentage returns data \(y\) to total index returns indexed so that time moves forward. To do this, we will use the function ret.to.idx() from library('EPFR.r'). We also use the functions map.rname() to ensure the row names of the matrices line up with our flow file and ret.idx.gaps.fix() to replace any NA values. Please refer to the library documentation for the complete list of parameters for these functions (tip: ?ret.to.idx(),?ret.idx.gaps.fix() ).

y[is.na(y)] <- 0
y <- ret.to.idx(map.rname(y, dimnames(x)[[1]])) # CONVERT TO A TOTAL-RETURN INDEX
y <- ret.idx.gaps.fix(y)

6.2.3 Ranking Sectors

Next, we sort each of the sectors in our country or region into five equal bins based on the last 12-month active/passive indicator values for the selected holding period. To do this, we will use the function from library('EPFR.r'), called bbk(). This function will output a standardized backtest result.

The bbk() function requires our 12-month active/passive indicator and the total return index data. Please refer to the library documentation for the complete list of parameters of this function (tip: ?bbk()).

The first parameter we add is the number of bins we want to use. For our case, we want to use 5 because our strategy is to go long the top fifth and short the bottom fifth.

nBin <- 5 # NUMBER OF BINS

Since EPFR data is published with a T+23 day lag and is released around 5:00 pm EST, we account for a T+1 month delay in our model.

delay <- 1 # DELAY IN KNOWING DATA (IN MONTHS)  

The day of the week the rebalancing occurs is at the user’s discretion, but for this example we will set the day of the week to trade as N/A.This allows the bbk() function to default to monthly-indexed returns, and avoids trading on a specific weekday on each rebalancing date.

doW <- NULL # DAY OF THE WEEK YOU WILL TRADE ON (5 = FRIDAYS)

Additionally, we also evaluate the returns for different holding periods. The user can input return the horizons that they are interested in here. For this example we define a return horizon for monthly, quarterly, semi-annual, and annual rebalancing, but is it important to note that this model can be re-balanced as desired.

hz <- c(1, 3, 6, 12) # RETURN HORIZON (IN MONTHS)

Now that we have defined all of our inputs, to rank the sectors into quintiles by their 12-month active/passive indicator, we call the function bbk() for a one-month holding period.

z <- bbk(x, y, 1, hz[1], nBin, doW, T, 0, delay)

6.2.4 Model

12-month cumulative indicator ranked into quintiles (computed only where forward returns are available)

z[["bins"]]
CStpls Engy Fins HCare Indls Tech Matls Telco Utes REst
202210 4 4 1 2 2 3 3 1 5 5
202209 4 4 1 2 2 3 3 1 5 5
202208 4 4 1 2 2 3 3 1 5 5
202207 4 3 1 2 2 3 4 1 5 5
202206 4 3 1 2 2 3 4 1 5 5
202205 4 3 1 2 2 3 4 1 5 5

Quintile returns over the equal-weight universe

z[["rets"]]
Q1 Q2 Q3 Q4 Q5 TxB uRet
202210 0.35854 -0.28226 1.26739 -1.06981 -0.27386 0.63240 2.65916
202209 -0.49311 0.20504 -0.48991 0.70189 0.07609 -0.56920 -0.54724
202208 -0.01306 -0.15416 -0.19726 -0.19001 0.55449 -0.56755 -0.93719
202207 0.35149 0.04659 -0.15981 -0.34411 0.10584 0.24565 -0.65964
202206 -0.53526 -0.53911 1.35414 0.27024 -0.55001 0.01475 1.24731
202205 -0.26872 0.70828 -1.14077 -0.39587 1.09708 -1.36580 -0.68743

Def: TxB represents summary statistics for the long/short portfolio (top - bottom = Q1 - Q5 = overall portfolio returns)


6.2.5 Performance

Go long the top basket and short the bottom basket.

Performance over all holding periods

fcn <- function(retW) {as.matrix(bbk(x, y, 1, retW, 5, NULL, T, 0, delay)$summ)} # DEFINE SUMMARY FUNCTION  

sapply(split(hz, hz), fcn, simplify = "array") # WRITE SUMMARIES
Q1 Q2 Q3 Q4 Q5 TxB uRet
Monthly
AnnMn -0.6 0.0 0.1 -0.5 0.8 -1.3 -1.2
AnnSd 1.3 1.7 1.8 1.7 2.0 2.7 3.5
Sharpe -42.9 -1.6 7.9 -31.4 37.2 -49.5 -34.5
HitRate -3.3 3.3 -1.9 -9.3 7.8 -5.6 -3.7
Beta NA NA NA NA NA NA 1.0
Alpha NA NA NA NA NA NA 0.0
DrawDn -9.5 -5.7 -6.1 -7.4 -5.0 -20.9 -19.5
DDnBeg 201109 201108 201712 201110 202001 201108 201304
DDnN 84 102 54 74 6 101 114
AnnTo 48 93 137 84 48 97 0
Quarterly
AnnMn -0.6 0.2 0.1 -0.7 0.8 -1.4 -1.3
AnnSd 1.3 1.4 1.6 1.8 1.7 2.3 3.3
Sharpe -44.8 11.6 7.6 -37.2 46.5 -60.4 -40.5
HitRate -11.7 -1.1 2.6 -12.4 12.4 -16.2 -10.5
Beta NA NA NA NA NA NA 1.0
Alpha NA NA NA NA NA NA 0.0
DrawDn -9.7 -3.8 -5.4 -8.1 -4.2 -21.3 -18.5
DDnBeg 201139 201374 201743 201109 201941 201139 201303
DDnN 28 17 15 35 2 32 38
AnnTo 39 75 90 55 25 64 0
Semi-Annual
AnnMn -0.7 0.3 0.1 -0.9 0.9 -1.6 -1.3
AnnSd 1.4 1.2 1.7 1.9 1.9 2.5 3.2
Sharpe -49.6 23.0 5.1 -44.5 50.2 -65.5 -40.3
HitRate -16.1 8.5 -2.3 -17.0 19.3 -21.5 -11.0
Beta NA NA NA NA NA NA 1.0
Alpha NA NA NA NA NA NA 0.0
DrawDn -9.8 -2.4 -4.1 -10.4 -3.7 -22.2 -17.7
DDnBeg 201125 201591 201642 201160 201925 201141 201288
DDnN 14 7 4 19 2 16 19
AnnTo 37 69 69 48 24 62 0
Annually
AnnMn -0.6 0.3 0.3 -0.9 0.9 -1.5 -1.2
AnnSd 1.4 1.5 1.7 1.6 1.7 2.5 3.4
Sharpe -45.6 22.6 13.7 -57.0 56.7 -62.1 -34.5
HitRate -16.1 0.5 -2.3 -12.0 30.6 -33.1 -9.0
Beta NA NA NA NA NA NA 1.0
Alpha NA NA NA NA NA NA 0.0
DrawDn -8.2 -2.3 -2.9 -10.7 -2.8 -19.4 -15.1
DDnBeg 201165 201523 201606 201340 201932 201165 201540
DDnN 7 3 2 8 2 8 7
AnnTo 31 54 44 40 24 56 0

Annualized mean one-week returns

bbk(x, y, 1, hz[1], 5, NULL, T, 0, delay)$annSumm # DISPLAY CALENDAR-YEAR RETURNS
Q1 Q2 Q3 Q4 Q5 TxB uRet nPrds
2011 0.1 -2.1 -4.2 -1.2 3.3 -3.1 0.0 4
2012 -1.8 -1.0 0.3 -0.1 0.5 -2.2 2.9 12
2013 0.3 -0.4 0.8 0.0 1.6 -1.3 -2.6 12
2014 0.0 -2.6 0.7 -0.8 2.0 -2.0 -1.1 12
2015 -2.4 1.8 1.6 -2.2 0.7 -3.1 -3.3 12
2016 -1.6 -1.2 2.6 -1.5 1.6 -3.2 3.4 12
2017 -2.2 1.7 1.3 -1.8 0.9 -3.1 1.0 12
2018 -1.1 0.8 -0.1 1.4 -1.0 -0.1 0.8 12
2019 -0.2 -3.7 -1.5 1.4 4.0 -4.3 0.3 12
2020 1.6 3.6 -2.3 0.2 -3.2 4.8 -5.5 12
2021 1.9 1.1 -1.0 -2.3 0.4 1.5 -7.1 12
2022 -1.0 0.3 0.6 0.3 -0.1 -0.9 -2.7 11