Do 2x prefs on early exits make a difference to investors?

Dave McClure recently sent out this tweetstorm, arguing in favor of 2x preferences on notes for early stage investments.  Dave’s passion made me wonder if it was an emotional concern or if it actually moved the needle.  I asked him, and he responded stating that “if I have a few unicorns, it prob doesn’t matter.  if I don’t, then it matters more.”  That was in line with my intuition, but I was interested in a more precise answer. Unfortunately, I don’t have access to a real database of venture investments and exits, so I sought out base rate information on VC investment results.  I decided to use the following data from Seth Levine’s article on venture outcomes.

Distribution of US Venture Returns
Distribution of US Venture Returns

Given that data, and the knowledge that the actual results likely follow a power law distribution I sought a mathematically valid way to simulate underlying results.  After some discussion, Austin Rochford kindly suggested that I start by using “a basic probability integral transformation” approach.  After ensuring that I understood what that meant (selecting buckets using  base rate probabilities, then treating outcomes within buckets as though they're distributed uniformly), I simulated two scenarios.

The first scenario is extremely to the above base rates, but with the additional knowledge that approximately 1/3 of the investments go all the way to zero.  The second scenario being the same as the first, except with modifications that make 1-2x results a bit more likely than partial return of capital results in order to simulate a 2x preference on early exits. I assumed 30 investments per fund (which is lower than then number of companies funded by each of 500 Startups' funds), and ran 100,000 iterations of the simulation.

So, do they matter?

A bit. The following violin plot shows the distribution of gross realized multiples for funds in both the base case and the case with 2x preferences for early exits. The performance of the bottom decile of funds is improved by around 10%, but the fund's LPs aren’t going to be throwing any parades. The clause improves upper decile by around 3%.  It's a visible difference, but it doesn't turn poor results into Shinola.

I would have preferred a dataset that included timing information, so I could make a realistic attempt at calculating then effect on other measures of portfolio performance, such as IRR, instead of only having only timing-free gross realized multiples.  That said, it was still interesting, and a good excuse to learn how to use Seaborn.

The text of the IPython Notebook used to generate the chart is below:

In [1]:
matplotlib inline
In [2]:
import matplotlib.pyplot as plt
import numpy as np
import random
import seaborn as sns

from collections import defaultdict 
In [4]:
def pit_generate(bins, cnt):
	# generates N results, using probability integral transformation
	for _ in xrange(cnt):
		bin_selector = random.random()
		for bin in bins:
			if bin_selector < bin[0]:
				yield random.uniform(bin[1], bin[2])
				break
In [5]:
def portfolio_generate(bins, size=100):
	while True:
		portfolio_returns = []
		for gmr in pit_generate(bins, size):
			portfolio_returns.append(gmr)
		yield sum(portfolio_returns)/size
In [6]:
# setup bin data for some basic probability integral transformation
# this uses the known bin probabilities 
# the tuple is structured as follows:
#    item 0 - cumulative probability of bin being the selected bin
#    item 1 - lower bound (inclusive) of bin
#    item 2 -- upper bound (exclusive) of bin
# the list of bins must be sorted in order of cumulative probability
#
# In this case, these bins represent the gross realized multiple ranges in 
# 	http://www.sethlevine.com/wp/2014/08/venture-outcomes-are-even-more-skewed-than-you-think
distribution = defaultdict(list)
distribution['a'].append((.333,0,0.01))
distribution['a'].append((.648,0,1))
distribution['a'].append((distribution['a'][-1][0] + .253,1,5))
distribution['a'].append((distribution['a'][-1][0] + .059,5,10))
distribution['a'].append((distribution['a'][-1][0] + .025,10,20))
distribution['a'].append((distribution['a'][-1][0] + .011,20,50))
distribution['a'].append((distribution['a'][-1][0] + .004,50,100))

distribution['b'].append((.333,0,0.01))
distribution['b'].append((.648,1,2))
distribution['b'].append((distribution['b'][-1][0] + .253,1,5))
distribution['b'].append((distribution['b'][-1][0] + .059,5,10))
distribution['b'].append((distribution['b'][-1][0] + .025,10,20))
distribution['b'].append((distribution['b'][-1][0] + .011,20,50))
distribution['b'].append((distribution['b'][-1][0] + .004,50,100))
In [8]:
returns = defaultdict(list)
portfolio_size = 30
portfolio_cnt = 100000

distributions = {}
for key in distribution.keys():
	 distributions[key] = portfolio_generate(distribution[key], size=portfolio_size)
In [9]:
results = []
for i in xrange(portfolio_cnt):
	arr = []
	for key in sorted(distribution.keys()):
		arr.append(distributions[key].next())
	results.append(arr)
In [10]:
sns.set_context('poster')
plt.figure(figsize=(8, 6))
sns.violinplot(np.array(results), names=['base case', '2x early exit pref'])
Out[10]:
In []: