Spaces:
Sleeping
Sleeping
add: comparison of multiple exit scenarios
Browse files- equity_calculator.py +404 -297
equity_calculator.py
CHANGED
@@ -4,201 +4,173 @@ import plotly.graph_objects as go
|
|
4 |
import plotly.express as px
|
5 |
from plotly.subplots import make_subplots
|
6 |
|
7 |
-
def
|
8 |
-
|
9 |
-
total_shares, your_options, strike_price,
|
10 |
-
# Seed round
|
11 |
seed_shares, seed_capital, seed_multiple, seed_participating,
|
12 |
-
# Series A
|
13 |
series_a_shares, series_a_capital, series_a_multiple, series_a_participating,
|
14 |
-
|
15 |
-
series_b_shares, series_b_capital, series_b_multiple, series_b_participating,
|
16 |
-
# Exit
|
17 |
-
exit_valuation
|
18 |
):
|
19 |
-
"""Calculate
|
20 |
-
|
21 |
-
# Handle None values and provide defaults
|
22 |
-
total_shares = total_shares or 10000000
|
23 |
-
your_options = your_options or 0
|
24 |
-
strike_price = strike_price or 0
|
25 |
-
seed_shares = seed_shares or 0
|
26 |
-
seed_capital = seed_capital or 0
|
27 |
-
seed_multiple = seed_multiple or 1.0
|
28 |
-
seed_participating = seed_participating or False
|
29 |
-
series_a_shares = series_a_shares or 0
|
30 |
-
series_a_capital = series_a_capital or 0
|
31 |
-
series_a_multiple = series_a_multiple or 1.0
|
32 |
-
series_a_participating = series_a_participating or False
|
33 |
-
series_b_shares = series_b_shares or 0
|
34 |
-
series_b_capital = series_b_capital or 0
|
35 |
-
series_b_multiple = series_b_multiple or 1.0
|
36 |
-
series_b_participating = series_b_participating or False
|
37 |
-
exit_valuation = exit_valuation or 0
|
38 |
-
|
39 |
-
# Input validation
|
40 |
-
if total_shares <= 0 or your_options < 0 or exit_valuation < 0:
|
41 |
-
return "Invalid inputs - please check your values", None, None
|
42 |
|
43 |
-
# Calculate common shares
|
44 |
total_preferred_shares = seed_shares + series_a_shares + series_b_shares
|
45 |
common_shares = total_shares - total_preferred_shares
|
46 |
|
47 |
if common_shares <= 0:
|
48 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
-
#
|
51 |
remaining_proceeds = exit_valuation
|
52 |
-
|
53 |
-
participating_shareholders = [] # Track participating preferred for later distribution
|
54 |
-
|
55 |
-
# Phase 1: Pay liquidation preferences first
|
56 |
|
57 |
-
# Series B
|
58 |
series_b_preference_payout = 0
|
59 |
if series_b_shares > 0 and series_b_capital > 0:
|
60 |
series_b_preference = series_b_capital * series_b_multiple
|
61 |
series_b_preference_payout = min(remaining_proceeds, series_b_preference)
|
62 |
remaining_proceeds -= series_b_preference_payout
|
63 |
-
|
64 |
if series_b_participating:
|
65 |
-
participating_shareholders.append({
|
66 |
-
'round': 'Series B',
|
67 |
-
'shares': series_b_shares,
|
68 |
-
'preference_paid': series_b_preference_payout
|
69 |
-
})
|
70 |
-
|
71 |
-
waterfall_data.append({
|
72 |
-
'Round': 'Series B (Pref)',
|
73 |
-
'Preference': series_b_preference,
|
74 |
-
'Payout': series_b_preference_payout,
|
75 |
-
'Remaining': remaining_proceeds,
|
76 |
-
'Type': 'Preference'
|
77 |
-
})
|
78 |
|
79 |
-
# Series A
|
80 |
series_a_preference_payout = 0
|
81 |
if series_a_shares > 0 and series_a_capital > 0:
|
82 |
series_a_preference = series_a_capital * series_a_multiple
|
83 |
series_a_preference_payout = min(remaining_proceeds, series_a_preference)
|
84 |
remaining_proceeds -= series_a_preference_payout
|
85 |
-
|
86 |
if series_a_participating:
|
87 |
-
participating_shareholders.append({
|
88 |
-
'round': 'Series A',
|
89 |
-
'shares': series_a_shares,
|
90 |
-
'preference_paid': series_a_preference_payout
|
91 |
-
})
|
92 |
-
|
93 |
-
waterfall_data.append({
|
94 |
-
'Round': 'Series A (Pref)',
|
95 |
-
'Preference': series_a_preference,
|
96 |
-
'Payout': series_a_preference_payout,
|
97 |
-
'Remaining': remaining_proceeds,
|
98 |
-
'Type': 'Preference'
|
99 |
-
})
|
100 |
|
101 |
-
# Seed
|
102 |
seed_preference_payout = 0
|
103 |
if seed_shares > 0 and seed_capital > 0:
|
104 |
seed_preference = seed_capital * seed_multiple
|
105 |
seed_preference_payout = min(remaining_proceeds, seed_preference)
|
106 |
remaining_proceeds -= seed_preference_payout
|
107 |
-
|
108 |
if seed_participating:
|
109 |
-
participating_shareholders.append({
|
110 |
-
'round': 'Seed',
|
111 |
-
'shares': seed_shares,
|
112 |
-
'preference_paid': seed_preference_payout
|
113 |
-
})
|
114 |
-
|
115 |
-
waterfall_data.append({
|
116 |
-
'Round': 'Seed (Pref)',
|
117 |
-
'Preference': seed_preference,
|
118 |
-
'Payout': seed_preference_payout,
|
119 |
-
'Remaining': remaining_proceeds,
|
120 |
-
'Type': 'Preference'
|
121 |
-
})
|
122 |
-
|
123 |
-
# Phase 2: Distribute remaining proceeds
|
124 |
|
125 |
-
#
|
126 |
-
# This includes: common shares + participating preferred shares
|
127 |
participating_preferred_shares = sum([p['shares'] for p in participating_shareholders])
|
128 |
total_participating_shares = common_shares + participating_preferred_shares
|
129 |
|
130 |
-
#
|
131 |
-
# than taking the liquidation preference
|
132 |
-
|
133 |
-
# Series B non-participating conversion check
|
134 |
if series_b_shares > 0 and series_b_capital > 0 and not series_b_participating:
|
135 |
-
# Calculate what they'd get if they converted to common
|
136 |
conversion_value = (series_b_shares / total_shares) * exit_valuation
|
137 |
if conversion_value > series_b_preference_payout:
|
138 |
-
# They convert - add back their preference and include them in common distribution
|
139 |
remaining_proceeds += series_b_preference_payout
|
140 |
total_participating_shares += series_b_shares
|
141 |
-
|
142 |
-
for item in waterfall_data:
|
143 |
-
if item['Round'] == 'Series B (Pref)':
|
144 |
-
item['Round'] = 'Series B (Converted)'
|
145 |
-
item['Payout'] = 0 # They'll get paid in common distribution
|
146 |
-
item['Type'] = 'Conversion'
|
147 |
-
|
148 |
-
# Series A non-participating conversion check
|
149 |
if series_a_shares > 0 and series_a_capital > 0 and not series_a_participating:
|
150 |
conversion_value = (series_a_shares / total_shares) * exit_valuation
|
151 |
if conversion_value > series_a_preference_payout:
|
152 |
remaining_proceeds += series_a_preference_payout
|
153 |
total_participating_shares += series_a_shares
|
154 |
-
for item in waterfall_data:
|
155 |
-
if item['Round'] == 'Series A (Pref)':
|
156 |
-
item['Round'] = 'Series A (Converted)'
|
157 |
-
item['Payout'] = 0
|
158 |
-
item['Type'] = 'Conversion'
|
159 |
|
160 |
-
# Seed non-participating conversion check
|
161 |
if seed_shares > 0 and seed_capital > 0 and not seed_participating:
|
162 |
conversion_value = (seed_shares / total_shares) * exit_valuation
|
163 |
if conversion_value > seed_preference_payout:
|
164 |
remaining_proceeds += seed_preference_payout
|
165 |
total_participating_shares += seed_shares
|
166 |
-
for item in waterfall_data:
|
167 |
-
if item['Round'] == 'Seed (Pref)':
|
168 |
-
item['Round'] = 'Seed (Converted)'
|
169 |
-
item['Payout'] = 0
|
170 |
-
item['Type'] = 'Conversion'
|
171 |
|
172 |
-
# Final distribution
|
173 |
if total_participating_shares > 0:
|
174 |
price_per_participating_share = remaining_proceeds / total_participating_shares
|
175 |
common_proceeds = price_per_participating_share * common_shares
|
176 |
-
|
177 |
-
# Add participating preferred payouts to waterfall
|
178 |
-
for participant in participating_shareholders:
|
179 |
-
participating_payout = price_per_participating_share * participant['shares']
|
180 |
-
waterfall_data.append({
|
181 |
-
'Round': f"{participant['round']} (Participating)",
|
182 |
-
'Preference': 0,
|
183 |
-
'Payout': participating_payout,
|
184 |
-
'Remaining': remaining_proceeds - participating_payout,
|
185 |
-
'Type': 'Participation'
|
186 |
-
})
|
187 |
else:
|
188 |
-
price_per_participating_share = 0
|
189 |
common_proceeds = remaining_proceeds
|
190 |
|
191 |
-
|
192 |
-
if common_shares > 0:
|
193 |
-
price_per_common_share = common_proceeds / common_shares
|
194 |
-
else:
|
195 |
-
price_per_common_share = 0
|
196 |
-
|
197 |
-
# Calculate your option value
|
198 |
option_value_per_share = max(0, price_per_common_share - strike_price)
|
199 |
total_option_value = option_value_per_share * your_options
|
200 |
|
201 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
202 |
your_equity_percentage = (your_options / total_shares) * 100 if total_shares > 0 else 0
|
203 |
|
204 |
# Build results summary
|
@@ -207,166 +179,264 @@ def calculate_equity_value(
|
|
207 |
if series_a_shares > 0: participating_status.append(f"Series A: {'Participating' if series_a_participating else 'Non-Participating'}")
|
208 |
if series_b_shares > 0: participating_status.append(f"Series B: {'Participating' if series_b_participating else 'Non-Participating'}")
|
209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
results = f"""
|
211 |
-
## π° Your Equity
|
212 |
|
213 |
-
**
|
214 |
-
**
|
215 |
**Your Equity Stake:** {your_equity_percentage:.3f}%
|
216 |
|
217 |
-
|
218 |
-
|
219 |
-
**Exit Valuation:** ${exit_valuation:,.2f}
|
220 |
-
**Common Stock Proceeds:** ${common_proceeds:,.2f}
|
221 |
-
**Price per Common Share:** ${price_per_common_share:.4f}
|
222 |
-
|
223 |
-
**Liquidation Terms:** {' | '.join(participating_status) if participating_status else 'No preferred rounds'}
|
224 |
-
|
225 |
-
**Break-even Exit Value:** ${(strike_price * total_shares):,.2f}
|
226 |
-
*(Exit value needed for your options to have value)*
|
227 |
|
228 |
## ποΈ Cap Table Summary
|
229 |
|
230 |
**Total Shares:** {total_shares:,}
|
231 |
**Common Shares:** {common_shares:,}
|
232 |
**Preferred Shares:** {total_preferred_shares:,}
|
|
|
|
|
|
|
|
|
|
|
233 |
"""
|
234 |
-
|
235 |
-
# Create
|
236 |
-
if
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
x=
|
252 |
-
y=
|
253 |
-
name=
|
254 |
-
marker_color=
|
255 |
-
text=f"${
|
256 |
-
textposition='
|
257 |
-
)
|
|
|
|
|
258 |
|
259 |
-
#
|
260 |
-
|
261 |
-
|
262 |
-
x=
|
263 |
-
y=
|
264 |
-
name=
|
265 |
-
marker_color='#
|
266 |
-
text=f"${
|
267 |
-
textposition='
|
268 |
-
|
|
|
|
|
|
|
269 |
|
270 |
fig.update_layout(
|
271 |
-
title="
|
272 |
-
|
273 |
-
yaxis_title="Payout ($)",
|
274 |
showlegend=True,
|
275 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
276 |
)
|
277 |
|
278 |
-
|
279 |
else:
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
|
|
297 |
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
|
|
|
|
|
|
304 |
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
310 |
|
311 |
-
if
|
312 |
-
|
313 |
-
temp_remaining -= temp_payout
|
314 |
-
if seed_participating:
|
315 |
-
temp_participating_shareholders.append({'shares': seed_shares})
|
316 |
|
317 |
-
|
318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
|
320 |
-
|
321 |
-
|
322 |
-
conversion_value = (series_b_shares / total_shares) * ev
|
323 |
-
preference_value = series_b_capital * series_b_multiple
|
324 |
-
if conversion_value > preference_value:
|
325 |
-
temp_remaining += min(temp_remaining + preference_value, preference_value)
|
326 |
-
temp_total_participating += series_b_shares
|
327 |
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
|
|
|
|
|
|
|
|
334 |
|
335 |
-
if
|
336 |
-
|
337 |
-
preference_value = seed_capital * seed_multiple
|
338 |
-
if conversion_value > preference_value:
|
339 |
-
temp_remaining += min(temp_remaining + preference_value, preference_value)
|
340 |
-
temp_total_participating += seed_shares
|
341 |
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
347 |
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
367 |
)
|
368 |
|
369 |
-
return
|
370 |
|
371 |
# Create Gradio interface
|
372 |
with gr.Blocks(title="Startup Equity Calculator", theme=gr.themes.Soft()) as app:
|
@@ -377,20 +447,20 @@ with gr.Blocks(title="Startup Equity Calculator", theme=gr.themes.Soft()) as app
|
|
377 |
with gr.Column():
|
378 |
gr.Markdown("## Cap Table Structure")
|
379 |
total_shares = gr.Number(label="Total Fully Diluted Shares", value=10000000, precision=0)
|
380 |
-
your_options = gr.Number(label="Your Option Grant", value=
|
381 |
strike_price = gr.Number(label="Strike Price per Share ($)", value=0.10, precision=4)
|
382 |
|
383 |
gr.Markdown("## Funding Rounds")
|
384 |
|
385 |
-
with gr.Accordion("Seed Round", open=
|
386 |
-
seed_shares = gr.Number(label="Seed Shares Issued", value=
|
387 |
-
seed_capital = gr.Number(label="Seed Capital Raised ($)", value=
|
388 |
seed_multiple = gr.Number(label="Liquidation Multiple", value=1.0, precision=1)
|
389 |
seed_participating = gr.Checkbox(label="Participating Preferred", value=False)
|
390 |
|
391 |
-
with gr.Accordion("Series A", open=
|
392 |
-
series_a_shares = gr.Number(label="Series A Shares Issued", value=
|
393 |
-
series_a_capital = gr.Number(label="Series A Capital Raised ($)", value=
|
394 |
series_a_multiple = gr.Number(label="Liquidation Multiple", value=1.0, precision=1)
|
395 |
series_a_participating = gr.Checkbox(label="Participating Preferred", value=False)
|
396 |
|
@@ -401,16 +471,42 @@ with gr.Blocks(title="Startup Equity Calculator", theme=gr.themes.Soft()) as app
|
|
401 |
series_b_participating = gr.Checkbox(label="Participating Preferred", value=False)
|
402 |
|
403 |
with gr.Column():
|
404 |
-
gr.Markdown("## Exit
|
405 |
-
|
406 |
|
407 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
408 |
|
409 |
results_text = gr.Markdown()
|
410 |
|
411 |
with gr.Row():
|
412 |
-
|
413 |
-
|
|
|
|
|
|
|
414 |
|
415 |
# Set up the calculation trigger
|
416 |
inputs = [
|
@@ -418,10 +514,14 @@ with gr.Blocks(title="Startup Equity Calculator", theme=gr.themes.Soft()) as app
|
|
418 |
seed_shares, seed_capital, seed_multiple, seed_participating,
|
419 |
series_a_shares, series_a_capital, series_a_multiple, series_a_participating,
|
420 |
series_b_shares, series_b_capital, series_b_multiple, series_b_participating,
|
421 |
-
|
|
|
|
|
|
|
|
|
422 |
]
|
423 |
|
424 |
-
outputs = [results_text, waterfall_plot,
|
425 |
|
426 |
calculate_btn.click(calculate_equity_value, inputs=inputs, outputs=outputs)
|
427 |
|
@@ -430,26 +530,33 @@ with gr.Blocks(title="Startup Equity Calculator", theme=gr.themes.Soft()) as app
|
|
430 |
input_component.change(calculate_equity_value, inputs=inputs, outputs=outputs)
|
431 |
|
432 |
gr.Markdown("""
|
433 |
-
## π How
|
434 |
-
|
435 |
-
###
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
453 |
""")
|
454 |
|
455 |
if __name__ == "__main__":
|
|
|
4 |
import plotly.express as px
|
5 |
from plotly.subplots import make_subplots
|
6 |
|
7 |
+
def calculate_single_scenario(
|
8 |
+
exit_valuation, total_shares, your_options, strike_price,
|
|
|
|
|
9 |
seed_shares, seed_capital, seed_multiple, seed_participating,
|
|
|
10 |
series_a_shares, series_a_capital, series_a_multiple, series_a_participating,
|
11 |
+
series_b_shares, series_b_capital, series_b_multiple, series_b_participating
|
|
|
|
|
|
|
12 |
):
|
13 |
+
"""Calculate equity value for a single exit scenario"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
15 |
+
# Calculate common shares
|
16 |
total_preferred_shares = seed_shares + series_a_shares + series_b_shares
|
17 |
common_shares = total_shares - total_preferred_shares
|
18 |
|
19 |
if common_shares <= 0:
|
20 |
+
return {
|
21 |
+
'exit_valuation': exit_valuation,
|
22 |
+
'option_value': 0,
|
23 |
+
'price_per_share': 0,
|
24 |
+
'common_proceeds': 0,
|
25 |
+
'error': 'Preferred shares exceed total shares'
|
26 |
+
}
|
27 |
|
28 |
+
# Phase 1: Pay liquidation preferences
|
29 |
remaining_proceeds = exit_valuation
|
30 |
+
participating_shareholders = []
|
|
|
|
|
|
|
31 |
|
32 |
+
# Series B (most recent)
|
33 |
series_b_preference_payout = 0
|
34 |
if series_b_shares > 0 and series_b_capital > 0:
|
35 |
series_b_preference = series_b_capital * series_b_multiple
|
36 |
series_b_preference_payout = min(remaining_proceeds, series_b_preference)
|
37 |
remaining_proceeds -= series_b_preference_payout
|
|
|
38 |
if series_b_participating:
|
39 |
+
participating_shareholders.append({'shares': series_b_shares})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
|
41 |
+
# Series A
|
42 |
series_a_preference_payout = 0
|
43 |
if series_a_shares > 0 and series_a_capital > 0:
|
44 |
series_a_preference = series_a_capital * series_a_multiple
|
45 |
series_a_preference_payout = min(remaining_proceeds, series_a_preference)
|
46 |
remaining_proceeds -= series_a_preference_payout
|
|
|
47 |
if series_a_participating:
|
48 |
+
participating_shareholders.append({'shares': series_a_shares})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
+
# Seed
|
51 |
seed_preference_payout = 0
|
52 |
if seed_shares > 0 and seed_capital > 0:
|
53 |
seed_preference = seed_capital * seed_multiple
|
54 |
seed_preference_payout = min(remaining_proceeds, seed_preference)
|
55 |
remaining_proceeds -= seed_preference_payout
|
|
|
56 |
if seed_participating:
|
57 |
+
participating_shareholders.append({'shares': seed_shares})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
|
59 |
+
# Phase 2: Handle non-participating conversions
|
|
|
60 |
participating_preferred_shares = sum([p['shares'] for p in participating_shareholders])
|
61 |
total_participating_shares = common_shares + participating_preferred_shares
|
62 |
|
63 |
+
# Check conversions for non-participating preferred
|
|
|
|
|
|
|
64 |
if series_b_shares > 0 and series_b_capital > 0 and not series_b_participating:
|
|
|
65 |
conversion_value = (series_b_shares / total_shares) * exit_valuation
|
66 |
if conversion_value > series_b_preference_payout:
|
|
|
67 |
remaining_proceeds += series_b_preference_payout
|
68 |
total_participating_shares += series_b_shares
|
69 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
if series_a_shares > 0 and series_a_capital > 0 and not series_a_participating:
|
71 |
conversion_value = (series_a_shares / total_shares) * exit_valuation
|
72 |
if conversion_value > series_a_preference_payout:
|
73 |
remaining_proceeds += series_a_preference_payout
|
74 |
total_participating_shares += series_a_shares
|
|
|
|
|
|
|
|
|
|
|
75 |
|
|
|
76 |
if seed_shares > 0 and seed_capital > 0 and not seed_participating:
|
77 |
conversion_value = (seed_shares / total_shares) * exit_valuation
|
78 |
if conversion_value > seed_preference_payout:
|
79 |
remaining_proceeds += seed_preference_payout
|
80 |
total_participating_shares += seed_shares
|
|
|
|
|
|
|
|
|
|
|
81 |
|
82 |
+
# Final distribution
|
83 |
if total_participating_shares > 0:
|
84 |
price_per_participating_share = remaining_proceeds / total_participating_shares
|
85 |
common_proceeds = price_per_participating_share * common_shares
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
else:
|
|
|
87 |
common_proceeds = remaining_proceeds
|
88 |
|
89 |
+
price_per_common_share = common_proceeds / common_shares if common_shares > 0 else 0
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
option_value_per_share = max(0, price_per_common_share - strike_price)
|
91 |
total_option_value = option_value_per_share * your_options
|
92 |
|
93 |
+
return {
|
94 |
+
'exit_valuation': exit_valuation,
|
95 |
+
'option_value': total_option_value,
|
96 |
+
'price_per_share': price_per_common_share,
|
97 |
+
'common_proceeds': common_proceeds,
|
98 |
+
'error': None
|
99 |
+
}
|
100 |
+
|
101 |
+
def calculate_equity_value(
|
102 |
+
# Cap table inputs
|
103 |
+
total_shares, your_options, strike_price,
|
104 |
+
# Seed round
|
105 |
+
seed_shares, seed_capital, seed_multiple, seed_participating,
|
106 |
+
# Series A
|
107 |
+
series_a_shares, series_a_capital, series_a_multiple, series_a_participating,
|
108 |
+
# Series B
|
109 |
+
series_b_shares, series_b_capital, series_b_multiple, series_b_participating,
|
110 |
+
# Multiple exit scenarios
|
111 |
+
exit_scenario_1, scenario_1_name,
|
112 |
+
exit_scenario_2, scenario_2_name,
|
113 |
+
exit_scenario_3, scenario_3_name,
|
114 |
+
exit_scenario_4, scenario_4_name,
|
115 |
+
exit_scenario_5, scenario_5_name
|
116 |
+
):
|
117 |
+
"""Calculate startup equity value with liquidation preferences for multiple exit scenarios"""
|
118 |
+
|
119 |
+
# Handle None values and provide defaults
|
120 |
+
total_shares = total_shares or 10000000
|
121 |
+
your_options = your_options or 0
|
122 |
+
strike_price = strike_price or 0
|
123 |
+
seed_shares = seed_shares or 0
|
124 |
+
seed_capital = seed_capital or 0
|
125 |
+
seed_multiple = seed_multiple or 1.0
|
126 |
+
seed_participating = seed_participating or False
|
127 |
+
series_a_shares = series_a_shares or 0
|
128 |
+
series_a_capital = series_a_capital or 0
|
129 |
+
series_a_multiple = series_a_multiple or 1.0
|
130 |
+
series_a_participating = series_a_participating or False
|
131 |
+
series_b_shares = series_b_shares or 0
|
132 |
+
series_b_capital = series_b_capital or 0
|
133 |
+
series_b_multiple = series_b_multiple or 1.0
|
134 |
+
series_b_participating = series_b_participating or False
|
135 |
+
|
136 |
+
# Handle exit scenarios
|
137 |
+
exit_scenario_1 = exit_scenario_1 or 0
|
138 |
+
exit_scenario_2 = exit_scenario_2 or 0
|
139 |
+
exit_scenario_3 = exit_scenario_3 or 0
|
140 |
+
exit_scenario_4 = exit_scenario_4 or 0
|
141 |
+
exit_scenario_5 = exit_scenario_5 or 0
|
142 |
+
scenario_1_name = scenario_1_name or "Scenario 1"
|
143 |
+
scenario_2_name = scenario_2_name or "Scenario 2"
|
144 |
+
scenario_3_name = scenario_3_name or "Scenario 3"
|
145 |
+
scenario_4_name = scenario_4_name or "Scenario 4"
|
146 |
+
scenario_5_name = scenario_5_name or "Scenario 5"
|
147 |
+
|
148 |
+
# Input validation
|
149 |
+
if total_shares <= 0:
|
150 |
+
return "Invalid inputs - please check your values", None, None, None
|
151 |
+
|
152 |
+
# Calculate scenarios
|
153 |
+
scenarios = []
|
154 |
+
exit_values = [exit_scenario_1, exit_scenario_2, exit_scenario_3, exit_scenario_4, exit_scenario_5]
|
155 |
+
scenario_names = [scenario_1_name, scenario_2_name, scenario_3_name, scenario_4_name, scenario_5_name]
|
156 |
+
|
157 |
+
for exit_val, name in zip(exit_values, scenario_names):
|
158 |
+
if exit_val > 0: # Only calculate scenarios with positive exit values
|
159 |
+
scenario_result = calculate_single_scenario(
|
160 |
+
exit_val, total_shares, your_options, strike_price,
|
161 |
+
seed_shares, seed_capital, seed_multiple, seed_participating,
|
162 |
+
series_a_shares, series_a_capital, series_a_multiple, series_a_participating,
|
163 |
+
series_b_shares, series_b_capital, series_b_multiple, series_b_participating
|
164 |
+
)
|
165 |
+
scenario_result['name'] = name
|
166 |
+
scenarios.append(scenario_result)
|
167 |
+
|
168 |
+
if not scenarios:
|
169 |
+
return "Please enter at least one exit scenario with a positive value", None, None, None
|
170 |
+
|
171 |
+
# Calculate common shares and basic info
|
172 |
+
total_preferred_shares = seed_shares + series_a_shares + series_b_shares
|
173 |
+
common_shares = total_shares - total_preferred_shares
|
174 |
your_equity_percentage = (your_options / total_shares) * 100 if total_shares > 0 else 0
|
175 |
|
176 |
# Build results summary
|
|
|
179 |
if series_a_shares > 0: participating_status.append(f"Series A: {'Participating' if series_a_participating else 'Non-Participating'}")
|
180 |
if series_b_shares > 0: participating_status.append(f"Series B: {'Participating' if series_b_participating else 'Non-Participating'}")
|
181 |
|
182 |
+
# Create scenario comparison table
|
183 |
+
scenario_table = "## π Exit Scenario Comparison\n\n"
|
184 |
+
scenario_table += "| Scenario | Exit Value | Your Option Value | Value per Option | Common Proceeds |\n"
|
185 |
+
scenario_table += "|----------|------------|-------------------|------------------|------------------|\n"
|
186 |
+
|
187 |
+
for scenario in scenarios:
|
188 |
+
scenario_table += f"| **{scenario['name']}** | ${scenario['exit_valuation']:,.0f} | "
|
189 |
+
scenario_table += f"${scenario['option_value']:,.2f} | ${scenario['option_value']/your_options if your_options > 0 else 0:.4f} | "
|
190 |
+
scenario_table += f"${scenario['common_proceeds']:,.0f} |\n"
|
191 |
+
|
192 |
results = f"""
|
193 |
+
## π° Your Equity Summary
|
194 |
|
195 |
+
**Your Option Grant:** {your_options:,} options
|
196 |
+
**Strike Price:** ${strike_price:.4f} per share
|
197 |
**Your Equity Stake:** {your_equity_percentage:.3f}%
|
198 |
|
199 |
+
{scenario_table}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
|
201 |
## ποΈ Cap Table Summary
|
202 |
|
203 |
**Total Shares:** {total_shares:,}
|
204 |
**Common Shares:** {common_shares:,}
|
205 |
**Preferred Shares:** {total_preferred_shares:,}
|
206 |
+
|
207 |
+
**Liquidation Terms:** {' | '.join(participating_status) if participating_status else 'No preferred rounds'}
|
208 |
+
|
209 |
+
**Break-even Price per Share:** ${strike_price:.4f}
|
210 |
+
*(Price needed for your options to have positive value)*
|
211 |
"""
|
212 |
+
|
213 |
+
# Create comparison bar chart
|
214 |
+
if scenarios:
|
215 |
+
scenario_names = [s['name'] for s in scenarios]
|
216 |
+
option_values = [s['option_value'] for s in scenarios]
|
217 |
+
exit_values = [s['exit_valuation'] for s in scenarios]
|
218 |
|
219 |
+
fig = make_subplots(
|
220 |
+
rows=2, cols=1,
|
221 |
+
subplot_titles=("Your Option Value by Scenario", "Exit Valuation by Scenario"),
|
222 |
+
vertical_spacing=0.20,
|
223 |
+
specs=[[{"secondary_y": False}], [{"secondary_y": False}]]
|
224 |
+
)
|
225 |
|
226 |
+
# Option values bar chart
|
227 |
+
fig.add_trace(
|
228 |
+
go.Bar(
|
229 |
+
x=scenario_names,
|
230 |
+
y=option_values,
|
231 |
+
name="Option Value",
|
232 |
+
marker_color='#2E86AB',
|
233 |
+
text=[f"${val:,.0f}" for val in option_values],
|
234 |
+
textposition='outside'
|
235 |
+
),
|
236 |
+
row=1, col=1
|
237 |
+
)
|
238 |
|
239 |
+
# Exit valuations bar chart
|
240 |
+
fig.add_trace(
|
241 |
+
go.Bar(
|
242 |
+
x=scenario_names,
|
243 |
+
y=exit_values,
|
244 |
+
name="Exit Valuation",
|
245 |
+
marker_color='#F18F01',
|
246 |
+
text=[f"${val:,.0f}" for val in exit_values],
|
247 |
+
textposition='outside',
|
248 |
+
showlegend=False
|
249 |
+
),
|
250 |
+
row=2, col=1
|
251 |
+
)
|
252 |
|
253 |
fig.update_layout(
|
254 |
+
title="Multi-Scenario Equity Analysis",
|
255 |
+
height=650,
|
|
|
256 |
showlegend=True,
|
257 |
+
margin=dict(t=80, b=50, l=80, r=50)
|
258 |
+
)
|
259 |
+
|
260 |
+
# Add extra space for text labels above bars
|
261 |
+
fig.update_yaxes(title_text="Your Option Value ($)", row=1, col=1, range=[0, max(option_values) * 1.15])
|
262 |
+
fig.update_yaxes(title_text="Company Valuation ($)", row=2, col=1, range=[0, max(exit_values) * 1.15])
|
263 |
+
|
264 |
+
comparison_chart = fig
|
265 |
+
else:
|
266 |
+
comparison_chart = None
|
267 |
+
|
268 |
+
# Create detailed breakdown chart for the highest scenario
|
269 |
+
if scenarios:
|
270 |
+
# Find the scenario with highest option value for detailed analysis
|
271 |
+
best_scenario = max(scenarios, key=lambda x: x['option_value'])
|
272 |
+
|
273 |
+
# Create a detailed waterfall for this scenario
|
274 |
+
detailed_fig = calculate_single_scenario_waterfall(
|
275 |
+
best_scenario['exit_valuation'], total_shares, your_options, strike_price,
|
276 |
+
seed_shares, seed_capital, seed_multiple, seed_participating,
|
277 |
+
series_a_shares, series_a_capital, series_a_multiple, series_a_participating,
|
278 |
+
series_b_shares, series_b_capital, series_b_multiple, series_b_participating
|
279 |
)
|
280 |
|
281 |
+
detailed_chart = detailed_fig
|
282 |
else:
|
283 |
+
detailed_chart = None
|
284 |
+
|
285 |
+
# Create ROI comparison
|
286 |
+
if scenarios and your_options > 0:
|
287 |
+
roi_data = []
|
288 |
+
investment_cost = your_options * strike_price
|
289 |
+
|
290 |
+
for scenario in scenarios:
|
291 |
+
if investment_cost > 0:
|
292 |
+
roi = ((scenario['option_value'] - investment_cost) / investment_cost) * 100
|
293 |
+
else:
|
294 |
+
roi = float('inf') if scenario['option_value'] > 0 else 0
|
295 |
+
|
296 |
+
roi_data.append({
|
297 |
+
'scenario': scenario['name'],
|
298 |
+
'roi': roi if roi != float('inf') else 999999, # Cap at very high number for display
|
299 |
+
'absolute_gain': scenario['option_value'] - investment_cost
|
300 |
+
})
|
301 |
|
302 |
+
roi_fig = go.Figure()
|
303 |
+
roi_fig.add_trace(go.Bar(
|
304 |
+
x=[d['scenario'] for d in roi_data],
|
305 |
+
y=[d['roi'] for d in roi_data],
|
306 |
+
name="ROI %",
|
307 |
+
marker_color='#28A745',
|
308 |
+
text=[f"{d['roi']:.0f}%" if d['roi'] < 999999 else "β%" for d in roi_data],
|
309 |
+
textposition='outside'
|
310 |
+
))
|
311 |
|
312 |
+
roi_fig.update_layout(
|
313 |
+
title="Return on Investment (ROI) by Scenario",
|
314 |
+
xaxis_title="Scenario",
|
315 |
+
yaxis_title="ROI (%)",
|
316 |
+
height=450,
|
317 |
+
margin=dict(t=60, b=50, l=60, r=50)
|
318 |
+
)
|
319 |
+
|
320 |
+
roi_chart = roi_fig
|
321 |
+
else:
|
322 |
+
roi_chart = None
|
323 |
+
|
324 |
+
return results, comparison_chart, detailed_chart, roi_chart
|
325 |
+
|
326 |
+
def calculate_single_scenario_waterfall(
|
327 |
+
exit_valuation, total_shares, your_options, strike_price,
|
328 |
+
seed_shares, seed_capital, seed_multiple, seed_participating,
|
329 |
+
series_a_shares, series_a_capital, series_a_multiple, series_a_participating,
|
330 |
+
series_b_shares, series_b_capital, series_b_multiple, series_b_participating
|
331 |
+
):
|
332 |
+
"""Create detailed waterfall chart for a single scenario"""
|
333 |
+
|
334 |
+
common_shares = total_shares - (seed_shares + series_a_shares + series_b_shares)
|
335 |
+
remaining_proceeds = exit_valuation
|
336 |
+
waterfall_data = []
|
337 |
+
participating_shareholders = []
|
338 |
+
|
339 |
+
# Phase 1: Liquidation preferences
|
340 |
+
if series_b_shares > 0 and series_b_capital > 0:
|
341 |
+
series_b_preference = series_b_capital * series_b_multiple
|
342 |
+
series_b_payout = min(remaining_proceeds, series_b_preference)
|
343 |
+
remaining_proceeds -= series_b_payout
|
344 |
|
345 |
+
if series_b_participating:
|
346 |
+
participating_shareholders.append({'round': 'Series B', 'shares': series_b_shares})
|
|
|
|
|
|
|
347 |
|
348 |
+
waterfall_data.append({
|
349 |
+
'Round': 'Series B (Pref)',
|
350 |
+
'Payout': series_b_payout,
|
351 |
+
'Type': 'Preference'
|
352 |
+
})
|
353 |
+
|
354 |
+
if series_a_shares > 0 and series_a_capital > 0:
|
355 |
+
series_a_preference = series_a_capital * series_a_multiple
|
356 |
+
series_a_payout = min(remaining_proceeds, series_a_preference)
|
357 |
+
remaining_proceeds -= series_a_payout
|
358 |
|
359 |
+
if series_a_participating:
|
360 |
+
participating_shareholders.append({'round': 'Series A', 'shares': series_a_shares})
|
|
|
|
|
|
|
|
|
|
|
361 |
|
362 |
+
waterfall_data.append({
|
363 |
+
'Round': 'Series A (Pref)',
|
364 |
+
'Payout': series_a_payout,
|
365 |
+
'Type': 'Preference'
|
366 |
+
})
|
367 |
+
|
368 |
+
if seed_shares > 0 and seed_capital > 0:
|
369 |
+
seed_preference = seed_capital * seed_multiple
|
370 |
+
seed_payout = min(remaining_proceeds, seed_preference)
|
371 |
+
remaining_proceeds -= seed_payout
|
372 |
|
373 |
+
if seed_participating:
|
374 |
+
participating_shareholders.append({'round': 'Seed', 'shares': seed_shares})
|
|
|
|
|
|
|
|
|
375 |
|
376 |
+
waterfall_data.append({
|
377 |
+
'Round': 'Seed (Pref)',
|
378 |
+
'Payout': seed_payout,
|
379 |
+
'Type': 'Preference'
|
380 |
+
})
|
381 |
+
|
382 |
+
# Phase 2: Check conversions and final distribution
|
383 |
+
participating_preferred_shares = sum([p['shares'] for p in participating_shareholders])
|
384 |
+
total_participating_shares = common_shares + participating_preferred_shares
|
385 |
+
|
386 |
+
# Simplified conversion logic for visualization
|
387 |
+
if total_participating_shares > 0:
|
388 |
+
price_per_share = remaining_proceeds / total_participating_shares
|
389 |
+
common_proceeds = price_per_share * common_shares
|
390 |
|
391 |
+
# Add participating preferred distributions
|
392 |
+
for participant in participating_shareholders:
|
393 |
+
participating_payout = price_per_share * participant['shares']
|
394 |
+
waterfall_data.append({
|
395 |
+
'Round': f"{participant['round']} (Part.)",
|
396 |
+
'Payout': participating_payout,
|
397 |
+
'Type': 'Participation'
|
398 |
+
})
|
399 |
+
else:
|
400 |
+
common_proceeds = remaining_proceeds
|
401 |
+
|
402 |
+
# Add common stock
|
403 |
+
waterfall_data.append({
|
404 |
+
'Round': 'Common Stock',
|
405 |
+
'Payout': common_proceeds,
|
406 |
+
'Type': 'Common'
|
407 |
+
})
|
408 |
+
|
409 |
+
# Create the chart
|
410 |
+
fig = go.Figure()
|
411 |
+
|
412 |
+
color_map = {
|
413 |
+
'Preference': '#FF6B6B',
|
414 |
+
'Participation': '#4ECDC4',
|
415 |
+
'Common': '#F7DC6F'
|
416 |
+
}
|
417 |
+
|
418 |
+
for item in waterfall_data:
|
419 |
+
if item['Payout'] > 0:
|
420 |
+
color = color_map.get(item['Type'], '#96CEB4')
|
421 |
+
fig.add_trace(go.Bar(
|
422 |
+
x=[item['Round']],
|
423 |
+
y=[item['Payout']],
|
424 |
+
name=f"{item['Round']} (${item['Payout']:,.0f})",
|
425 |
+
marker_color=color,
|
426 |
+
text=f"${item['Payout']:,.0f}",
|
427 |
+
textposition='outside'
|
428 |
+
))
|
429 |
+
|
430 |
+
fig.update_layout(
|
431 |
+
title=f"Liquidation Waterfall - ${exit_valuation:,.0f} Exit",
|
432 |
+
xaxis_title="Stakeholder",
|
433 |
+
yaxis_title="Payout ($)",
|
434 |
+
height=450,
|
435 |
+
showlegend=True,
|
436 |
+
margin=dict(t=60, b=50, l=80, r=50)
|
437 |
)
|
438 |
|
439 |
+
return fig
|
440 |
|
441 |
# Create Gradio interface
|
442 |
with gr.Blocks(title="Startup Equity Calculator", theme=gr.themes.Soft()) as app:
|
|
|
447 |
with gr.Column():
|
448 |
gr.Markdown("## Cap Table Structure")
|
449 |
total_shares = gr.Number(label="Total Fully Diluted Shares", value=10000000, precision=0)
|
450 |
+
your_options = gr.Number(label="Your Option Grant", value=0, precision=0)
|
451 |
strike_price = gr.Number(label="Strike Price per Share ($)", value=0.10, precision=4)
|
452 |
|
453 |
gr.Markdown("## Funding Rounds")
|
454 |
|
455 |
+
with gr.Accordion("Seed Round", open=False):
|
456 |
+
seed_shares = gr.Number(label="Seed Shares Issued", value=0, precision=0)
|
457 |
+
seed_capital = gr.Number(label="Seed Capital Raised ($)", value=0, precision=0)
|
458 |
seed_multiple = gr.Number(label="Liquidation Multiple", value=1.0, precision=1)
|
459 |
seed_participating = gr.Checkbox(label="Participating Preferred", value=False)
|
460 |
|
461 |
+
with gr.Accordion("Series A", open=False):
|
462 |
+
series_a_shares = gr.Number(label="Series A Shares Issued", value=0, precision=0)
|
463 |
+
series_a_capital = gr.Number(label="Series A Capital Raised ($)", value=0, precision=0)
|
464 |
series_a_multiple = gr.Number(label="Liquidation Multiple", value=1.0, precision=1)
|
465 |
series_a_participating = gr.Checkbox(label="Participating Preferred", value=False)
|
466 |
|
|
|
471 |
series_b_participating = gr.Checkbox(label="Participating Preferred", value=False)
|
472 |
|
473 |
with gr.Column():
|
474 |
+
gr.Markdown("## Exit Scenarios")
|
475 |
+
gr.Markdown("*Define multiple exit scenarios to compare side-by-side*")
|
476 |
|
477 |
+
with gr.Row():
|
478 |
+
with gr.Column():
|
479 |
+
scenario_1_name = gr.Textbox(label="Scenario 1 Name", value="Conservative", placeholder="e.g., Conservative")
|
480 |
+
exit_scenario_1 = gr.Number(label="Exit Valuation ($)", value=25000000, precision=0)
|
481 |
+
|
482 |
+
with gr.Column():
|
483 |
+
scenario_2_name = gr.Textbox(label="Scenario 2 Name", value="Base Case", placeholder="e.g., Base Case")
|
484 |
+
exit_scenario_2 = gr.Number(label="Exit Valuation ($)", value=50000000, precision=0)
|
485 |
+
|
486 |
+
with gr.Row():
|
487 |
+
with gr.Column():
|
488 |
+
scenario_3_name = gr.Textbox(label="Scenario 3 Name", value="Optimistic", placeholder="e.g., Optimistic")
|
489 |
+
exit_scenario_3 = gr.Number(label="Exit Valuation ($)", value=100000000, precision=0)
|
490 |
+
|
491 |
+
with gr.Column():
|
492 |
+
scenario_4_name = gr.Textbox(label="Scenario 4 Name", value="", placeholder="e.g., Moon Shot")
|
493 |
+
exit_scenario_4 = gr.Number(label="Exit Valuation ($)", value=0, precision=0)
|
494 |
+
|
495 |
+
with gr.Row():
|
496 |
+
with gr.Column():
|
497 |
+
scenario_5_name = gr.Textbox(label="Scenario 5 Name", value="", placeholder="e.g., IPO")
|
498 |
+
exit_scenario_5 = gr.Number(label="Exit Valuation ($)", value=0, precision=0)
|
499 |
+
|
500 |
+
calculate_btn = gr.Button("π Calculate All Scenarios", variant="primary", size="lg")
|
501 |
|
502 |
results_text = gr.Markdown()
|
503 |
|
504 |
with gr.Row():
|
505 |
+
comparison_plot = gr.Plot(label="Multi-Scenario Comparison")
|
506 |
+
|
507 |
+
with gr.Row():
|
508 |
+
waterfall_plot = gr.Plot(label="Detailed Waterfall (Best Scenario)")
|
509 |
+
roi_plot = gr.Plot(label="Return on Investment")
|
510 |
|
511 |
# Set up the calculation trigger
|
512 |
inputs = [
|
|
|
514 |
seed_shares, seed_capital, seed_multiple, seed_participating,
|
515 |
series_a_shares, series_a_capital, series_a_multiple, series_a_participating,
|
516 |
series_b_shares, series_b_capital, series_b_multiple, series_b_participating,
|
517 |
+
exit_scenario_1, scenario_1_name,
|
518 |
+
exit_scenario_2, scenario_2_name,
|
519 |
+
exit_scenario_3, scenario_3_name,
|
520 |
+
exit_scenario_4, scenario_4_name,
|
521 |
+
exit_scenario_5, scenario_5_name
|
522 |
]
|
523 |
|
524 |
+
outputs = [results_text, comparison_plot, waterfall_plot, roi_plot]
|
525 |
|
526 |
calculate_btn.click(calculate_equity_value, inputs=inputs, outputs=outputs)
|
527 |
|
|
|
530 |
input_component.change(calculate_equity_value, inputs=inputs, outputs=outputs)
|
531 |
|
532 |
gr.Markdown("""
|
533 |
+
## π How to Use This Calculator
|
534 |
+
|
535 |
+
### π― Multi-Scenario Analysis
|
536 |
+
**This is where the real value lies!** Instead of guessing one exit value, define multiple realistic scenarios:
|
537 |
+
- **Conservative**: What if growth is slower than expected?
|
538 |
+
- **Base Case**: Most likely scenario based on current trajectory
|
539 |
+
- **Optimistic**: If everything goes right
|
540 |
+
- **Moon Shot**: Best case scenario (10x+ returns)
|
541 |
+
|
542 |
+
### π Key Outputs
|
543 |
+
1. **Comparison Table**: Side-by-side option values across all scenarios
|
544 |
+
2. **Visual Charts**: See how your returns scale with different exits
|
545 |
+
3. **ROI Analysis**: Understand your return on investment potential
|
546 |
+
4. **Detailed Waterfall**: How liquidation preferences affect distributions
|
547 |
+
|
548 |
+
### π‘ Decision Framework
|
549 |
+
Use this to evaluate:
|
550 |
+
- **Risk vs Reward**: How much upside vs downside?
|
551 |
+
- **Opportunity Cost**: Compare to other job offers or investments
|
552 |
+
- **Negotiation Power**: Understanding your equity's potential value range
|
553 |
+
|
554 |
+
### π§ Liquidation Preferences
|
555 |
+
- **Non-Participating**: Investors choose preference OR convert to common (better for employees)
|
556 |
+
- **Participating**: Investors get preference AND share upside (worse for employees)
|
557 |
+
- **Multiples**: How many times their investment investors get back first
|
558 |
+
|
559 |
+
**Pro Tip**: Try toggling participating preferred on/off to see the dramatic impact on your equity value!
|
560 |
""")
|
561 |
|
562 |
if __name__ == "__main__":
|