Skip to content

Instantly share code, notes, and snippets.

@spesenti
Created June 19, 2020 18:17
Show Gist options
  • Save spesenti/4192852cd29f90e900b420bc0b4dbc3c to your computer and use it in GitHub Desktop.
Save spesenti/4192852cd29f90e900b420bc0b4dbc3c to your computer and use it in GitHub Desktop.

A portfolio example

Here, through an example, we illustrate the basic concepts and usage of SWIM for sensitivity analysis. More advanced usage of SWIM and options for constructing stresses are demonstrated in the vignette Vignette.html.

We consider a simple portfolio model, with the portfolio loss defined by Y = Z1 + Z2 + Z3. The random variables Z1, Z2, Z3 represent normally distributed losses, where Z1 has mean 100 and standard deviation 40, and Z2 and Z3 have mean 100 and standard deviation 2. Further, Z1 and Z2 are correlated, while Z3 is independent of (Z1, Z2). Our purpose in this example is to investigate how a stress on the loss Z1 impacts on the overall portfolio loss Y. First we derive simulated data from the random vector (Z1, Z2, Z3, Y), forming our baseline model.

set.seed(0)
# number of simulated scenarios
n.sim <- 10 ^ 5
# correlation between Z1 and Z2
r <- 0.5
# simulation of Z1  and Z2
# constructed as a combination of independent standard normals U1, U2
U1 <- rnorm(n.sim)
U2 <- rnorm(n.sim)
Z1 <- 100 + 40 * U1
Z2 <- 100 + 20 * (r * U1 + sqrt(1 - r ^ 2) * U2)
# simulation of Z3
Z3 <- rnorm(n.sim, 100, 20)
# portfolio loss Y
Y <- Z1 + Z2 + Z3
# data of baseline model
dat <- data.frame(Z1, Z2, Z3, Y)

Now we introduce a stress to our baseline model. For our first stress, we require that the mean of Z1 is increased from 100 to 110. This is done using the stress function, which generates as output the SWIM object str.mean. This object stores the stressed model, i.e. the realisations of the model components and the scenario weights. In the function call, the argument k = 1 indicates that the stress is applied on the first column of dat, that is, on the realisations of the random variable Z1.

library(SWIM)
str.mean <- stress(type = "mean", x = dat, k = 1, new_means = 110)
summary(str.mean, base = TRUE)
## $base
##                   Z1       Z2       Z3        Y
## mean         1.0e+02  99.9404  99.9843 299.9811
## sd           4.0e+01  19.9970  19.9819  56.6389
## skewness    -6.1e-04   0.0012  -0.0025  -0.0023
## ex kurtosis -1.1e-02  -0.0090  -0.0126  -0.0094
## 1st Qu.      7.3e+01  86.4745  86.4816 261.6121
## Median       1.0e+02  99.9866 100.0091 300.0548
## 3rd Qu.      1.3e+02 113.3957 113.4934 338.2670
## 
## $`stress 1`
##                   Z1       Z2       Z3        Y
## mean        110.0000 102.4437  99.9828 312.4265
## sd           40.0333  19.9954  19.9762  56.6173
## skewness     -0.0024  -0.0015  -0.0049  -0.0037
## ex kurtosis  -0.0050  -0.0032  -0.0155  -0.0012
## 1st Qu.      82.9984  88.9771  86.4815 274.2200
## Median      110.0759 102.4810  99.9954 312.5039
## 3rd Qu.     136.9310 115.8744 113.5019 350.6120

The summary function, applied to the SWIM object str.mean, shows how the distributional characteristics of all random variables change from the baseline to the stressed model. In particular, we see that the mean of Z1 changes to its required value, while the mean of Y also increases. Furthermore there is a small impact on Z2, due to its positive correlation to Z1.

Beyond considering the standard statistics evaluated via the summary function, stressed probability distributions can be plotted. In the next figure we show the impact of the stress on the cumulative distribution functions (cdf) of Z1 and Y. It is seen how the stressed cdfs are lower than the original (baseline) ones. Loosely speaking, this demonstrates that the stress has increased (in a stochastic sense) both random variables Z1 and Y. While the stress was on Z1, the impact on the distribution of the portfolio Y is clearly visible.

# refer to variable of interest by name...
plot_cdf(str.mean, xCol = "Z1", base = TRUE)
# ... or column number
plot_cdf(str.mean, xCol = 4, base = TRUE)

plot of chunk example1-cdfs-meanplot of chunk example1-cdfs-mean

The scenario weights, given their central role, can be extracted from a SWIM object. The scenario weights from str.mean are plotted against realisations from Z1 and Y respectively. It is seen how the weights are increasing in the realisations from Z1. This is a consequence of the weights' derivation via a stress on the model component Z1. The increasingness shows that those scenarios for which Z1 is largest are assigned a higher weight. The relation between scenario weights and Y is still increasing (reflecting that high outcomes of Y tend to receive higher weights), but no longer deterministic (showing that Y is not completely driven by changes in Z1).

# extract weights from stressed model
w.mean <- get_weights(str.mean)
plot(Z1[1:5000], w.mean[1:5000], pch = 20, xlab = "Z1", ylab = "scenario weights")
plot(Y[1:5000], w.mean[1:5000], pch = 20, xlab = "Y", ylab = "scenario weights")

plot of chunk example1-weights-meanplot of chunk example1-weights-mean

The stress to the mean of Z1 did not impact the volatility of either Z1 or Y, as can be seen by the practically unchanged standard deviations in the output of summary(str.mean). Thus, we introduce an alternative stress that keeps the mean of Z1 fixed at 100, but increases its standard deviation from 40 to 50. This new stress is seen to impact the standard deviation of the portfolio loss Y.

str.sd <- stress(type = "mean sd", x = dat, k = 1, new_means = 100, new_sd = 50)
summary(str.sd, base = FALSE)
## $`stress 1`
##                   Z1      Z2       Z3        Y
## mean        100.0000  99.941  99.9782 299.9187
## sd           50.0005  21.349  19.9800  67.9233
## skewness     -0.0027   0.007  -0.0034   0.0049
## ex kurtosis  -0.0556  -0.033  -0.0061  -0.0427
## 1st Qu.      66.0964  85.495  86.4822 253.7496
## Median      100.1290  99.974 100.0455 299.9766
## 3rd Qu.     133.7733 114.301 113.4701 345.9159

Furthermore, in the next figure, we compare the baseline and stressed cdfs of Z1 and Y, under the new stress on Z1. The crossing of probability distribution reflects the increase in volatility.

plot_cdf(str.sd, xCol = "Z1", base = TRUE)
plot_cdf(str.sd, xCol = 4, base = TRUE)

plot of chunk example1-cdfs-sdplot of chunk example1-cdfs-sd

The different way in which a stress on the standard deviation of Z1 impacts on the model, compared to a stress on the mean, is reflected by the scenario weights. The next figure shows the pattern of the scenario weights and how, when stressing standard deviations, higher weight is placed on scenarios where Z1 is extreme, either much lower or much higher than its mean of 100.

w.sd <- get_weights(str.sd)
plot(Z1[1:5000], w.sd[1:5000], pch = 20, xlab = "Z1", ylab = "scenario weights")
plot(Y[1:5000], w.sd[1:5000], pch = 20, xlab = "Y", ylab = "scenario weights")

plot of chunk example1-weights-sdplot of chunk example1-weights-sd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment