financialnoob.me

Blog about quantitative finance

Quasi-multivariate pairs trading

This article is based on a paper ‘M of a kind: A Multivariate Approach at Pairs Trading’ (Perlin, 2007). In this paper author proposes using an artificial portfolio of assets to generate trading signals for a particular stock. It is not a pairs trading strategy in a traditional sense because we only trade one asset of a constructed pair. Another asset (artificially constructed portfolio) is used to estimate whether the target asset is overpriced or underpriced. Similar approach was used in another article — ‘Pairs trading with Support Vector Machines’.

The paper is quite old, so I will use old data for a backtest —from 2003–01–01to 2005–12–31. First two years are used as a formation period and trading is done during the third year. As my stock universe I’m going to use 100 assets from VBR Small-Cap ETF with the highest mean daily trading volume during the given period. The list of used stocks is provided below.

['TRN', 'BDN', 'CMC', 'NYT', 'LEG', 'VNO', 'HLX', 'ORI', 'HP', 'EQC', 'MTOR', 'DKS', 'SEE', 'EAT', 'AGCO', 'AIV', 'WSM', 'BIG', 'HFC', 'AN', 'ENDP', 'OI', 'FFIV', 'AXL', 'VSH', 'NCR', 'MDRX', 'UIS', 'CRUS', 'FLR', 'MUR', 'ATI', 'PBI', 'PWR', 'TEX', 'RRC', 'FL', 'NVAX', 'LPX', 'CMA', 'AMKR', 'RMBS', 'MFA', 'ZION', 'HOG', 'UNM', 'IVZ', 'NWL', 'GME', 'JWN', 'NUAN', 'ANF', 'FHN', 'JBL', 'URBN', 'PBCT', 'HRB', 'LNC', 'RDN', 'TGNA', 'NYCB', 'WEN', 'CNX', 'STLD', 'TOL', 'BBBY', 'APA', 'MAT', 'BPOP', 'KBH', 'PTEN', 'SANM', 'DVN', 'MOS', 'OVV', 'TPR', 'CLF', 'AEO', 'KSS', 'SWN', 'MTG', 'GT', 'NOV', 'CDE', 'IPG', 'JBLU', 'THC', 'ODP', 'RIG', 'SNV', 'M', 'ON', 'GPS', 'X', 'MRO', 'XRX', 'JNPR', 'CAR', 'RAD', 'SLM']

For each stock we need to construct an artificial portfolio of assets which we then use to generate trading signals. To do this we first need to normalize stock prices by subtracting mean and dividing by standard deviation. Then we use normalized prices of each stock to calculate the sum of squared distances (SSD) with all other stocks. The stock (or several stocks) with the minimum SSD is selected as a partner. Alternatively we can calculate correlation coefficients between normalized price series and select assets with the highest correlation coefficients. It is claimed in the paper that both methods produce the same results. Let’s try to check that.

First we load and prepare the data.

I will use only the first stock (TRN) to compare stocks selected based on SSD with stocks selected based on correlation coefficient.

First we calculate correlation coefficients of TRN with all other stocks and sort them in ascending order. Here we are interested in pairs with the highest correlation coefficient.

Top 5 pairs (correlation)

Then we calculate SSD between TRN and all other stocks and sort the results in descending order since we are interested in pairs with the smallest SSD.

Top 5 pairs (SSD)

Indeed we can see that both methods produce the same pairs. I will use correlation method for the rest of this post.


The idea behind this trading strategy is that we can decompose price series of a target asset using prices series of other (similar) assets as follows:

Decomposition of asset price

The price of a given asset is assumed to be equal to a weighted sum of other similar assets (artificial portfolio) and an error term.

Similar assets for each stock are selected as shown above (either by SSD or correlation coefficient). The number of assets to use in decomposition (m) can be either static or dynamic. In the paper static value m=5 is used. There are also different approaches for calculating weights of each asset in the portfolio. Three approaches are tested in the paper — Ordinary Least Squares (OLS), equal weighting and correlation weighting schemes. I am also going to implement and test all of them.

After constructing a portfolio trading signals are generated based on the value of epsilon (last term in the equation above). If it is positive (negative), the target asset is overpriced (underpriced) and we should take a short (long) position.

We need to determine which value of threshold d to use. Author tested many different values of this parameter for opening positions, but I think it is unnecessary and can lead to overfitting. We can see on Table 1 on the paper that values of d between 1.8 and 2.0 provide acceptable results for all weighting methods and beat 100% of returns of random portfolios. Moreover I have more stocks in my universe (100 vs. 57 in the paper), so there should be more trading opportunities for large values of d. I will use d=1.9 for my tests. The rules for closing positions are not provided. I assume that position is closed when the conditions above stop to be true. Now we have all the information required to perform a backtest.


