Back

Pairs Trading - Copula Method vs Cointegration

I finished a pairs trading strategy based on copula method. Please look into tutorial page for details. In order to compare the performance of copula pairs trading technique, I also implemented a simple cointegration methods for comparison. Leave a comment if anyone has questions or suggestion about my implementation.

Update Backtest






The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.



Hi HanByul, yes this algorithm needs model selection and training period. For the two parameters here,

self.numdays = 1200 # set the length of formation period which determine the copula we use
self.lookbackdays = 250 # set the length of history data in trading period I use 1200 days to train the

history data to find the best fit copula from Archimedean copulas class, and use 250 days to train the chosen copula function to find the best parameter estimation. For pairs trading, when to trade and how many trades each month really depend on if the criteria is satisfied and can't control manually. But for this reason, when there is a trading opportunity for buying the pair(buy first sell second), it could happen that the last trading opportunity is still buying signal, then since you already hold the long position, you have limited money to buy new ones. That's why the quantity decreased dramatically sometimes. But the decreasing trading quantity can be modified by changing the leverage or you can set your own trading rules when there is a pairs trading opportunity.

0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


Jingw, Thank you for your explanation. Regarding the quantity of each leg, I think it's understandable. But I still don't understand why trading from year 2017 (see backtest right above.) looks so disappointing. Compared to the backtest starting 2016, two results are not giving me any level of confidence. If I deployed this algo in Jan. 2017, I would've gotten so bad result. However, if I did in Jan. 2016, it would've been totally a different story. What do you think? Is there any other way to improve regarding this aspect? How will this algo go in live trading? Thanks :) 

0

HanByul, It is reasonable. As in algorithm, we just choose copula once and use this copula in the following days. The only thing that changes is the parameter of that copula. Your backtest starting from 2016 and starting from 2017 use the different history data to choose the copula, they might choose the different copula and the algorithm will use this copula for the following backtesting. You can control the copula you use by ignoring the copula selection process to reach the same result.

0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


Jingw, Thanks for all the answers and explanation. I will dig into more about 'copula' method and see if we can implement for multi-pairs instead of picking one pair (If you've already done for multi-pairs, please let us know. I appreciate it.). Again, thank you for your great work and the opportunity to explore the 'copula' method.  :)

0

your universe is: tick_syl =  [["SPY","AGG","XME","TNA","FAS","XLF","EWC","QLD"],
                                         ["DIA","JNK","EWG","TLT","FAZ","XLU","EWA","QID"]]

as a non-programmer, I'm wondering if I can replace names here and run backtest with my names?  I've tried and gotten errors

0

If for a Gumbel copula we get a combination of (u,v) of (1,1) -> the pdf of your algorithm returns an infinity value.

0

Hi Dennis,

When (u, v) -> (1, 1), log(u) and log(v) are zero so the Gumbel pdf will be "inf". u and v are  constructed with the empirical distribution function from the log return series, there must be a 1 in u or v. Therefore, in the original algorithm I try to convert the infinity value to the finite number with

# Replace nan with zero and inf with finite numbers in lpdf list 
lpdf = np.nan_to_num(lpdf)

The finite numbers are still huge so the sum would be inf. A better solution would be converting the 1 in u or v to a number less than 1 for example 0.9999.

0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


Hi,

I cloned the file and tried to run a backtest but its giving me an error

During the algorithm initialization, the following exception has occurred: TypeError : 'numpy.float64' object is not callable
at Initialize in main.py:line 61
at <listcomp> in main.py:line 61
at _lpdf_copula in main.py:line 180
TypeError : 'numpy.float64' object is not callable

Please let me know how to fix this error.

Here's the log

 

2016-01-01 00:00:00 tau[0.8275683378675994]
2016-01-01 00:00:00 pr[0.9731561488653664]
2016-01-01 00:00:00 sr[0.9537108433734941]
2016-01-01 00:00:00 ['QQQ', 'XLK']
0

I recloned main.py and now its giving me divide by zero

 

2010-01-01 00:00:00 Launching analysis for cce8e0431a787372de3292bb08c292cf with LEAN Engine v2.4.0.0.4204
2010-01-01 00:00:00 tau[0.8253320393090852, 0.6179262171683773, -0.17722502914885346, -0.9721300061192752, 0.337274464884929, 0.6267612506512401, -0.9799310265428414]
2010-01-01 00:00:00 pr[0.9670259814409863, 0.8317319961533359, -0.2781919432858115, -0.9609895525136876, 0.5122325081095581, 0.8490757342741757, -0.9978284222463686]
2010-01-01 00:00:00 sr[0.9530808788145118, 0.8030656940040984, -0.2571348620287602, -0.9973554211728561, 0.4769522258617463, 0.8083956634210044, -0.9990981283624972]
2010-01-01 00:00:00 ['QQQ', 'XLK']
2010-01-01 00:00:00 gumbel
2010-01-01 00:00:00 {'clayton': [9.466099356441555, -2120.1947620276846], 'frank': [array([20.41761605]), -2347.304612053184], 'gumbel': [5.733049678220778, -2584.9402802921536]}
2010-01-04 00:00:00 Runtime Error: DivisionByZero : [<class 'decimal.DivisionByZero'>]
at OnData in main.py:line 112
DivisionByZero : [<class 'decimal.DivisionByZero'>]
2010-01-04 00:00:00 Algorithm Id:(cce8e0431a787372de3292bb08c292cf) completed in 11.19 seconds at 0k data points per second. Processing total of 5,516 data points.
0

# compute today's log return of 2 stocks
if len(self.price_list[self.syl[0]]) < 3 or len(self.price_list[self.syl[1]]) < 3: return
else:
return_x = np.log(float(self.price_list[self.syl[0]][-1]/self.price_list[self.syl[0]][-2]))
return_y = np.log(float(self.price_list[self.syl[1]][-1]/self.price_list[self.syl[1]][-2]))

Tweaked it to check for at least 3 days. The -2 position wasn't set yet.

0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


Thanks Jared! worked like a charm

0

One more question, I am trying to use similar strategy for currencies, is it possible to change the ticker to use currency?

2 currency pairs: EUR/USD and NZD/USD

test for cointegration of prices between both assets

0

Two Questions:

1. How is the Quantity calculated? (i.e. where can I find the function CalculateOrderQuantity() )

2. 1200 days to determine which copula and 250 days to determine the parameters? So 1200 days are used to decide Frank/Gumbel/etc. and the parameter theta is optimized using the 250 days before each trade? Or how many times and when is this parameter updated?

Thanks in advance,

Dennis

1

Hi Jing Wu,

I have tried the pair selection as you did by selecting the highest Kendall’s tau of the pair log return. I ran though the data of entire NYSE stock list and pick the highest 30 stock pair of Kendall's tau each year from 2001 to 2017. Then I backtested the pair on the next year historical data. I find that the high Kendall's tau doesn't has a direct relationship with good performance. P.S. the backtesting is using the stratigy that you posted out.

Is there a better way to pick a good pair?

0

Hello,

How do I implement this strategy for forex pairs? Thank you

0

What happened to the rest of this thread?

I am trying to find the working copula algorithm.

Best,

Andrew

0

where is the rest of this thread?

Best,

Andrew

0

Hi All!

Sincere apologies for the above for some reason the page did not load for me.

I am really fasciantated with the above and would like to build on it.

I have a couple of quesions -

If i want to try another type of copula in a python package, how can i import the package

My first impression is that i could only do it locally.

So i would like to set up a local backetest enviroment preferably in jypyter notbeook.

What would be the best way to acheive this?

Many thanks all,

Best,

Andrew

0

Update Backtest





0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


Loading...

This discussion is closed