If any issues, questions or suggestions feel free to reach me out via e-mail wieczynskipawel@gmail.com or Linkedin. You can also visit my Github.
if(!require(pacman)) install.packages('pacman')
pacman::p_load(PolishStock, dplyr, corrplot, lubridate, tidyr, ggplot2, stringr, ggrepel)
We will check Pearson correlation beetwen monthly log-returns of the following assets:
- WIG index
- yield of 10-years Polish bonds
- S&P500 index
- DAX index
- iShares MSCI Emerging Markets ETF
- USDPLN
- EURPLN
- Gold price (XAUUSD)
- Eurozone Manufacturing PMI.
We use PolishStock package to download the above data from the website stooq.pl. Monthly data for period June 2010 - February 2022 consists of 138 observations.
tickers <- c('WIG', '10PLY.B', '^SPX', '^DAX', 'EEM.US'
,'USDPLN', 'EURPLN', 'XAUUSD', 'PMMNEU.M')
# for (ticker in tickers) {
# stooq_download(ticker
# ,start_date = 20100101
# ,end_date = 20222502
# ,interval = 'm'
# ,destination = paste0(getwd(), '/datasets/'))
# }
close_prices <- df_prices(paste0(tickers, '.csv')
,source = 'datasets/')
returns <- data.frame(
Date = close_prices$Date[-1]
,sapply(select(close_prices, -Date)
,FUN = function(x) diff(log(x), lag = 1))
)
colnames(returns) <- c('Date', 'WIG', '10Y Yield', 'S&P', 'DAX'
,'EM', 'USDPLN', 'EURPLN', 'Gold', 'Euro PMI')
Pearson correlation coefficient shows linear relationships \(Y = aX +b\). When calculating it and making inferences, be aware of some pitfalls:
- if distribution of \(X\) and \(Y\) is far from bivariate normal then Pearson coefficient could exhibit linear relationship where in fact such relationship doesn’t exists; and remember that normality of marginal distributions don’t guarantee normality of joint distribution
- outliers in the dataset can influence interpretability of Pearson coefficient
- in the correlation context there is no sense in distiction beetwen dependent and independent variable; theoretically we don’t know if there is equation either \(Y = aX +b\) or equation \(X = a^{-1} (Y - b)\); if there really exists dependence beetwen variables, Pearson coefficient won’t tell us about it
- if there exists unknown factor \(Z\) which positively affects \(X\) and negatively affects \(Y\) then Pearson coefficient will be negative
- if \(X\) and \(Y\) are independent then Pearson coefficient is equal 0, but the reverse ain’t true
- Pearson coefficient doesn’t show proportion, e.g. we can’t say that correlation of \(0.6\) is \(2\) times higher than correlation of \(0.3\); however determination coefficient \(R^2\) which is in fact Pearson correlation squared shows us proportions.
Below we can see positive correlation beetwen WIG and DAX, S&P500, Emerging Markets. We can also see negative correlation beetwen WIG and USDPLN, EURPLN. There is no correlation beetwen WIG and 10Y Polish bonds yield and Eurozone Manufacturing PMI.
corr_matrix <- cor(select_if(returns, is.numeric)) %>%
round(2)
corrplot(corr_matrix
,title = 'Pearson Correlation'
,mar = c(1,0,1,0)
,method = 'color'
,type = 'lower'
,order = 'alphabet'
,tl.col = 'black'
,tl.cex = 0.8
,tl.srt = 0
,addCoef.col = 'black'
,diag = FALSE
)

However, above we calculated correlation for ~11 years time horizon. Now we calculate and visualize moving correlation for \(t = 1, \dots, 11\) years.
returns <- returns %>%
mutate(Year = year(returns$Date))
moving_correlation <- data.frame(
Index = names(select(returns, -Date, -Year))
)
for (i in 1:floor(nrow(returns) / 12)) {
temp_corr_matrix <- returns %>%
slice_tail(n = i * 12) %>%
select(-Date, -Year) %>%
cor() %>%
round(2) %>%
as.data.frame() %>%
mutate(Index = row.names(.))
moving_correlation <- moving_correlation %>%
left_join(select(temp_corr_matrix, WIG, Index)
,by = c('Index' = 'Index'))
colnames(moving_correlation)[i+1] <- paste0(i, '-years')
}
ggplot(moving_correlation %>%
pivot_longer(cols = 2:ncol(moving_correlation)
,names_to = 'Variable'
,values_to = 'Value') %>%
filter(Index != 'WIG') %>%
mutate(Year = str_extract(Variable, '[0-9]*') %>%
as.numeric()
,Label = if_else(Year == 8
,as.character(Index)
,NA_character_))) +
geom_line(aes(x = reorder(Variable, -Year)
,y = Value
,group = Index
,color = Index)
,size = 1) +
geom_label_repel(aes(x = reorder(Variable, -Year)
,y = Value
,label = Label
,color = Index),
nudge_x = 1,
na.rm = TRUE
,min.segment.length = 5) +
theme_bw() +
theme(legend.position = 'none') +
labs(x = '', y = '', title = 'Moving Correlation of WIG index')

