Skip to content

Instantly share code, notes, and snippets.

@zapstar
Last active October 10, 2020 16:34
Show Gist options
  • Save zapstar/a888cd0fc3ca087672e05e8d2e59c1d5 to your computer and use it in GitHub Desktop.
Save zapstar/a888cd0fc3ca087672e05e8d2e59c1d5 to your computer and use it in GitHub Desktop.
Stock Options Calculator (For a startup's employee)
#!/usr/bin/env python3
"""
Stock Options Calculator
Helps you get a fair idea of the costs involved and profits that can be gained in the future.
Example Usage:
# --option-grant 10000,0.25 10000,0.5 --exercise-fmv 1.25 --income-tax-rate 0.3 --exercise-exch-rate 73 --sale-fmv 2.5 --capital-gain-rate 0.2 --sale-exch-rate 75 --indexation-ratio 1.075
"""
import argparse
from typing import List, Tuple
def compute(stock_options: List[Tuple[int, float]],
exercise_fmv: float,
tax_slab_rate: float,
exercise_exch_rate: float,
sale_fmv: float,
cap_gain_rate: float,
cii_ratio: float,
sale_exch_rate: float) -> None:
print('Options Grant:')
for num_vested_shares, strike_price in stock_options:
print(f'* Vested: {num_vested_shares}, Strike Price (in $): {strike_price}')
print('Fair Market Value at exercise (in $):', exercise_fmv)
print(f'Income Tax Rate at exercise: {tax_slab_rate * 100}%')
print('Exchange rate of $ at exercise:', exercise_exch_rate)
# Assume metrics to be zero
cur_market_value = 0.0
cost_to_purchase = 0.0
total_perquisite = 0.0
# Compute basic metrics
for num_vested_shares, strike_price in stock_options:
cost_to_purchase += num_vested_shares * strike_price
cur_market_value += num_vested_shares * exercise_fmv
total_perquisite += (exercise_fmv - strike_price) * num_vested_shares
# Compute tax liability for during exercise
if total_perquisite > 0:
tax_pay_exercise = total_perquisite * tax_slab_rate
else:
tax_pay_exercise = 0
total_cost_exercise = cost_to_purchase + tax_pay_exercise
# Print stuff related to exercise
print('Cost to employee to exercise options:', cost_to_purchase * exercise_exch_rate)
print('Current Market Value of shares:', cur_market_value * exercise_exch_rate)
print('Total Discount:', (cur_market_value - cost_to_purchase) * exercise_exch_rate)
print('Income Tax at exercise:', tax_pay_exercise * exercise_exch_rate)
print('Total cost to employee at exercise:', total_cost_exercise * exercise_exch_rate)
print('Unrealized Profit at exercise:', (cur_market_value - total_cost_exercise) * exercise_exch_rate)
# Compute future values if asked for
if sale_fmv is not None:
print('Fair Market value at sale (in $):', sale_fmv)
print(f'Capital Gains Tax Rate at sale: {cap_gain_rate * 100}%')
print('Indexation Ratio:', cii_ratio)
print('Exchange rate of $ at sale:', exercise_exch_rate)
fut_market_value = 0.0
for num_vested_shares, _ in stock_options:
fut_market_value += num_vested_shares * sale_fmv
# Compute capital gains for the future
capital_gain = fut_market_value - cur_market_value * cii_ratio
if capital_gain > 0:
tax_pay_sale = capital_gain * cap_gain_rate
else:
tax_pay_sale = 0
# Print stuff related to future values
print('Market Value of shares at sale:', fut_market_value * sale_exch_rate)
print('Tax to be paid on sale:', tax_pay_sale * sale_exch_rate)
future_total_profit = (fut_market_value - tax_pay_sale) * sale_exch_rate - total_cost_exercise * exercise_exch_rate
print('Future Profit on sale:', future_total_profit)
def option_grant_type(s):
try:
num_options, strike_price = [float(x) for x in s.split(',')]
except ValueError:
raise argparse.ArgumentTypeError('Options should be NUM_OPTIONS,STRIKE_PRICE')
return num_options, strike_price
def main():
# Parse the arguments
parser = argparse.ArgumentParser()
# Exercised Options. List of (Shares, Strike Price)
parser.add_argument('--option-grant',
type=option_grant_type,
help='Options Grant Tuple[Number of options (> 0), Strike Price (> 0)]',
nargs='+')
# Fair market value at exercise
parser.add_argument('--exercise-fmv', required=True, type=float, help='Fair Market Value at exercise (> 0)')
# Tax rate at exercise
parser.add_argument('--income-tax-rate', required=True, type=float, help='Income Tax rate slab [0, 1)')
# Exchange rate from dollars to rupees
parser.add_argument('--exercise-exch-rate', type=float, help='Dollar Exchange rate on exercise', default=1)
# Fair Market Value at sale
parser.add_argument('--sale-fmv', type=float, help='Fair Market value at sale')
# Tax rate for capital gains during sale
parser.add_argument('--capital-gain-rate', type=float, help='Capital Gains Taxation rate [0, 1)')
# Ratio of cost inflation indices (sale date / excercise date)
parser.add_argument('--indexation-ratio', type=float, default=1,
help='Ratio of cost inflation indices (Sale Date / Exercise Date)')
# Exchange rate from dollars to rupees
parser.add_argument('--sale-exch-rate', type=float, help='Dollar Exchange rate on sale date', default=1)
# Parse and compute.
ops = parser.parse_args()
# If sale FMV is given, capital gains tax is a must
if bool(ops.sale_fmv) ^ bool(ops.capital_gain_rate):
print('Sale FMV and Capital Gains Tax Rate are both required or optional')
exit(1)
compute(ops.option_grant, ops.exercise_fmv, ops.income_tax_rate, ops.exercise_exch_rate,
ops.sale_fmv, ops.capital_gain_rate, ops.indexation_ratio, ops.sale_exch_rate)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment