简体   繁体   中英

Simulate a portfolio with active weights between [-0.02,0.02] and absolute weights sum to 1

I have an original set of weights for a portfolio and need to generate new weights that don't deviate more than 2% from the original data. The new absolute weights (original weights + new increment) must sum to one and the absolute weights must also be larger than 0 (ie it is a long only portfolio)

  1. I used runif(n=40, -0.02, 0.02) to generate my active weights
  2. I added the active weights to the original weights to get the new absolute weights
  3. I then calculated the sum of all the weights and divided every individual weight by the sum in order to get all the weights to sum to 1.
  4. I then take any new absolute weights that are smaller than zero and redistribute the excess "negative weight" between the positive weights

But the problem with this is that now my active weights get enlarged by getting my absolute weights to sum to 1 and then they are outside the [-0.02,0.02] active weight bounds.

Is there any way I can get my weights to sum to unity as well as making sure my active weights stay within the boundries and my portfolio only has absolute weights that are larger than zero.

Any suggestions will be appreciated!

As long as you don't have any specific distribution requirements you can use the following brute-force approach.

First we define two functions to generate random numbers that sum to a given total > 0 :

get_weights <- function(N, total = 1)
  total * diff(c(0, sort(runif(N-1)), 1))

And to zero:

get_weight_changes <- function(N, ratio = N)
  (get_weights(N) - 1/N) / ratio

See this question for notes on the algorithm. The ratio argument is an empirical parameter that controls how large a typical change is compared to a typical absolute weight. If it is to small, you will have to try very many random weight changes before one satisfies your conditions. If it is to large, your relative weight changes will be much smaller than the allowed range.

Next we generate random weights and random weight changes. The latter is done until we hit a random weight change vector that fulfills the minimum change requirement:

N <- 40
ratio <- 300

w <- get_weights(N)
dw <- get_weight_changes(N, ratio) 

while (any(abs(dw/w) > 0.02)) {
  dw <- get_weight_changes(N, ratio) 
}

Here a typical histogram of the resulting weight changes:

在此处输入图片说明

As one can see they are far from uniform, but the weight changes fulfill all the requirements.

Side note: Since there are potentially very many random numbers necessary, I use

library(dqrng)
dqRNGkind("Xoroshiro128+")
dqset.seed(42)
runif <- dqrunif

to use on of the fast RNGs from the dqrng package

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM