Why Build a Random Portfolio Generator?
I don’t Like Benchmark Indexes
I am not a fan of benchmarking against widely available indexes.
Most anyone you ask will tell you that you should benchmark against an index because it is an objective measure of performance. It provides you with the “beta” that allows you to figure out if an investment manager delivers “alpha”.
Is this actually true? No. An index is a trading system in disguise. An index is created by establishing and implementing rules (inclusion, weighting, rebalancing, treatment of dividends and buybacks, etc.). The index vendor constructed those rules much the same way as a systematic manager would design their trading strategy.
Don’t look too closely: You will find some of the decisionmaking that goes into an index is discretionary. Yep, there is a committee in the background picking stocks! Both the S&P 500 and the Dow 30 have an index selection committee that picks the firms that best represents the goals of the index. Not really objective.
What Else Can You Use?
If your task is to evaluate any kind of active manager’s performance, you are trying to determine if he or she has skill or luck. The best way to do that, in my opinion, is to compare the actual manager to a random version of him or herself.
Here’s what I mean. Let’s say a manager states the basics of his strategy as follows:
We select a concentrated portfolio of stocks from the S&P 500 universe. We are fully invested at all times, long only, and do not use leverage. Our portfolio holds 20 positions. We never open a position with more than 10% or less than 2.5% of our capital.
Instead of using the manager’s skill or process, we build thousands of portfolios each month within the stated constraints and see how they perform versus our manager. If the manager significantly outperforms our random portfolios we know they add value, regardless how they do relative to the S&P 500 index itself.
Hedge Fund Selection
In my case, I put together portfolios of hedge fund and managed futures strategies. I can use the same process to evaluate my own approach to selecting managers: I compare the portfolios I create following my portfolio construction methodology with random portfolios drawn from the same universe. By choosing which aspects of the portfolio construction process are controlled or random, I can explore the impact of each aspect on the final portfolios I create.
Random Portfolio Generator
Using the random portfolio generator presented below, you can create thousands of random portfolios. You can represent pretty much any equity strategy (long only, short only, bear bias, long bias, market neutral, etc.) and any fundoffund portfolio construction technique.
This is a hedge fund hack that uses a Monte Carlo approach to evaluating a manager’s performance.
Basic Concepts
Objectives
I set out to create a tool that would build random portfolios for me. I wanted it to have the following capabilities:
 Create a fixed number of portfolios with a fixed number of assets in each portfolio as a matrix.
 Allow both long and short positions which combine to deliver a fixed net exposure.
 Control the maximum and minimum number of short positions in the portfolio.
 Control the maximum and minimum total short exposure in the portfolio.
 Set the minimum and maximum permissible size for individual long positions.
 Control the maximum and minimum size for individual short positions.
 Set the resolution of the portfolio positions (e.g. 1%, 0.1%, .01%, etc.).
 Provide optional reporting on the population of portfolios generated.
The portfoliolevel parameters on the long side (total long book and count of long positions) are the complement of the same parameters on the short side. For example, if my net position is +150% and my short book is 30%, obviously my long book will be +180%. I chose to control the portfoliolevel parameters on the short side rather than the long side as it feels more natural to me to do this. I think most people would tend to approach the problem in the order:
 What net exposure and total number of positions do I want?
 How much of that am I prepared to carry on the short side?
Additional Capabilities
Other capabilities I considered but discarded were:
 Select net exposure randomly subject to a maximum and minimum.
 Select the number of asset randomly subject to a maximum and minimum.
I discarded both these ideas because they would require much more intelligence in portfoliolevel parameters (maximum total short book, maximum number of positions in short book, etc.). For example, 100 assets with 10 short may make sense, but 20 assets with 10 short may not. It is easy enough to run the random portfolio generator inside a script setting multiple random sets of these global parameters and having them influence the perportfolio parameters. For example, you could generate 100 portfolios with 5 assets and up to 2 short positions, and another 100 with 10 assets and up to 4 short positions, etc.
Key Concept: Stars and Bars
Note 20190528: Modified the implementation to simplify dividing up the range. Don’t need to explicitly use the bars at all, just randomly select the end point of each partition WITH replacement. Need to use replacement to ensure zerosized partitions. The sample space then simply reduces to (0:N) in the notation below. This saves a couple of operations in the code. The stars and bars can be used to calculate total possible arrangements ((N + G)!/N!/G!). If this is less than the number of portfolios requested, it becomes more efficient to exhaustively derive the portfolios.
The key concept behind a random portfolio is the stars and bars approach to dividing up a range. If you are not familiar with this approach it works as follows:
Let’s say I have 10 units of something I wish to divide up into 3 groups. To divide something into 3 groups I need 2 dividers. The stars are what I want to divide and the bars are the dividers. Here are some possible arrangements:
********** = (4, 1, 5)
********** = (2, 0, 8)
I can denote the positions in the above representations as a vector (1:12). This is a sample space. I can randomly sample 2 items from the sample space without replacement and these are the random positions of my bars. I have an implicit bar at position 0, and one at position 13. Let’s say my random selections are 7 and 3. I can create a vector: (0, 3, 7, 13) – note I have sorted the random selection.
I can now create a portfolio by subtraction: vector[1] – vector[4] = (3, 4, 6). Notice they sum to 13 – I have 3 (the number of groups) too many. Subtracting 1 off each value I get: (2, 3, 5) which sums to 10.
We can generalize to N units and G groups and create our vector: V = c(0, sort(sample(1:(N + G – 1), G – 1)), N + G) where “sample” takes (G – 1) random samples without replacement from the vector (1, 2, …, N + G – 1).
Then our portfolio is simply (V[1] – V[length(V)]) – 1.
Separating Short From Long
The approach I adopt in the random portfolio generator is to complete the short side first, if there is one, and then complete the long side.
I choose the number of short positions at random from the minimum to the maximum inclusive. I make adjustments to the minimum and maximum total short exposure to ensure feasible portfolios. Then I set the total short exposure at random from between the limits. Finally, I use the stars and bars approach to build the portfolio. Individual positions are tweaked to ensure all of the individual positions are within the maximum and minimum permitted. See the two sections below about positions that are too small or too large.
Note that some of the ranges entered by the user may get truncated due to the number of positions taken. For example, if the minimum individual short position is 1%, and the minimum total short position 10% and there are 5 short positions, the minimum short position has to be 2%.
Once the short side is completed, the long book is done in a similar way. The total long book is not random as it is the net position adjusted for the total short position. For example, if the net position is set to 100%, for a given portfolio the short position is 20%, then the long position must be 120%.
Finally, I construct the full portfolio by randomly assigning the long and short positions to the available assets. e.g. my short portfolio is (8, 2, 10) and my long portfolio is (+20, +26, +14, +5, +18, +28, +9), maybe my final portfolio is (8, +20, +26, 2, 10, +14, +5, +18, +28, +9).
Dealing with Resolution
In order to use the stars and bars method, we need integer values. Therefore, we have to specify a resolution which enables us to divide up our net position into a fixed number of units: 120% with a resolution of 0.1% = 1200 units. The random portfolio generator converts everything to units at the beginning, does all the manipulation in “units”, and converts it back to percent before returning the portfolios at the end.
Preventing Positions That Are Too Small
We specify minimum position size in the inputs using minShortPos and minLongPos. If we have, say, 10 positions and a minimum of 2% for each we can reserve 20% of our assets to meet this requirement. We can reduce the stars in the stars and bars approach by 20%. After we have partitioned the remaining stars, we add 2% back to each. We are guaranteed never to have a position less than the required minimum of 2%.
Fixing Positions That Are Too Large
We can end up with individual positions that exceed the upper limit long or short because the bars are placed randomly. The random portfolio generator handles this by capping those positions at the maximum permissible and randomly distributing the excess around all the other positions. This leads to a truncated distribution of individual positions. i.e. if the cap is, say 5% on the long side, there can be a large number of 5% positions – it is all the positions of 5+% combined into the 5% bar.
An alternative approach would be to randomly resize the overlarge bars, and distribute the excess around the remaining positions. The risk in doing this is that you may create an endless process as new excess positions are created and redistributed back to the other positions. The process may never end. Another approach might be to simply resize excessively large positions, but this introduces a bias in the overall size of the book – large books become less likely. I chose my approach because I think it mimics what a portfolio manager would do: he would cap the position and reallocate to smaller positions.
The Code
NOTE: Replaced code 20190528 with slightly more efficient version.
Here is the code in R to generate random portfolios. I have tried to add in sufficient comments to make it understandable. Any questions, just ask. If you use the code and would like to change it in any way, please make a suggestion in the comments. Similarly, if you find ways to break it, let me know – I will try to improve it.
Note: Sometimes, with edgecases you can get the random portfolio generator to fail. The code strays into a nonfeasible area, but I have not yet figured out how to trap the problem!
# Random Portfolio Generator  using stars and bars to divide up allocations into n random parts # Ian Rayner May 2019 MakePorts < function(count=100, assets=5, resolution=1, report=F, netPosition=100, minLongPos=10, maxLongPos=40, minShortCount=0, minShortPos=0, minShortTotal=0, maxShortCount=0, maxShortPos=0, maxShortTotal=0){ # count = number of portfolios # assets = number of positions in each portfolio # resolution = minimum increment in % for each position # report = print portfolio diagnostic report # netPosition = % overall exposure of portfolio (indirectly sets min. and maxx. long positions) # minLongPos = minimum size of a position given a position is long # maxLongPos = maximum size of a position given a position is long # minShortCount = smallest number of short positions # minShortPos = minimum size of a position given a position is short (negative) # minShortTotal = smallest total short position (negative) # maxShortCount = largest number of short positions # maxShortPos = maximum size of a position given a position is short (negative) # maxShortTotal = largest total short position (negative) if (assets <= 1) stop("Need at least 2 assets") if (maxShortCount >= assets  minShortCount >= assets) stop(paste("Total assets:", assets, "Max short assets:", maxShortCount, "Min short assets", minShortCount)) if ((assets  maxShortCount) * maxLongPos < netPosition  maxShortTotal) stop(paste("maxLongPos too small, or maxShortCount, maxShortTotal, and netPosition too large.")) if ((assets  minShortCount) * minLongPos > netPosition  minShortTotal) stop(paste("minLongPos and netPosition too large, or minShortCount and minShortTotal too small.")) if (maxLongPos < minLongPos) stop("maxLongPos < minLongPos") # Scale values netPosition < netPosition / resolution minLongPos < minLongPos / resolution maxLongPos < maxLongPos / resolution minShortPos < minShortPos / resolution maxShortPos < maxShortPos / resolution minShortTotal < minShortTotal / resolution maxShortTotal < maxShortTotal / resolution # Reset values as appropriate if (minShortPos >= 0) message(paste0("Resetting minShortPos from ", resolution * minShortPos, " to ", resolution)) minShortPos < min(minShortPos, 1) if (floor(minShortTotal / minShortPos) < maxShortCount) message(paste0("Resetting maxShortCount from ", maxShortCount, " to ", floor(minShortTotal / minShortPos))) maxShortCount < min(floor(minShortTotal / minShortPos), maxShortCount) portfolios < matrix(0, ncol=assets, nrow=count) if (maxShortPos < 0 & maxShortTotal < 0) { if (maxShortCount < minShortCount) stop("maxShortCount < minShortCount") if (maxShortPos > minShortPos) stop("maxShortPos > minShortPos") if (maxShortTotal > minShortTotal) stop("maxShortTotal > minShortTotal") maxShortTotal < max(maxShortTotal, maxShortPos * maxShortCount) for (i in 1:count){ randLongShort < rep(F, assets) # Set short part of portfolio first shortCount < ifelse(minShortCount == maxShortCount, minShortCount, sample(minShortCount:maxShortCount, 1)) if (shortCount > 0){ randLongShort[sample(assets, shortCount)] < T if (shortCount == 1){ shortPort < sample(min(1, minShortPos, minShortTotal):maxShortPos, 1) }else{ maxShortTotalLocal < max(shortCount * maxShortPos, maxShortTotal) # given number of positions, largest possible total smallestShort < min(minShortTotal  maxShortPos * (shortCount  1), minShortPos) # constrain minimum short position minShortTotalLocal < min(minShortTotal, smallestShort * shortCount) # constrain minimum total position sampleSpace < sample((minShortTotalLocal:maxShortTotalLocal)  shortCount * smallestShort, 1) # reduce sample space to allow for smallest short partStops < sort(sample(0:sampleSpace, shortCount  1, replace=T)) # randomly select for end of each partition shortPort < c(sampleSpace, partStops)  c(partStops, 0) + smallestShort # figure differences and add back minimum short position if (sum(shortPort) > minShortTotal) browser() underPositions < shortPort >= maxShortPos # Now correct for oversort positions while(!all(underPositions)){ underPositions < shortPort > maxShortPos shortExcess < sum(pmin(shortPort  maxShortPos, 0)) # total all the overages underCount < sum(underPositions) # count the number of positions to allocate overage to excessPartStops < sort(sample(0:shortExcess, underCount  1, replace=T)) # randomly divide up the excess deltas < c(shortExcess, excessPartStops)  c(excessPartStops, 0) # figure differences shortPort < pmax(shortPort, maxShortPos) # cap the too large positions at the max shortPort[underPositions] < shortPort[underPositions] + deltas underPositions < shortPort >= maxShortPos # check for any new excess positions } if (sum(shortPort) > minShortTotal) browser() } portfolios[i, randLongShort] < shortPort } } }else{message("Assuming no short positions based on maxShortPos and maxShortTotal")} for (i in 1:count){ longShort < portfolios[i, ] >= 0 if (sum(!longShort) < minShortCount) { longShort[sample(which(longShort), minShortCount  sum(!longShort))] < F} longCount < sum(longShort) longTotal < netPosition  sum(portfolios[i, ]) if (longCount == 1){ longPort < longTotal }else{ smallestLong < max(longTotal  maxLongPos * (longCount  1), minLongPos) sampleSpace < longTotal  longCount * smallestLong partStops < sort(sample(0:sampleSpace, longCount  1, replace=T)) longPort < c(partStops, sampleSpace)  c(0, partStops) + smallestLong overPositions < longPort <= maxLongPos while(!all(overPositions)){ overPositions < longPort < maxLongPos longExcess < sum(pmax(longPort  maxLongPos, 0)) # total all the overages overCount < sum(overPositions) # count the number of positions to allocate overage to excessPartStops < sort(sample(0:longExcess, overCount  1, replace=T)) # randomly divide up the excess deltas < c(excessPartStops, longExcess)  c(0, excessPartStops) # figure differences longPort < pmin(longPort, maxLongPos) # cap the too large positions at the max longPort[overPositions] < longPort[overPositions] + deltas # adjusted positions overPositions < longPort <= maxLongPos # check for any new excess positions } } portfolios[i, longShort] < longPort } if (report){ hist(rowSums(portfolios) * resolution, main="Net Portfolio Position", xlab="Size", col="grey") dev.new() hist(portfolios * resolution, main="Individual Positions", xlab="Size", col="grey") message("Summary of portfolio net positions: ") print(summary(rowSums(portfolios))) message(paste0("Total flat positions: ", sum(apply(portfolios, 1, function(vect) sum(vect == 0))), " out of ", count * assets, " total positions")) message("Smallest single long position: ", min(apply(portfolios,1,function(vect) min(vect[vect >= 0]))) * resolution) message("Largest single long position: ", max(portfolios) * resolution) message("Fewest long positions in any portfolio: ", min(apply(portfolios,1,function(vect) sum(vect >= 0)))) message("Least long portfolio: ", min(apply(portfolios,1,function(vect) sum(vect[vect >= 0]))) * resolution) message("Most long positions in any portfolio: ", max(apply(portfolios,1,function(vect) sum(vect >= 0)))) message("Most long portfolio: ", max(apply(portfolios,1,function(vect) sum(vect[vect >= 0]))) * resolution) if (maxShortPos < 0 & maxShortTotal < 0) { # long histograms are only relevent if there are short positions dev.new() hist(apply(portfolios,1,function(vect) sum(vect >= 0)), col="grey", main="Portfolio Long Books", xlab="Number of Long Positions") dev.new() hist(apply(portfolios,1,function(vect) sum(vect[vect >= 0])) * resolution, col="grey", main="Portfolio Long Books", xlab="Total Long Positions") dev.new() hist(apply(portfolios,1,function(vect) sum(vect < 0)), col="grey", main="Portfolio Short Books", xlab="Number of Short Positions") dev.new() hist(apply(portfolios,1,function(vect) sum(vect[vect < 0])) * resolution, col="grey", main="Portfolio Short Books", xlab="Total Short Positions") message("Fewest short positions in any portfolio: ", min(apply(portfolios,1,function(vect) sum(vect < 0)))) message("Smallest single short position: ", max(apply(portfolios,1,function(vect) max(vect[vect < 0]))) * resolution) message("Least short portfolio: ", max(apply(portfolios,1,function(vect) sum(vect[vect < 0]))) * resolution) message("Most short positions in any portfolio: ", max(apply(portfolios,1,function(vect) sum(vect < 0)))) message("Largest single short position: ", min(portfolios) * resolution) message("Most short portfolio: ", min(apply(portfolios,1,function(vect) sum(vect[vect < 0]))) * resolution) } } return(portfolios * resolution) }
The inputs to the random portfolio generator are as follows:
 count = number of portfolios
 assets = number of positions in each portfolio
 resolution = minimum increment in % for each position
 report = print portfolio diagnostic report
 netPosition = % overall exposure of portfolio (indirectly sets min. and max. long book.)
 minLongPos = % minimum size of a position given a position is long
 maxLongPos = % maximum size of a position given a position is long
 minShortCount = smallest number of short positions
 minShortPos = % minimum size of a position given a position is short (negative)
 minShortTotal = % smallest total short position (negative)
 maxShortCount = largest number of short positions
 maxShortPos = % maximum size of a position given a position is short (negative)
 maxShortTotal = % largest total short position (negative)
Sample Results
To give you an idea of the kind of results you can generate, I have put some of the reporting output below. The first example is a randomly generated set of 100 marketneutral portfolios, the second is a set of 130/30 style portfolios. The final set is for a set of portfolios, each of 12 positions, longonly to represent a random fund of hedge funds.
To get the R function to produce the reports, simply set “report” to “T” in the function call.
Market Neutral
Inputs for a Market Neutral Portfolio
The inputs to the function call I chose were as follows:

 Number of portfolios to generate, count = 1000
 Number of positions, or assets, in the portfolio, assets = 100
 Position resolution, resolution = 0.1%
 Net position for a market neutral portfolio, netPosition = 0%
 Smallest long position, minLongPos = 0.1%
 Largest long position, maxLongPos = 5%
 Fewest short positions in the portfolio, minShortCount = 30
 Smallest, or least short position, minShortPos = 0.1%
 Smallest short book in a portfolio, minShortTotal = 50%
 Most short positions in the portfolio, maxShortCount = 70
 Largest, or most short position, maxShortPos = 5%
 Largest short book in a portfolio, minShortTotal = 100%
The number of short positions was chosen to be symmetrical around 50, or half the total positions in the portfolio. The size of the short book was chosen to give a wide spread of total exposure. Obviously, if the total assets are set to 100, and the overall book is neutral, you can figure out the complementary values on the long side.
Reporting
The function reports back all the information above but derived from the actual portfolios so you can confirm you got what you expected. It also tells me the total number of flat positions. In this case, there were none as expected due to the min long and min short parameters.
The charts give a good visual overview of the portfolios. In the first chart, you can clearly see the effect of truncating positions to the max and min permitted in the tall bars at the left and right. Without the truncation, the values would show long tails. You can see that the ranges conform to the input values. You can also see that the long and short books are complementary as you would expect in market neutral portfolios.
130 Long 30 Short Portfolio
Inputs for a 130/30 Portfolio
The inputs to the function call I chose were the same as above except as follows:

 Net position for a market neutral portfolio, netPosition = 100%
 Smallest long position, minLongPos = 1%
 Fewest short positions in the portfolio, minShortCount = 15
 Smallest, or least short position, minShortPos = 1%
 Smallest short book in a portfolio, minShortTotal = 30%
 Most short positions in the portfolio, maxShortCount = 35
 Largest short book in a portfolio, minShortTotal = 30%
I chose 1% and 1% as the smallest individual position sizes just to make the histograms more interesting! This time I have set minShortTotal and maxShortTotal to the same value, 30%. Naturally, this forces the long side to +130%. Thus, every portfolio will be 130% long and 30% short.
I chose 15 and 35 as the min and max short position count as they are symmetrical about 25% (30% / 130% ~ 25%). This will also illustrate an interesting aspect of the random portfolio generator.
Reporting
The generator reports back that the value of 35 short positions was reset to 30. If the smallest short position is 1% and the maximum total short is 30%, then you can only ever carry a maximum of 30 positions. The function adjusts to this reality.
The more interesting histograms are presented nearby. Notice the big gap in the distribution of individual positions. This is because we told the generator that all short positions were to be 1% or more short, and all long positions were to be +1% or more.
If you are observant, your spidey senses should be set off by the large bars that don’t seem to fit in the position count histograms. This is an effect you get with histograms of integer values: the first bar includes BOTH 15 and 16 positions on the short side and 70 and 71 positions on the long side. The range of each bar except the first is closed on the right and open on the left. The first bar is closed both sides.
The same effect is causing the first bar on the long side of the individual positions histogram to look unusually short – it contains only the positions that are exactly 1%!
If you check the earlier example, you can see the effect there too. It is less obvious because the bars cover 5 values each – they are about 20% taller than you would naively expect.
Fund of Hedge Fund Portfolios
Inputs for a FoHF Portfolio
The inputs to the function call I chose were as follows:

 Number of positions, assets = 12
 Net position, netPosition = 100%
 Resolution of positions, resolution = 1%
 Smallest long position, minLongPos = 6%
 Largest long position, maxLongPos = 25%
 All shortrelated parameters set to zero.
Reporting
The individual positions histogram is presented nearby. It looks as you would expect, with many more small positions than large. Remember the first bar contains both 6 and 7% positions. There are a couple of 25% positions, showing the effectiveness of the “stars and bars” approach at providing full coverage of the range of possibilities.
Conclusion
Let me know if you have any questions or suggestions concerning the random portfolio generator. If you would like me to email you a copy, use the contact form or request it via LinkedIn. I would especially appreciate it if you would let me know if you find an issue with the script.
Share
If you found this post informative, please share it!