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.csvBefore 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()).
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\).
* 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.
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.
| 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() ).
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.
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.
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.
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.
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.
6.2.4 Model
12-month cumulative indicator ranked into quintiles (computed only where forward returns are available)
| 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
| 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
| 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 |