Basic Bootstrapping in GAUSS

Introduction

The bootstrap is a commonly used resampling technique which involves taking random samples with replacement to quantify uncertainty about a particular estimator or statistic.

Goals

In this post, we will apply the bootstrap procedure to asset returns. Our data will be annual returns from the S&P 500 and the 10 year US Treasury Bond from 1988-2017. We will apply the bootstrap to the cumulative return of a portfolio with 50% stocks and 50% bonds.

The bootstrap in GAUSS.

How to take a random sample

After loading our data, the first thing we need to do is to take random samples of our data. We will use the GAUSS function, sampleData, which takes the following inputs:


X
NxK matrix from which to take the samples.
size
Scalar, the size of the sample in terms of rows.
replace
Optional scalar input. If replace = 0, the sample is drawn without replacement. If replace = 1, the sample is drawn with replacement. Default, replace = 0.

To familiarize ourselves, let's create a small vector and take a couple of samples.

// For repeatable random samples
rndseed 4324;

v = { 7, 2, 9 };

// Take a sample of length 3
// without replacement
v_swor = sampleData(v, rows(v));

// Take a sample of length 3
// with replacement
v_swr = sampleData(v, rows(v), 1);

After the code above:

v = 7    v_swor = 2    v_swr = 2
    2             9            9
    9             7            9

As we would expect, we see that both samples are the same size as the original vector. The sample without replacement contains the same values as the original vector, just in a different order. The sample with replacement contains a repeated value. This is what we need for the bootstrap.

Example data

The first 5 rows of our data file look like this:

Year, S&P500, 10yrTBond
1988, 1.1654,   1.0822
1989, 1.3148,   1.1769
1990, 0.9694,   1.0624
1991, 1.3023,   1.15

The asset return data is 1 plus the year's return expressed as a decimal. For example, the S&P 500 return for 1988 was 16.54% and the 10 year Treasury Bond returned 6.24% in 1990. With the data in this form, it is easy to compute the cumulative return as the cumulative product of each annual value.

For example, for the period 1988 through 1991:

S&P500 Total Return = 1.1654 * 1.3148 * 0.9694 * 1.3023 = 1.9344

meaning that $1 invested in the S&P 500 at the start of 1988 would be worth $1.93 at the end of 1991. That assumes dividends are reinvested and there are no taxes, but still a pretty good return for four years.

One bootstrap iteration

After we load our data we need to:

  • Take a random sample with replacement.
  • Compute the return from this sample.

Take a random sample

Here is the code to load the data and take the first sample:

// Set seed for repeatable random numbers
rndseed 12577;

// Load all 30 observations for both assets
X = loadd("asset_returns.csv", "S&P500 + 10yrTBond"); 

// Take a sample with replacement
X_s = sampleData(X, rows(X), 1);

Compute the return

Earlier we mentioned that we can compute the return of our data by computing the cumulative product, which we illustrated when we found that $1 invested in the S&P 500 at the start of 1988 would be worth $1.93 by the end of 1991.

We will use the GAUSS function prodc, which computes the cumulative product of every column in a matrix.

// Compute the returns of each asset
returns = prodc(X_s);

// Average the two returns to find the return
// of a portfolio split equally between each asset
total_return = meanc(returns);

After running the last two code snippets, we find:

returns = 11.78    total_return = 8.44
           5.09 

The full bootstrap

To complete our bootstrap all we have to do now is:

  1. Create a vector to hold the results of our bootstrapped portfolio returns.
  2. Create a loop to perform our bootstrap samples.
// Set seed for repeatable random numbers
rndseed 12577;

// Load all 30 observations for both assets
X = loadd("asset_returns.csv", "S&P500 + 10yrTBond");

// The number of boostrap iterations to perform
n_iters = 10000;

// Create a vector to hold the bootstrap results
results = zeros(n_iters, 1);

for i(1, n_iters, 1);

    // Take a sample with replacement
    X_s = sampleData(X, rows(X), 1);

    // Compute the returns of each asset
    returns = prodc(X_s);

    // Average the two returns to find the return
    // of a portfolio split equally between each asset.
    // Store the total return in the 'results' vector.
    results[i] = meanc(returns);

endfor;

Results

Bootstrapped Investment Returns.

The histogram of our results vector is shown above. As we mentioned earlier, this data does not account for inflation, assumes all dividends are reinvested and that there are no taxes.

However, even with these stipulations, the returns seem unrealistically high. This is because the bootstrap procedure assumes that each observation is completely independent of all other observations.

This assumption of independence is not generally reasonable for time series data, including asset returns. Future blogs will explore bootstrap modifications to deal with this issue.

Conclusions

In this post, we have learned how to sample data with replacement and perform a basic bootstrap in GAUSS. Make sure to look out for future posts on more advanced bootstrap options.

Code and data from this blog can be found here.

Leave a Reply