# Analyzing Bitcoin in R - Part 13 - Copulas and extreme values, two asssets

Pub: 04.12.17

In Finance.

Tags: coding r bitcoin analysis .

The issue with portfolio allocation is that for some assets there are not enough return observations. Or that we want to establish how robust the allocations are in simulated outcomes of the world. However, we also know that returns are notoriously difficult to simulate. One way that we can attempt to capture some of the interesting return dynamics is by using copulas and extreme value / tail risk dynamics to help.

A straight forward description of the background, math, and application can be read in Optimization with Tail-Dependence and Tail Risk: A Copula Based Approach for Strategic Asset Allocation by Francesco Paolo Natale. It gives you all you need to continue pursuing this type of analysis yourself.

The following is a simple paraphrasing of the approach. I will leave out the initial ARMA / GARCH model residual estimation and instead model the returns directly. I will also only show one simulation run instead of multiple.

Let's start by doing it for two assets. Bitcoin and the Index. They are not that correlated.

tworets <- cbind(btcnret, spidret)
colnames(tworets) <- c('BitcoinUSD', 'SP500')
tworets <- as.timeSeries(tworets)
cor(tworets)
BitcoinUSD     SP500
BitcoinUSD  1.0000000 0.1552561
SP500       0.1552561 1.0000000


What does the scatter plot look like

png(filename = "btc_plot_scatter1.png")
plot(as.matrix(tworets), pch = 20)
dev.off() Let's automatically find out which copula best represents the two series:

library(VineCopula)
selectedCopula <- BiCopSelect(pobs(tworets[,1]), pobs(tworets[,2]), familyset=NA)
selectedCopula
Bivariate copula: Rotated Tawn type 1 180 degrees (par = 1.57, par2 = 0.36, tau = 0.19)
summary(selectedCopula)
Family
------
No:    114
Name:  Rotated Tawn type 1 180 degrees

Parameter(s)
------------
par:  1.57
par2: 0.36
Dependence measures
-------------------
Kendall's tau:    0.19 (empirical = 0.16, p value = 0.04)
Upper TD:         0
Lower TD:         0.24

Fit statistics
--------------
logLik:  3.49
AIC:    -2.99
BIC:    1.65


Now that we know the copula, let's simulate from it:

cop <- BiCop(family = 114, par = 1.57, par2 = 0.36)
simdata <- BiCopSim(300, cop)
outsim <- matrix(NA, 300, 2)
colnames(outsim) <- colnames(tworets)
outsim[,1] <- qnorm(simdata[,1], mean(tworets[,1]), sd(tworets[,1]))
outsim[,2] <- qnorm(simdata[,2], mean(tworets[,2]), sd(tworets[,2]))
png(filename = "btc_plot_scatter2.png")
plot(as.matrix(outsim), pch = 20)
dev.off()
outsim <- as.timeSeries(outsim)
out <- minvariancePortfolio(outsim, constraints = "LongOnly")
store <- out@portfolio@portfolio$weights out <- maxratioPortfolio(outsim, constraints = "LongOnly") store <- rbind(store, out@portfolio@portfolio$weights) Let's also get results from the normal distribution for comparison:

outsim[,1] <- rnorm(300, mean(tworets[,1]), sd(tworets[,1]))
outsim[,2] <- rnorm(300, mean(tworets[,2]), sd(tworets[,2]))
outsim <- as.timeSeries(outsim)
out <- minvariancePortfolio(outsim, constraints = "LongOnly")
store <- rbind(store, out@portfolio@portfolio$weights) out <- maxratioPortfolio(outsim, constraints = "LongOnly") store <- rbind(store, out@portfolio@portfolio$weights)
rownames(store) <- c('CopulaMinVar', 'CopulaMaxRat', 'NormMinVar', 'NormMaxRat')


Is the difference big? Not really, I guess.

             BitcoinUSD     SP500
CopulaMinVar 0.000000000 1.0000000
CopulaMaxRat 0.028204004 0.9717960
NormMinVar   0.004985198 0.9950148
NormMaxRat   0.027463749 0.9725363


The results from the simulated data of 300 observations is almost the same as from the raw data.

A partial problem with extreme value theory is that fitting the tail distributions needs a bit more data than we have on Bitcoin. But we can use our simulation from the Copula to help us:

library(spd)
cop <- BiCop(family = 114, par = 1.57, par2 = 0.36)
simdata <- BiCopSim(1000, cop)
outsim <- matrix(NA, 1000, 2)
colnames(outsim) <- colnames(tworets)
outsim[,1] <- qnorm(simdata[,1], mean(tworets[,1]), sd(tworets[,1]))
outsim[,2] <- qnorm(simdata[,2], mean(tworets[,2]), sd(tworets[,2]))
simout <- matrix(NA, 1000, 2)
colnames(simout) <- colnames(outsim)
fit <- spdfit(outsim[,1], upper=0.9, lower=0.1, tailfit='GPD', kernelfit='normal')
simout[,1] <- rspd(1000, fit)
fit <- spdfit(outsim[,2], upper=0.9, lower=0.1, tailfit='GPD', kernelfit='normal')
simout[,2] <- rspd(1000, fit)
png(filename = "btc_plot_scatter3.png")
plot(as.matrix(simout), pch = 20)
dev.off() Let's compare the new results with our old

simout <- as.timeSeries(simout)
out <- minvariancePortfolio(simout, constraints = "LongOnly")
store <- rbind(store, out@portfolio@portfolio$weights) out <- maxratioPortfolio(simout, constraints = "LongOnly") store <- rbind(store, out@portfolio@portfolio$weights)
rownames(store) <- c('CopulaMinVar', 'CopulaMaxRat', 'NormMinVar', 'NormMaxRat', 'EVMinVar', 'EVMaxRat')
store


So or tail fitting seems to produce something a bit more interesting than the few copula observations but less weight on Bitcoin than just simulating from a normal distribution. Probably meaning that the tails matter a bit more for Bitcoin and that should be considered with a lower weight.

              BitcoinUSD     SP500
CopulaMinVar 0.000000000 1.0000000
CopulaMaxRat 0.028204004 0.9717960
NormMinVar   0.004985198 0.9950148
NormMaxRat   0.027463749 0.9725363
EVMinVar     0.001179433 0.9988206
EVMaxRat     0.028906096 0.9710939


We can compare all three distributions:

png(filename = "btc_plot_scatter4.png")
par(mfrow = c(3, 1))
par(mar = c(4, 4, 3, 2))
plot(as.numeric(tworets[,1]), as.numeric(tworets[,2]), pch = 20);abline(h=0,v=0);
plot(as.numeric(outsim[,1]), as.numeric(outsim[,2]), pch = 20);abline(h=0,v=0);
plot(as.numeric(simout[,1]), as.numeric(simout[,2]), pch = 20);abline(h=0,v=0);
dev.off() Because we extended the data using our copula approach, we were able to add some extreme values and get a broader distribution of returns.

What if you have more than two assets that you want to evaluate in conjunction: Copulas and extreme value, many assets

You can also jump to each section directly from here: