>600 subscribers
Share Dialog
Share Dialog
I've been wanting to do some quick back-of-the-napkin math to explore how VC power laws work. This Thanksgiving, I finally got around to it. Thanks to AI, it took me less than 15 minutes to write the code and analyze the results. I've included the Python code at the end of the post. Let’s dive in!
Basic assumptions:
In this example, I consider a $100M fund with a 7-year lifecycle. The portfolio consists of 80 companies, implying an average check size of $1M. For simplicity, the simulation assumes a standard 2/20 fee structure: a 2% annual management fee and 20% carried interest. The fund does not recycle capital or allocate reserves for follow-on rounds. Feel free to tweak the parameters below to run your own experiments.
def simulate_vc_portfolio_with_fees(num_investments=80, investment_size=10000000, years=7, management_fee=2, carry=20):The industry benchmark for a good fund performance is a MOIC = 3 (Multiple on Invested Capital). This means that if investors give you $100M, you would return $300M after seven years. While there have been exceptional cases, such as early (pre 2020) crypto VC returns, these were outliers driven by highly favorable market conditions for early adopters. Generally, achieving a 3x return is surprisingly challenging, especially when managing a large amount of money under typical market conditions.
I have run through quite a few scenarios to produce a MOIC of 3 result:
High failure rate scenario: 50% of the portfolio results in a total loss, 30% breaks even by returning the initial capital, 17.5% delivers a 5x return, and 2.5% achieves a remarkable 100x return. This yields an overall MOIC of 3.01. In a portfolio of 80 companies, this means your fund produced two unicorns.
outcomes = {
0: 0.5, #return nothing
1: 0.3, #return capital
5: 0.175, #return 5x
100: 0.025 #return 100x
}Low failure rate scenario: 25% of the portfolio results in a total loss; 55% breaks even by returning the initial capital; And the rest remains unchanged. That yields an MOIC of 3.24. In this case, we cut down the number of completely failed companies to half but it only improved the MOIC for 7% (3.01 -> 3.24)
outcomes = {
0: 0.25, #return nothing
1: 0.55, #return capital
5: 0.175, #return 5x
100: 0.025 #return 100x
}Three unicorns scenario: One of the 5x companies turns into a 100x, while the rest of the portfolio remains unchanged. The result? MOIC = 4. Wow! Even with a 50% failure rate, your fund transitions from good to great.
outcomes = {
0: 0.50, # return nothing
1: 0.30, # return capital
5: 0.1625, # return 5x
100: 0.0375 # return 100x
}The power law:
By now, the power law distribution in a venture portfolio is clear: to achieve strong returns, each fund needs to produce at least 2-3 unicorns. The failure rate matters far less than your ability to identify and invest in these high-performing outliers. Venture investing isn’t about how often you’re right—it’s about how big your wins are when you’re right and how small your losses are when you’re wrong.
Finding unicorns:
Finding a 100x unicorn is incredibly challenging. It requires alignment across multiple factors—team, market timing, narrative, product, and more—many of which are entirely outside an investor’s control. However, there’s at least one critical factor that investors can control: the initial valuation at the time of investment.
Consider the difference between investing in a company at a $20M valuation VS a $200M valuation. Achieving a 100x return would mean a $2B exit for the former and a $20B exit for the latter. Currently, if you check the front page of CoinMarketCap, the only tokens with $20B+ valuations are old L1 chains or meme tokens. However, if you lower the threshold to $2B, a much wider variety of projects meets the criteria. More variety increases everyone’s chances of discovering a unicorn.
My simulation is intentionally biased toward a large, diverse, super-early-stage VC portfolio. If you’re running a smaller and concentrated portfolio with larger check sizes or focusing on later-stage investing, I’d love to hear about your experiments. Feel free to reach out to me on X: @huangkuan.
Here’s the code snippet for running the simulation. You can execute it directly here, even if you don’t have a development environment set up on your laptop.
import numpy as np
def simulate_vc_portfolio_with_fees(num_investments=80, investment_size=10000000, years=7, management_fee=2, carry=20):
# Define the distribution of outcomes
outcomes = {
0: 0.5, # return nothing
1: 0.3, # return capital
5: 0.175, # return 5x
100: 0.025 # return 100x
}
# Generate outcomes based on the distribution
portfolio_returns = np.random.choice(
list(outcomes.keys()),
size=num_investments,
p=list(outcomes.values())
)
# Calculate total investment
total_investment = num_investments * investment_size
# Calculate total return before fees
total_return_before_fees = sum(portfolio_returns) * investment_size
# Apply management fees annually
annual_fee = total_investment * (management_fee / 100)
total_fees = annual_fee * years
# Calculate net return after management fees
net_return_after_management_fees = total_return_before_fees - total_fees
# Apply carried interest (Carry) on profit above the initial investment
profit = max(0, net_return_after_management_fees - total_investment) # Ensure no negative carry
carry_amount = profit * (carry / 100)
# Net return to investors after all fees
net_return_to_investors = net_return_after_management_fees - carry_amount
# Calculate MOIC for investors
moic = net_return_to_investors / total_investment
# Estimate IRR (very simplified approach)
irr = ((moic ** (1/years)) - 1) * 100
return {
'Total Investment': total_investment,
'Total Return Before Fees': total_return_before_fees,
'Total Management Fees': total_fees,
'Carried Interest': carry_amount,
'Net Return to Investors': net_return_to_investors,
'MOIC': moic,
'Approx IRR': f"{irr:.2f}%"
}
# Simulate one portfolio
result = simulate_vc_portfolio_with_fees()
print(result)
# Simulate multiple portfolios for more robust statistics
def multiple_simulations_with_fees(num_simulations=1000):
results = []
for _ in range(num_simulations):
simulation = simulate_vc_portfolio_with_fees()
results.append({
'MOIC': simulation['MOIC'],
'IRR': float(simulation['Approx IRR'][:-1]) # Remove the % sign
})
average_moic = np.mean([r['MOIC'] for r in results])
average_irr = np.mean([r['IRR'] for r in results])
std_moic = np.std([r['MOIC'] for r in results])
std_irr = np.std([r['IRR'] for r in results])
print(f"Average MOIC: {average_moic:.2f}")
print(f"Average IRR: {average_irr:.2f}%")
print(f"Standard Deviation MOIC: {std_moic:.2f}")
print(f"Standard Deviation IRR: {std_irr:.2f}%")
# Run multiple simulations
multiple_simulations_with_fees()I've been wanting to do some quick back-of-the-napkin math to explore how VC power laws work. This Thanksgiving, I finally got around to it. Thanks to AI, it took me less than 15 minutes to write the code and analyze the results. I've included the Python code at the end of the post. Let’s dive in!
Basic assumptions:
In this example, I consider a $100M fund with a 7-year lifecycle. The portfolio consists of 80 companies, implying an average check size of $1M. For simplicity, the simulation assumes a standard 2/20 fee structure: a 2% annual management fee and 20% carried interest. The fund does not recycle capital or allocate reserves for follow-on rounds. Feel free to tweak the parameters below to run your own experiments.
def simulate_vc_portfolio_with_fees(num_investments=80, investment_size=10000000, years=7, management_fee=2, carry=20):The industry benchmark for a good fund performance is a MOIC = 3 (Multiple on Invested Capital). This means that if investors give you $100M, you would return $300M after seven years. While there have been exceptional cases, such as early (pre 2020) crypto VC returns, these were outliers driven by highly favorable market conditions for early adopters. Generally, achieving a 3x return is surprisingly challenging, especially when managing a large amount of money under typical market conditions.
I have run through quite a few scenarios to produce a MOIC of 3 result:
High failure rate scenario: 50% of the portfolio results in a total loss, 30% breaks even by returning the initial capital, 17.5% delivers a 5x return, and 2.5% achieves a remarkable 100x return. This yields an overall MOIC of 3.01. In a portfolio of 80 companies, this means your fund produced two unicorns.
outcomes = {
0: 0.5, #return nothing
1: 0.3, #return capital
5: 0.175, #return 5x
100: 0.025 #return 100x
}Low failure rate scenario: 25% of the portfolio results in a total loss; 55% breaks even by returning the initial capital; And the rest remains unchanged. That yields an MOIC of 3.24. In this case, we cut down the number of completely failed companies to half but it only improved the MOIC for 7% (3.01 -> 3.24)
outcomes = {
0: 0.25, #return nothing
1: 0.55, #return capital
5: 0.175, #return 5x
100: 0.025 #return 100x
}Three unicorns scenario: One of the 5x companies turns into a 100x, while the rest of the portfolio remains unchanged. The result? MOIC = 4. Wow! Even with a 50% failure rate, your fund transitions from good to great.
outcomes = {
0: 0.50, # return nothing
1: 0.30, # return capital
5: 0.1625, # return 5x
100: 0.0375 # return 100x
}The power law:
By now, the power law distribution in a venture portfolio is clear: to achieve strong returns, each fund needs to produce at least 2-3 unicorns. The failure rate matters far less than your ability to identify and invest in these high-performing outliers. Venture investing isn’t about how often you’re right—it’s about how big your wins are when you’re right and how small your losses are when you’re wrong.
Finding unicorns:
Finding a 100x unicorn is incredibly challenging. It requires alignment across multiple factors—team, market timing, narrative, product, and more—many of which are entirely outside an investor’s control. However, there’s at least one critical factor that investors can control: the initial valuation at the time of investment.
Consider the difference between investing in a company at a $20M valuation VS a $200M valuation. Achieving a 100x return would mean a $2B exit for the former and a $20B exit for the latter. Currently, if you check the front page of CoinMarketCap, the only tokens with $20B+ valuations are old L1 chains or meme tokens. However, if you lower the threshold to $2B, a much wider variety of projects meets the criteria. More variety increases everyone’s chances of discovering a unicorn.
My simulation is intentionally biased toward a large, diverse, super-early-stage VC portfolio. If you’re running a smaller and concentrated portfolio with larger check sizes or focusing on later-stage investing, I’d love to hear about your experiments. Feel free to reach out to me on X: @huangkuan.
Here’s the code snippet for running the simulation. You can execute it directly here, even if you don’t have a development environment set up on your laptop.
import numpy as np
def simulate_vc_portfolio_with_fees(num_investments=80, investment_size=10000000, years=7, management_fee=2, carry=20):
# Define the distribution of outcomes
outcomes = {
0: 0.5, # return nothing
1: 0.3, # return capital
5: 0.175, # return 5x
100: 0.025 # return 100x
}
# Generate outcomes based on the distribution
portfolio_returns = np.random.choice(
list(outcomes.keys()),
size=num_investments,
p=list(outcomes.values())
)
# Calculate total investment
total_investment = num_investments * investment_size
# Calculate total return before fees
total_return_before_fees = sum(portfolio_returns) * investment_size
# Apply management fees annually
annual_fee = total_investment * (management_fee / 100)
total_fees = annual_fee * years
# Calculate net return after management fees
net_return_after_management_fees = total_return_before_fees - total_fees
# Apply carried interest (Carry) on profit above the initial investment
profit = max(0, net_return_after_management_fees - total_investment) # Ensure no negative carry
carry_amount = profit * (carry / 100)
# Net return to investors after all fees
net_return_to_investors = net_return_after_management_fees - carry_amount
# Calculate MOIC for investors
moic = net_return_to_investors / total_investment
# Estimate IRR (very simplified approach)
irr = ((moic ** (1/years)) - 1) * 100
return {
'Total Investment': total_investment,
'Total Return Before Fees': total_return_before_fees,
'Total Management Fees': total_fees,
'Carried Interest': carry_amount,
'Net Return to Investors': net_return_to_investors,
'MOIC': moic,
'Approx IRR': f"{irr:.2f}%"
}
# Simulate one portfolio
result = simulate_vc_portfolio_with_fees()
print(result)
# Simulate multiple portfolios for more robust statistics
def multiple_simulations_with_fees(num_simulations=1000):
results = []
for _ in range(num_simulations):
simulation = simulate_vc_portfolio_with_fees()
results.append({
'MOIC': simulation['MOIC'],
'IRR': float(simulation['Approx IRR'][:-1]) # Remove the % sign
})
average_moic = np.mean([r['MOIC'] for r in results])
average_irr = np.mean([r['IRR'] for r in results])
std_moic = np.std([r['MOIC'] for r in results])
std_irr = np.std([r['IRR'] for r in results])
print(f"Average MOIC: {average_moic:.2f}")
print(f"Average IRR: {average_irr:.2f}%")
print(f"Standard Deviation MOIC: {std_moic:.2f}")
print(f"Standard Deviation IRR: {std_irr:.2f}%")
# Run multiple simulations
multiple_simulations_with_fees()

No comments yet