LS0tDQp0aXRsZTogIkNvcnJlbGF0aW9uIGJlZXR3ZW4gV0lHIGluZGV4IGFuZCBvdGhlciBhc3NldHMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpJZiBhbnkgaXNzdWVzLCBxdWVzdGlvbnMgb3Igc3VnZ2VzdGlvbnMgZmVlbCBmcmVlIHRvIHJlYWNoIG1lIG91dCB2aWEgZS1tYWlsIDx3aWVjenluc2tpcGF3ZWxAZ21haWwuY29tPiBvciBbTGlua2VkaW5dKGh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9pbi9wYXdlbC13aWVjenluc2tpLykuIFlvdSBjYW4gYWxzbyB2aXNpdCBteSBbR2l0aHViXShodHRwczovL2dpdGh1Yi5jb20vcGF3ZWwtd2llY3p5bnNraSkuDQoNCmBgYHtyIGxpYnJhcmllcywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmlmKCFyZXF1aXJlKHBhY21hbikpIGluc3RhbGwucGFja2FnZXMoJ3BhY21hbicpDQpwYWNtYW46OnBfbG9hZChQb2xpc2hTdG9jaywgZHBseXIsIGNvcnJwbG90LCBsdWJyaWRhdGUsIHRpZHlyLCBnZ3Bsb3QyLCBzdHJpbmdyLCBnZ3JlcGVsKQ0KYGBgDQoNCldlIHdpbGwgY2hlY2sgUGVhcnNvbiBjb3JyZWxhdGlvbiBiZWV0d2VuIG1vbnRobHkgbG9nLXJldHVybnMgb2YgdGhlIGZvbGxvd2luZyBhc3NldHM6IFwNCiAtIFdJRyBpbmRleCBcDQogLSB5aWVsZCBvZiAxMC15ZWFycyBQb2xpc2ggYm9uZHMgXA0KIC0gUyZQNTAwIGluZGV4IFwNCiAtIERBWCBpbmRleCBcDQogLSBpU2hhcmVzIE1TQ0kgRW1lcmdpbmcgTWFya2V0cyBFVEYgXA0KIC0gVVNEUExOIFwNCiAtIEVVUlBMTiBcDQogLSBHb2xkIHByaWNlIChYQVVVU0QpIFwNCiAtIEV1cm96b25lIE1hbnVmYWN0dXJpbmcgUE1JLg0KDQpXZSB1c2UgW1BvbGlzaFN0b2NrIHBhY2thZ2VdKGh0dHBzOi8vZ2l0aHViLmNvbS9wYXdlbC13aWVjenluc2tpL1BvbGlzaFN0b2NrKSB0byBkb3dubG9hZCB0aGUgYWJvdmUgZGF0YSBmcm9tIHRoZSB3ZWJzaXRlIFtzdG9vcS5wbF0oaHR0cHM6Ly9zdG9vcS5wbC8pLiBNb250aGx5IGRhdGEgZm9yIHBlcmlvZCBKdW5lIDIwMTAgLSBGZWJydWFyeSAyMDIyIGNvbnNpc3RzIG9mIDEzOCBvYnNlcnZhdGlvbnMuDQpgYGB7ciBnZXRfZGF0YX0NCnRpY2tlcnMgPC0gYygnV0lHJywgJzEwUExZLkInLCAnXlNQWCcsICdeREFYJywgJ0VFTS5VUycNCiAgICAgICAgICAgICAsJ1VTRFBMTicsICdFVVJQTE4nLCAnWEFVVVNEJywgJ1BNTU5FVS5NJykNCg0KZm9yICh0aWNrZXIgaW4gdGlja2Vycykgew0KICBzdG9vcV9kb3dubG9hZCh0aWNrZXINCiAgICAgICAgICAgICAgICAgLHN0YXJ0X2RhdGUgPSAyMDEwMDEwMQ0KICAgICAgICAgICAgICAgICAsZW5kX2RhdGUgPSAyMDIyMjUwMg0KICAgICAgICAgICAgICAgICAsaW50ZXJ2YWwgPSAnbScNCiAgICAgICAgICAgICAgICAgLGRlc3RpbmF0aW9uID0gcGFzdGUwKGdldHdkKCksICcvZGF0YXNldHMvJykpDQp9DQoNCmNsb3NlX3ByaWNlcyA8LSBkZl9wcmljZXMocGFzdGUwKHRpY2tlcnMsICcuY3N2JykNCiAgICAgICAgICAgICAgICAgICAgICAgICAgLHNvdXJjZSA9ICdkYXRhc2V0cy8nKQ0KDQpyZXR1cm5zIDwtIGRhdGEuZnJhbWUoDQogIERhdGUgPSBjbG9zZV9wcmljZXMkRGF0ZVstMV0NCiAgLHNhcHBseShzZWxlY3QoY2xvc2VfcHJpY2VzLCAtRGF0ZSkNCiAgICAgICAgICxGVU4gPSBmdW5jdGlvbih4KSBkaWZmKGxvZyh4KSwgbGFnID0gMSkpDQopDQoNCmNvbG5hbWVzKHJldHVybnMpIDwtIGMoJ0RhdGUnLCAnV0lHJywgJzEwWSBZaWVsZCcsICdTJlAnLCAnREFYJw0KICAgICAgICAgICAgICAgICAgICAgICAsJ0VNJywgJ1VTRFBMTicsICdFVVJQTE4nLCAnR29sZCcsICdFdXJvIFBNSScpDQogIA0KYGBgDQoNClBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnQgc2hvd3MgbGluZWFyIHJlbGF0aW9uc2hpcHMgJFkgPSBhWCArYiQuIFdoZW4gY2FsY3VsYXRpbmcgaXQgYW5kIG1ha2luZyBpbmZlcmVuY2VzLCBiZSBhd2FyZSBvZiBzb21lIHBpdGZhbGxzOiBcDQogLSBpZiBkaXN0cmlidXRpb24gb2YgJFgkIGFuZCAkWSQgaXMgZmFyIGZyb20gYml2YXJpYXRlIG5vcm1hbCB0aGVuIFBlYXJzb24gY29lZmZpY2llbnQgY291bGQgZXhoaWJpdCBsaW5lYXIgcmVsYXRpb25zaGlwIHdoZXJlIGluIGZhY3Qgc3VjaCByZWxhdGlvbnNoaXAgZG9lc24ndCBleGlzdHM7IGFuZCByZW1lbWJlciB0aGF0IG5vcm1hbGl0eSBvZiBtYXJnaW5hbCBkaXN0cmlidXRpb25zIGRvbid0IGd1YXJhbnRlZSBub3JtYWxpdHkgb2Ygam9pbnQgZGlzdHJpYnV0aW9uIFwNCiAtIG91dGxpZXJzIGluIHRoZSBkYXRhc2V0IGNhbiBpbmZsdWVuY2UgaW50ZXJwcmV0YWJpbGl0eSBvZiBQZWFyc29uIGNvZWZmaWNpZW50IFwNCiAtIGluIHRoZSBjb3JyZWxhdGlvbiBjb250ZXh0IHRoZXJlIGlzIG5vIHNlbnNlIGluIGRpc3RpY3Rpb24gYmVldHdlbiBkZXBlbmRlbnQgYW5kIGluZGVwZW5kZW50IHZhcmlhYmxlOyB0aGVvcmV0aWNhbGx5IHdlIGRvbid0IGtub3cgaWYgdGhlcmUgaXMgZXF1YXRpb24gZWl0aGVyICRZID0gYVggK2IkIG9yIGVxdWF0aW9uICRYID0gYV57LTF9IChZIC0gYikkOyBpZiB0aGVyZSByZWFsbHkgZXhpc3RzIGRlcGVuZGVuY2UgYmVldHdlbiB2YXJpYWJsZXMsIFBlYXJzb24gY29lZmZpY2llbnQgd29uJ3QgdGVsbCB1cyBhYm91dCBpdCBcDQogLSBpZiB0aGVyZSBleGlzdHMgdW5rbm93biBmYWN0b3IgJFokIHdoaWNoIHBvc2l0aXZlbHkgYWZmZWN0cyAkWCQgYW5kIG5lZ2F0aXZlbHkgYWZmZWN0cyAkWSQgdGhlbiBQZWFyc29uIGNvZWZmaWNpZW50IHdpbGwgYmUgbmVnYXRpdmUgXA0KIC0gaWYgJFgkIGFuZCAkWSQgYXJlIGluZGVwZW5kZW50IHRoZW4gUGVhcnNvbiBjb2VmZmljaWVudCBpcyBlcXVhbCAwLCAqKmJ1dCB0aGUgcmV2ZXJzZSBhaW4ndCB0cnVlKiogXA0KIC0gUGVhcnNvbiBjb2VmZmljaWVudCBkb2Vzbid0IHNob3cgcHJvcG9ydGlvbiwgZS5nLiAgd2UgY2FuJ3Qgc2F5IHRoYXQgY29ycmVsYXRpb24gb2YgJDAuNiQgaXMgJDIkIHRpbWVzIGhpZ2hlciB0aGFuIGNvcnJlbGF0aW9uIG9mICQwLjMkOyBob3dldmVyIGRldGVybWluYXRpb24gY29lZmZpY2llbnQgJFJeMiQgd2hpY2ggaXMgaW4gZmFjdCBQZWFyc29uIGNvcnJlbGF0aW9uIHNxdWFyZWQgc2hvd3MgdXMgcHJvcG9ydGlvbnMuDQoNCkJlbG93IHdlIGNhbiBzZWUgcG9zaXRpdmUgY29ycmVsYXRpb24gYmVldHdlbiBXSUcgYW5kIERBWCwgUyZQNTAwLCBFbWVyZ2luZyBNYXJrZXRzLiBXZSBjYW4gYWxzbyBzZWUgbmVnYXRpdmUgY29ycmVsYXRpb24gYmVldHdlbiBXSUcgYW5kIFVTRFBMTiwgRVVSUExOLiBUaGVyZSBpcyBubyBjb3JyZWxhdGlvbiBiZWV0d2VuIFdJRyBhbmQgMTBZIFBvbGlzaCBib25kcyB5aWVsZCBhbmQgRXVyb3pvbmUgTWFudWZhY3R1cmluZyBQTUkuDQoNCmBgYHtyIGNvcnJlbGF0aW9uX21hdHJpeH0NCmNvcnJfbWF0cml4IDwtIGNvcihzZWxlY3RfaWYocmV0dXJucywgaXMubnVtZXJpYykpICU+JQ0KICByb3VuZCgyKQ0KDQpjb3JycGxvdChjb3JyX21hdHJpeA0KICAgICAgICAgLHRpdGxlID0gJ1BlYXJzb24gQ29ycmVsYXRpb24nDQogICAgICAgICAsbWFyID0gYygxLDAsMSwwKQ0KICAgICAgICAgLG1ldGhvZCA9ICdjb2xvcicNCiAgICAgICAgICx0eXBlID0gJ2xvd2VyJw0KICAgICAgICAgLG9yZGVyID0gJ2FscGhhYmV0Jw0KICAgICAgICAgLHRsLmNvbCA9ICdibGFjaycNCiAgICAgICAgICx0bC5jZXggPSAwLjgNCiAgICAgICAgICx0bC5zcnQgPSAwDQogICAgICAgICAsYWRkQ29lZi5jb2wgPSAnYmxhY2snDQogICAgICAgICAsZGlhZyA9IEZBTFNFDQopIA0KYGBgDQpIb3dldmVyLCBhYm92ZSB3ZSBjYWxjdWxhdGVkIGNvcnJlbGF0aW9uIGZvciB+MTEgeWVhcnMgdGltZSBob3Jpem9uLiBOb3cgd2UgY2FsY3VsYXRlIGFuZCB2aXN1YWxpemUgbW92aW5nIGNvcnJlbGF0aW9uIGZvciAkdCA9IDEsIFxkb3RzLCAxMSQgeWVhcnMuDQpgYGB7ciBtb3ZpbmdfY29ycmVsYXRpb259DQpyZXR1cm5zIDwtIHJldHVybnMgJT4lDQogIG11dGF0ZShZZWFyID0geWVhcihyZXR1cm5zJERhdGUpKQ0KDQptb3ZpbmdfY29ycmVsYXRpb24gPC0gZGF0YS5mcmFtZSgNCiAgSW5kZXggPSBuYW1lcyhzZWxlY3QocmV0dXJucywgLURhdGUsIC1ZZWFyKSkNCikNCg0KZm9yIChpIGluIDE6Zmxvb3IobnJvdyhyZXR1cm5zKSAvIDEyKSkgew0KICANCiAgdGVtcF9jb3JyX21hdHJpeCA8LSByZXR1cm5zICU+JQ0KICAgIHNsaWNlX3RhaWwobiA9IGkgKiAxMikgJT4lDQogICAgc2VsZWN0KC1EYXRlLCAtWWVhcikgJT4lDQogICAgY29yKCkgJT4lDQogICAgcm91bmQoMikgJT4lDQogICAgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICAgIG11dGF0ZShJbmRleCA9IHJvdy5uYW1lcyguKSkNCiAgICANCiAgbW92aW5nX2NvcnJlbGF0aW9uIDwtIG1vdmluZ19jb3JyZWxhdGlvbiAlPiUNCiAgICBsZWZ0X2pvaW4oc2VsZWN0KHRlbXBfY29ycl9tYXRyaXgsIFdJRywgSW5kZXgpDQogICAgICAgICAgICAgICxieSA9IGMoJ0luZGV4JyA9ICdJbmRleCcpKQ0KICANCiAgY29sbmFtZXMobW92aW5nX2NvcnJlbGF0aW9uKVtpKzFdIDwtIHBhc3RlMChpLCAnLXllYXJzJykNCiAgDQp9DQoNCmdncGxvdChtb3ZpbmdfY29ycmVsYXRpb24gJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gMjpuY29sKG1vdmluZ19jb3JyZWxhdGlvbikNCiAgICAgICAgICAgICAgICxuYW1lc190byA9ICdWYXJpYWJsZScNCiAgICAgICAgICAgICAgICx2YWx1ZXNfdG8gPSAnVmFsdWUnKSAlPiUNCiAgICBmaWx0ZXIoSW5kZXggIT0gJ1dJRycpICU+JQ0KICAgIG11dGF0ZShZZWFyID0gc3RyX2V4dHJhY3QoVmFyaWFibGUsICdbMC05XSonKSAlPiUNCiAgICAgICAgICAgICBhcy5udW1lcmljKCkNCiAgICAgICAgICAgLExhYmVsID0gaWZfZWxzZShZZWFyID09IDgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAsYXMuY2hhcmFjdGVyKEluZGV4KQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICxOQV9jaGFyYWN0ZXJfKSkpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0gcmVvcmRlcihWYXJpYWJsZSwgLVllYXIpDQogICAgICAgICAgICAgICAgLHkgPSBWYWx1ZQ0KICAgICAgICAgICAgICAgICxncm91cCA9IEluZGV4DQogICAgICAgICAgICAgICAgLGNvbG9yID0gSW5kZXgpDQogICAgICAgICAgICAsc2l6ZSA9IDEpICsNCiAgZ2VvbV9sYWJlbF9yZXBlbChhZXMoeCA9IHJlb3JkZXIoVmFyaWFibGUsIC1ZZWFyKQ0KICAgICAgICAgICAgICAgICAgICAgICAseSA9IFZhbHVlDQogICAgICAgICAgICAgICAgICAgICAgICxsYWJlbCA9IExhYmVsDQogICAgICAgICAgICAgICAgICAgICAgICxjb2xvciA9IEluZGV4KSwNCiAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAxLA0KICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFDQogICAgICAgICAgICAgICAgICAsbWluLnNlZ21lbnQubGVuZ3RoID0gNSkgKyANCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykgKw0KICBsYWJzKHggPSAnJywgeSA9ICcnLCB0aXRsZSA9ICdNb3ZpbmcgQ29ycmVsYXRpb24gb2YgV0lHIGluZGV4JykNCg0KYGBg