I am going to start with OLS weighting scheme. The normalized price of the traded asset will be a dependent variable and normalized prices of assets in the artificial portfolio will be independent variables. Note that no algorithm is provided for selecting several ‘best’ assets for trading, therefore we build artificial portfolios for each of 100 stocks in the universe and follow the rules for opening and closing positions whenever the trading opportunity arises. Since we can’t know beforehand how many positions we will have on any given day, I will start with allocating equal amount of capital to each of the stocks. Code for running a backtest if provided below.

Each stock is processed separately. Every day we use the mean and variance from the last 494 trading days to calculate normalized price series. Every 10 days we update the stocks in the portfolio and their weights. Then the value of the spread (epsilon) is calculated and positions are opened if it is large enough. Below is the plot of cumulative returns of this strategy.

Cumulative returns (OLS weighting)

The results above don’t look very promising. But if we look at the positions dataframe we can see that the amount of trading opportunities is very low. We never have a lot of positions opened on any given day and most of the capital is not used (because equal amount of capital is allocated to each of the stocks). Let’s see what happens if we limit the amount of positions on any given day to 3. That way one third of the total capital will be dedicated to each position. Basically on each trading day we start analyzing stocks one by one and stop as soon as we have 3 trading opportunities. If we have less than 3 positions, still only one third of the total capital will be allocated to any position we have. It can be done easily with 3 lines of code.

Cumulative returns (OLS weighting), max 3 positions

This looks a lot better. Total return is somewhere between 25% and 30%. I think that it can be improved even more if we develop some better way of capital allocation. Please note that for the sake of simplicity I didn’t include any transaction costs.

Two strategies are proposed in the paper to evaluate the performance of the algorithm — naive portfolio method and bootstrap method. I want to use a bootstrap method, but it is not clear to me how exactly it was implemented in the paper. The idea is calculate the total number of long\short positions and their lengths and then use that information to construct a random portfolio with the similar number of positions of similar length. We do it many times and calculate the probability that total return of the strategy can be beaten by the total return of a random portfolio.

I will implement something similar:

  • For each column (stock) in the positions dataframe I calculate the number of long\short positions and lengths (in days) of each position.
  • Then I shuffle the positions within the column, so that I have exactly the same positions with the same length, just starting at completely random times.
  • After that shuffle the columns to get new positions dataframe which I can use to calculate returns.

Code for doing it is shown below.

Let’s look at the performance metrics of two versions of the algorithm tested so far.

Performance metrics

As you can see the returns of both versions of the strategy are better than 99% of random trading portfolios. This indicates that it is highly unlikely to get such results by pure chance. On the histogram below we can clearly see that returns from random trading are symmetrical around zero. The vast majority of them are lower than total return of the strategy (indicated with red line).

Histogram of random (bootstrap) returns


Let’s test another weighting method — equal weighting. Code is shown below. The only difference is in calculating weights (line 16).

Cumulative returns (equal weighting)

We can see above that performance of the algorithm with equal weighting is a little bit better than with OLS weighting. But here again the capital is equally divided among 100 stocks, so that each position uses only 1/100 of the total capital. Let’s repeat the experiment with limiting the number of positions to 3.

Cumulative returns (equal weighting), max 3 positions

Performance is improved and total return is almost twice as high as the that of the similar strategy with OLS weighting. Other performance metrics are shown below.

Performance metrics


Now let’s test correlation weighting scheme. The idea is to assign weights that are proportional to the correlation coefficient between normalized prices of target asset and given asset in portfolio. And also we need to make sure that weights sum to one. Code for it is shown below. Again, the difference is only in calculating weights (line 16).

Cumulative returns (correlation weighing)

Cumulative returns we get are quite similar to the ones we got with equal weighting scheme. I will also try to limit the number of positions to 3.

Cumulative returns (correlation weighing), max 3 positions

Finally, let’s look at the metrics of all tested strategies together.

Performance metrics

We can see above that correlation weighting scheme gives the best results. Equal weighting gives similar results, which are a little worse than with correlation weighting (probably due to chance). The worst of all is OLS weighting scheme. The reason for this is probably that OLS algorithm is not suitable for highly correlated independent variables. Maybe using other algorithm (for example ridge regression) can improve the performance.

All algorithms outperform trading on random signals (from bootstrap). I believe that returns of algorithms with limited number of positions would still be profitable even with transaction costs. It would be interesting to test this strategy on more modern data.


Jupyter notebook with source code is available here.

If you have any questions, suggestions or corrections please post them in the comments. Thanks for reading.


References

[1] M of a kind: A Multivariate Approach at Pairs Trading (Perlin, 2009)

[2] Statistical arbitrage pairs trading strategies: Review and outlook (Krauss, 2015)

Leave a Reply

Your email address will not be published. Required fields are marked *