Stock Option Tax Calculator

Stock Option Tax Calculator – Estimate Your Tax Liability body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f8f9fa; color: #333; line-height: 1.6; margin: 0; padding: 0; } .container { max-width: 1000px; margin: 20px auto; padding: 20px; background-color: #fff; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; align-items: center; } header { background-color: #004a99; color: white; padding: 15px 0; width: 100%; text-align: center; border-radius: 8px 8px 0 0; } header h1 { margin: 0; font-size: 2.2em; } main { width: 100%; padding: 20px; } h2 { color: #004a99; border-bottom: 2px solid #004a99; padding-bottom: 5px; margin-top: 30px; margin-bottom: 20px; font-size: 1.8em; } h3 { color: #0056b3; margin-top: 25px; margin-bottom: 15px; font-size: 1.4em; } .calculator-section { margin-bottom: 40px; padding: 25px; background-color: #eef5ff; border-radius: 8px; border: 1px solid #d0e0f0; } .calculator-section h2 { margin-top: 0; border-bottom: none; color: #004a99; font-size: 1.6em; } .loan-calc-container { display: flex; flex-direction: column; gap: 15px; } .input-group { display: flex; flex-direction: column; gap: 8px; } .input-group label { font-weight: bold; color: #004a99; } .input-group input[type="number"], .input-group input[type="text"], .input-group select { padding: 10px; border: 1px solid #ccc; border-radius: 5px; font-size: 1em; box-sizing: border-box; width: 100%; } .input-group input[type="number"]:focus, .input-group input[type="text"]:focus, .input-group select:focus { border-color: #007bff; outline: none; box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25); } .input-group .helper-text { font-size: 0.85em; color: #6c757d; margin-top: 5px; } .error-message { color: #dc3545; font-size: 0.85em; margin-top: 5px; min-height: 1.2em; /* Prevent layout shifts */ } button { background-color: #004a99; color: white; border: none; padding: 12px 20px; border-radius: 5px; cursor: pointer; font-size: 1.1em; transition: background-color 0.3s ease; margin-top: 15px; } button:hover { background-color: #003d80; } button.reset { background-color: #6c757d; margin-left: 10px; } button.reset:hover { background-color: #5a6268; } #results { margin-top: 30px; padding: 25px; background-color: #d4edda; border: 1px solid #c3e6cb; border-radius: 8px; display: flex; flex-direction: column; align-items: center; text-align: center; } #results h2 { margin-top: 0; color: #155724; font-size: 1.6em; border-bottom: none; } .main-result { font-size: 2.5em; font-weight: bold; color: #155724; margin: 15px 0; background-color: #ffffff; padding: 15px 25px; border-radius: 8px; box-shadow: inset 0 1px 3px rgba(0,0,0,0.1); } .intermediate-results { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px; margin-top: 20px; margin-bottom: 20px; } .intermediate-results div { background-color: #ffffff; padding: 15px; border-radius: 6px; box-shadow: 0 1px 5px rgba(0,0,0,0.08); text-align: center; flex: 1; min-width: 150px; } .intermediate-results div span { display: block; font-size: 1.2em; font-weight: bold; color: #004a99; } .formula-explanation { font-size: 0.9em; color: #6c757d; margin-top: 15px; text-align: left; } #copyResultsBtn { background-color: #007bff; margin-top: 20px; } #copyResultsBtn:hover { background-color: #0056b3; } table { width: 100%; border-collapse: collapse; margin-top: 30px; overflow-x: auto; /* Mobile responsiveness */ display: block; /* Needed for overflow-x */ white-space: nowrap; /* Prevent wrapping in table cells */ } th, td { border: 1px solid #ddd; padding: 10px 15px; text-align: right; } th { background-color: #004a99; color: white; font-weight: bold; } td { background-color: #f2f2f2; } tr:nth-child(even) td { background-color: #e9e9e9; } caption { caption-side: top; text-align: left; font-weight: bold; color: #004a99; margin-bottom: 10px; font-size: 1.1em; } canvas { display: block; /* Remove extra space below canvas */ margin-top: 30px; width: 100%; /* Make canvas responsive */ max-width: 100%; /* Ensure it doesn't exceed container */ height: auto; /* Maintain aspect ratio */ border: 1px solid #ddd; background-color: #fff; border-radius: 5px; } .chart-container { width: 100%; max-width: 100%; overflow-x: auto; } .article-content { margin-top: 40px; padding: 25px; background-color: #fdfdfd; border-radius: 8px; border: 1px solid #eee; } .article-content p { margin-bottom: 15px; } .article-content h2, .article-content h3 { color: #004a99; margin-top: 30px; margin-bottom: 15px; font-size: 1.7em; } .article-content h3 { font-size: 1.4em; } .article-content ul { margin-left: 20px; margin-bottom: 15px; } .article-content li { margin-bottom: 8px; } .variable-table { width: 100%; border-collapse: collapse; margin-top: 20px; margin-bottom: 20px; box-shadow: 0 1px 5px rgba(0,0,0,0.08); } .variable-table th, .variable-table td { border: 1px solid #ddd; padding: 10px; text-align: left; } .variable-table th { background-color: #004a99; color: white; } .variable-table td { background-color: #f9f9f9; } .variable-table tr:nth-child(even) td { background-color: #f2f2f2; } .faq-section { margin-top: 30px; } .faq-section h3 { color: #004a99; margin-bottom: 10px; font-size: 1.3em; } .faq-section p { margin-bottom: 20px; padding-left: 15px; border-left: 3px solid #004a99; } .related-tools { margin-top: 40px; padding: 25px; background-color: #e9ecef; border-radius: 8px; border: 1px solid #dee2e6; } .related-tools h2 { margin-top: 0; border-bottom: none; font-size: 1.6em; color: #004a99; } .related-tools ul { list-style: none; padding: 0; } .related-tools li { margin-bottom: 10px; } .related-tools a { color: #004a99; text-decoration: none; font-weight: bold; } .related-tools a:hover { text-decoration: underline; } .related-tools p { font-size: 0.9em; color: #6c757d; margin-top: 5px; } footer { text-align: center; margin-top: 40px; padding: 20px; font-size: 0.9em; color: #6c757d; } .highlight { background-color: #ffc107; padding: 2px 5px; border-radius: 3px; font-weight: bold; } .success-text { color: #28a745; font-weight: bold; }

Stock Option Tax Calculator

Estimate your tax liability on Incentive Stock Options (ISOs) and Non-Qualified Stock Options (NSOs).

Stock Option Tax Calculator

Non-Qualified Stock Option (NSO) Incentive Stock Option (ISO) – Regular Taxable Event Incentive Stock Option (ISO) – Alternative Minimum Tax (AMT) Event
Select the type of stock option.
Date the options were granted.
Date when options became exercisable.
Date you exercised your options.
The total number of stock options you are exercising.
The price you pay to buy each share.
The market value of one share on the exercise date.
The market value of one share on the grant date (only needed for ISOs).
The market value of one share on the date you sell the stock.
Date you sold the stock acquired from options.
Your estimated marginal federal income tax rate (e.g., 24 for 24%).
Your estimated marginal state income tax rate (e.g., 5 for 5%).
Your estimated federal long-term capital gains tax rate (e.g., 15 for 15%).
Yes No
Determines tax treatment for ISOs (held > 1 year after exercise AND > 2 years after grant).

Tax Calculation Summary

$0.00
Exercise Cost
$0.00
Ordinary Income
$0.00
Capital Gains
$0.00
AMT Adjustment
$0.00
Formula Explanation:
NSOs are taxed as ordinary income upon exercise on the "bargain element" (FMV at exercise – exercise price). Capital gains/losses are calculated from the FMV at exercise when sold. ISOs have special rules: If it's a "qualifying disposition," gains are long-term capital gains. If "disqualifying," the bargain element at exercise is ordinary income, and any further appreciation upon sale is capital gain (short or long-term depending on sale date). Alternative Minimum Tax (AMT) can apply to ISOs if the bargain element is significant, creating a potential tax liability even if shares aren't sold.

Taxable Events Summary

Summary of Taxable Amounts
Event Date FMV Per Share Exercise Price Per Share Bargain Element Per Share Total Bargain Element Ordinary Income Tax Capital Gain Per Share Total Capital Gain Capital Gains Tax AMT Adjustment Per Share Total AMT Adjustment

Tax Impact Over Time

Chart Explanation: This chart illustrates the estimated tax impact at different stages: Exercise (Ordinary Income Tax, potentially AMT Adjustment) and Sale (Capital Gains Tax). For ISOs, it shows how a qualifying vs. disqualifying disposition affects the tax burden.

Understanding Your Stock Option Tax Liability

Navigating the world of employee stock options can be incredibly rewarding, but it also comes with complex tax implications. Understanding these nuances is crucial for maximizing your net returns. This comprehensive guide and stock option tax calculator are designed to demystify the process, helping you estimate your tax obligations accurately.

What is Stock Option Taxation?

Stock option taxation refers to the rules and rates governing how income and gains derived from exercising and selling employee stock options are taxed by federal and state governments. The way your options are taxed depends heavily on the type of option granted (ISOs vs. NSOs) and how you handle the exercise and sale of the underlying stock.

Who should use this calculator? Any employee who has been granted Incentive Stock Options (ISOs) or Non-Qualified Stock Options (NSOs) and is considering exercising them, or has recently exercised and sold the stock, should use this stock option tax calculator. It's particularly useful for understanding the tax differences between ISOs and NSOs and the impact of qualifying vs. disqualifying dispositions for ISOs.

Common Misconceptions:

  • Myth: All stock options are taxed the same way. This is false; ISOs and NSOs have distinct tax treatments.
  • Myth: You only pay tax when you sell the stock. For NSOs, tax is often due at exercise. For ISOs, even if you don't sell, you might owe Alternative Minimum Tax (AMT).
  • Myth: Exercising ISOs is always tax-free. While they offer potential tax advantages, a "disqualifying disposition" can trigger ordinary income tax, and the bargain element can trigger AMT in the year of exercise.

Stock Option Tax Calculator Formula and Mathematical Explanation

The core of stock option taxation revolves around two main tax events: ordinary income tax and capital gains tax. The exact calculation depends on the option type.

Non-Qualified Stock Options (NSOs)

When you exercise NSOs, you are taxed on the "bargain element" at exercise. This is the difference between the Fair Market Value (FMV) of the stock on the exercise date and the exercise price.

Formula:

Exercise Cost = Number of Options × Exercise Price

Bargain Element Per Share = FMV at Exercise Per Share - Exercise Price Per Share

Total Bargain Element = Number of Options × Bargain Element Per Share

Ordinary Income = Total Bargain Element

Ordinary Income Tax = Ordinary Income × (Federal Tax Rate + State Tax Rate)

When you sell the stock later:

Sale Proceeds = Number of Options × FMV at Sale Per Share

Cost Basis Per Share = Exercise Price Per Share + (Ordinary Income / Number of Options)

Capital Gain Per Share = FMV at Sale Per Share - Cost Basis Per Share

Total Capital Gain = Number of Options × Capital Gain Per Share

Capital Gains Tax = Total Capital Gain × Long-Term Capital Gains Rate (if held > 1 year after exercise)

Incentive Stock Options (ISOs)

ISOs offer potential tax advantages, primarily allowing gains to be treated as long-term capital gains if specific holding periods are met.

Qualifying Disposition (Held > 1 year after exercise AND > 2 years after grant):

Exercise Cost = Number of Options × Exercise Price

Total Gain = Number of Options × (FMV at Sale Per Share - Exercise Price Per Share)

Taxable Gain = Total Gain (treated as long-term capital gain)

Capital Gains Tax = Taxable Gain × Long-Term Capital Gains Rate

Disqualifying Disposition (Does NOT meet holding periods):

The bargain element at exercise is taxed as ordinary income in the year of exercise (or sale, if earlier).

Ordinary Income = Number of Options × (FMV at Exercise Per Share - Exercise Price Per Share)

Ordinary Income Tax = Ordinary Income × (Federal Tax Rate + State Tax Rate)

The sale of the stock is then taxed based on the difference between the sale price and the *cost basis* (exercise price + ordinary income recognized).

Cost Basis Per Share = Exercise Price Per Share + (Ordinary Income / Number of Options)

Capital Gain Per Share = FMV at Sale Per Share - Cost Basis Per Share

Total Capital Gain = Number of Options × Capital Gain Per Share

Capital Gains Tax = Total Capital Gain × (Short/Long-Term Capital Gains Rate depending on sale date relative to exercise date)

Alternative Minimum Tax (AMT) for ISOs

Even in a qualifying disposition, the "bargain element" at exercise (FMV at exercise – exercise price) is an adjustment item for AMT purposes in the year of exercise. If this adjustment, combined with other AMT items, exceeds your regular tax liability, you may owe AMT.

AMT Bargain Element Per Share = FMV at Exercise Per Share - Exercise Price Per Share

Total AMT Bargain Element = Number of Options × AMT Bargain Element Per Share

AMT Adjustment = Total AMT Bargain Element

Note: The AMT paid can sometimes be claimed as a credit in future years.

Variables Used in Stock Option Tax Calculations
Variable Meaning Unit Typical Range
Option Type Classification of the stock option grant (NSO, ISO). String NSO, ISO
Grant Date The date the stock options were officially awarded. Date YYYY-MM-DD
Vesting Date The date(s) when the employee gains the right to exercise options. Date YYYY-MM-DD
Exercise Date The date the employee purchases the stock at the strike price. Date YYYY-MM-DD
Sale Date The date the employee sells the stock acquired via options. Date YYYY-MM-DD
Number of Options The quantity of shares the options represent. Integer 100 – 100,000+
Exercise Price Per Share The fixed price at which the employee can buy each share. Currency ($) $0.10 – $100.00+
FMV at Exercise Per Share The fair market value of one share on the date of exercise. Currency ($) $1.00 – $1,000.00+
FMV at Grant Per Share The fair market value of one share on the grant date (relevant for ISOs). Currency ($) $1.00 – $100.00+
FMV at Sale Per Share The fair market value of one share on the date of sale. Currency ($) $1.00 – $1,000.00+
Federal Tax Rate Estimated marginal federal income tax bracket percentage. Percentage (%) 10 – 37
State Tax Rate Estimated marginal state income tax bracket percentage. Percentage (%) 0 – 13+
LTCG Rate Estimated federal long-term capital gains tax rate. Percentage (%) 0 – 20
Qualifying Disposition Boolean indicating if ISO holding periods are met. Boolean True / False
Exercise Cost Total cost to purchase the shares. Currency ($) Calculated
Bargain Element Difference between FMV and exercise price at exercise. Currency ($) Calculated
Ordinary Income Income subject to standard income tax rates. Currency ($) Calculated
Capital Gain Profit from selling stock at a higher price than basis. Currency ($) Calculated
AMT Adjustment ISO bargain element added back for AMT calculation. Currency ($) Calculated

Practical Examples (Real-World Use Cases)

Example 1: NSO Exercise and Sale

Sarah is granted 10,000 NSOs with an exercise price of $10.00. After vesting, she exercises all options on Jan 15, 2023, when the FMV is $50.00 per share. She sells all the shares on Mar 10, 2024, when the FMV is $70.00 per share. Her estimated federal tax rate is 24%, state is 5%, and long-term capital gains rate is 15%.

Inputs:

  • Option Type: NSO
  • Number of Options: 10,000
  • Exercise Price: $10.00
  • FMV at Exercise: $50.00
  • FMV at Sale: $70.00
  • Federal Tax Rate: 24%
  • State Tax Rate: 5%
  • LTCG Rate: 15%
  • Exercise Date: 2023-01-15
  • Sale Date: 2024-03-10

Calculations:

  • Exercise Cost: 10,000 * $10.00 = $100,000
  • Bargain Element Per Share: $50.00 – $10.00 = $40.00
  • Total Bargain Element (Ordinary Income): 10,000 * $40.00 = $400,000
  • Ordinary Income Tax: $400,000 * (24% + 5%) = $400,000 * 29% = $116,000
  • Cost Basis Per Share: $10.00 + ($400,000 / 10,000) = $10.00 + $40.00 = $50.00
  • Capital Gain Per Share: $70.00 – $50.00 = $20.00
  • Total Capital Gain: 10,000 * $20.00 = $200,000
  • Capital Gains Tax: $200,000 * 15% = $30,000 (LTCG because sold > 1 year after exercise)
  • Total Estimated Tax: $116,000 + $30,000 = $146,000

Interpretation: Sarah owes $116,000 in ordinary income tax upon exercise and $30,000 in long-term capital gains tax when she sells the stock. The stock option tax calculator helps see this breakdown clearly.

Example 2: ISO – Qualifying Disposition

John is granted 5,000 ISOs with an exercise price of $5.00 and FMV at grant of $5.00. He exercises on Feb 1, 2022, when FMV is $25.00. He holds the stock and sells it on Mar 15, 2024, when FMV is $60.00. His estimated federal tax rate is 22%, state is 6%, and LTCG rate is 15%.

Inputs:

  • Option Type: ISO
  • Number of Options: 5,000
  • Exercise Price: $5.00
  • FMV at Exercise: $25.00
  • FMV at Sale: $60.00
  • Federal Tax Rate: 22%
  • State Tax Rate: 6%
  • LTCG Rate: 15%
  • Exercise Date: 2022-02-01
  • Sale Date: 2024-03-15
  • Qualifying Disposition: Yes

Calculations:

  • Exercise Cost: 5,000 * $5.00 = $25,000
  • Sale Proceeds: 5,000 * $60.00 = $300,000
  • Total Gain: $300,000 – $25,000 = $275,000
  • Taxable Gain (as LTCG): $275,000 (because it's a qualifying disposition)
  • Capital Gains Tax: $275,000 * 15% = $41,250
  • AMT Bargain Element Per Share (Year of Exercise 2022): $25.00 – $5.00 = $20.00
  • Total AMT Adjustment (for 2022): 5,000 * $20.00 = $100,000
  • Ordinary Income Tax: $0 (in the year of sale)
  • Total Estimated Tax (upon sale): $41,250 (plus potential AMT in 2022)

Interpretation: John benefits from the ISO treatment, paying only long-term capital gains tax. The stock option tax calculator highlights this by marking it as a Qualifying Disposition. However, he must also consider the potential AMT liability in the year he exercised (2022) due to the $100,000 AMT adjustment.

How to Use This Stock Option Tax Calculator

Using our stock option tax calculator is straightforward. Follow these steps:

  1. Select Option Type: Choose NSO, ISO (Regular), or ISO (AMT) based on your grant.
  2. Enter Dates: Input your Grant Date, Vesting Date, Exercise Date, and Sale Date. Use the calendar picker for accuracy.
  3. Input Option Details: Enter the Number of Options, Exercise Price, FMV at Exercise, FMV at Grant (if applicable for ISOs), and FMV at Sale.
  4. Provide Tax Rates: Enter your estimated Federal and State Income Tax Rates, and your Long-Term Capital Gains Tax Rate.
  5. ISO Specifics: If you selected ISO, indicate whether it was a Qualifying Disposition.
  6. Click Calculate: Press the "Calculate Taxes" button.

How to Read Results: The calculator will display the primary estimated tax liability. It also breaks down key intermediate values like Exercise Cost, Ordinary Income, Capital Gains, and potentially AMT Adjustments. The summary table provides a detailed breakdown of each taxable event.

Decision-Making Guidance: The results help you understand the immediate tax impact of exercising and the potential long-term capital gains tax. Compare the outcomes for NSOs vs. ISOs, or qualifying vs. disqualifying dispositions, to make informed decisions about when to exercise and sell. Remember to consult a tax professional for personalized advice, especially regarding AMT.

Key Factors That Affect Stock Option Tax Results

Several factors significantly influence your final tax bill from stock options. Understanding these helps in planning:

  1. Option Type (NSO vs. ISO): This is the most critical factor. NSOs trigger ordinary income tax at exercise, while ISOs offer potential capital gains treatment if holding periods are met, deferring tax until sale and potentially lowering the rate.
  2. Fair Market Value (FMV) at Exercise: For NSOs, a higher FMV at exercise increases the bargain element, leading to higher ordinary income tax. For ISOs, it increases the potential AMT adjustment.
  3. Exercise Price (Strike Price): A lower exercise price relative to FMV increases the bargain element, thus increasing the taxable amount at exercise for NSOs and the AMT adjustment for ISOs.
  4. Holding Period After Exercise: For ISOs, holding the stock for more than one year after exercise is crucial for qualifying for long-term capital gains tax rates. Selling before this period results in a disqualifying disposition.
  5. Sale Date FMV: The price at which you sell the stock determines your capital gains or losses. A higher sale price results in a larger capital gain, but the tax rate depends on whether it qualifies for long-term rates.
  6. Your Marginal Tax Brackets: Both ordinary income tax rates and capital gains tax rates vary based on your overall income. Higher tax brackets mean a larger tax liability on the same amount of income or gain.
  7. State Income Tax Laws: Different states have varying tax rules for stock options. Some states tax ISOs as ordinary income even if they qualify for federal capital gains treatment.
  8. Alternative Minimum Tax (AMT): The "bargain element" of ISOs at exercise is a preference item for AMT. If your AMT liability exceeds your regular tax, you'll pay the AMT, which can be a substantial, unexpected cost.

Frequently Asked Questions (FAQ)

Q1: When am I taxed on NSOs?

You are typically taxed when you *exercise* NSOs. The difference between the Fair Market Value (FMV) at exercise and your exercise price (the "bargain element") is treated as ordinary income for that year.

Q2: What's the main advantage of ISOs over NSOs?

The primary advantage of ISOs is the potential for favorable tax treatment. If you meet the required holding periods (more than 1 year after exercise and more than 2 years after the grant date), the entire profit from exercise to sale can be taxed at lower long-term capital gains rates instead of higher ordinary income rates.

Q3: What is a "disqualifying disposition" for ISOs?

A disqualifying disposition occurs when you sell stock acquired through ISOs before meeting BOTH the one-year-after-exercise and two-year-after-grant holding periods. When this happens, the bargain element at the time of exercise is taxed as ordinary income in the year of the sale (or exercise, if earlier), negating the primary tax benefit of ISOs.

Q4: Do I have to pay tax on ISOs if I haven't sold the stock yet?

Yes, potentially. The "bargain element" (FMV at exercise minus exercise price) for ISOs is considered when calculating the Alternative Minimum Tax (AMT). Even if you hold onto the stock, you might owe AMT in the year you exercise if the AMT adjustment is significant enough.

Q5: How is the cost basis calculated for stock acquired through options?

For NSOs, your cost basis is your exercise price plus the amount you recognized as ordinary income at exercise. For ISOs in a qualifying disposition, your cost basis is simply your exercise price. For a disqualifying disposition of ISOs, it's the exercise price plus the amount recognized as ordinary income.

Q6: What happens if the FMV at sale is lower than my cost basis?

If you sell the stock for less than your cost basis (the adjusted purchase price, including any taxes paid at exercise), you will have a capital loss. This capital loss can be used to offset other capital gains and, up to a certain limit ($3,000 per year typically), ordinary income.

Q7: Should I exercise all my options at once?

Not necessarily. Consider your financial situation, your company's stability, your belief in its future prospects, diversification needs, and importantly, the tax implications (especially AMT). Exercising in stages might help manage tax liabilities and cash flow.

Q8: Does this calculator account for all possible taxes and scenarios?

This stock option tax calculator provides an estimate based on the inputs provided. It covers federal income tax, state income tax, and federal long-term capital gains tax, along with the AMT adjustment for ISOs. It does not account for nuances like state-specific AMT, payroll taxes (if applicable at exercise for NSOs in some cases), Section 83(b) elections (not typically relevant for options), or complex multi-state tax residency issues. Always consult with a qualified tax advisor for personalized guidance.

© 2023 Your Company Name. All rights reserved. This calculator is for informational purposes only and does not constitute financial or tax advice. Consult with a qualified professional.

function getElement(id) { return document.getElementById(id); } function setText(id, text) { getElement(id).innerText = text; } function setDisplay(id, display) { getElement(id).style.display = display; } function formatCurrency(amount) { if (isNaN(amount) || amount === null) return '$0.00'; return '$' + amount.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,'); } function formatPercentage(value) { if (isNaN(value) || value === null) return '0.00%'; return value.toFixed(2) + '%'; } function isValidDate(dateString) { if (!dateString) return false; var date = new Date(dateString); return !isNaN(date.getTime()); } function daysBetween(date1, date2) { var oneDay = 1000 * 60 * 60 * 24; var date1Ms = new Date(date1).getTime(); var date2Ms = new Date(date2).getTime(); return Math.ceil((date2Ms – date1Ms) / oneDay); } function updateError(elementId, message) { getElement(elementId).innerText = message; } function clearErrors() { getElement('optionTypeError').innerText = "; getElement('grantDateError').innerText = "; getElement('vestingDateError').innerText = "; getElement('exerciseDateError').innerText = "; getElement('numberOfOptionsError').innerText = "; getElement('exercisePriceError').innerText = "; getElement('fairMarketValueAtExerciseError').innerText = "; getElement('fairMarketValueAtGrantError').innerText = "; getElement('fairMarketValueAtSaleError').innerText = "; getElement('saleDateError').innerText = "; getElement('federalTaxRateError').innerText = "; getElement('stateTaxRateError').innerText = "; getElement('longTermCapitalGainsRateError').innerText = "; getElement('isQualifyingDispositionError').innerText = "; } function validateInputs() { var isValid = true; var today = new Date().toISOString().split('T')[0]; var optionType = getElement('optionType').value; var grantDate = getElement('grantDate').value; var vestingDate = getElement('vestingDate').value; var exerciseDate = getElement('exerciseDate').value; var saleDate = getElement('saleDate').value; var numberOfOptions = parseFloat(getElement('numberOfOptions').value); var exercisePrice = parseFloat(getElement('exercisePrice').value); var fairMarketValueAtExercise = parseFloat(getElement('fairMarketValueAtExercise').value); var fairMarketValueAtGrant = parseFloat(getElement('fairMarketValueAtGrant').value); var fairMarketValueAtSale = parseFloat(getElement('fairMarketValueAtSale').value); var federalTaxRate = parseFloat(getElement('federalTaxRate').value); var stateTaxRate = parseFloat(getElement('stateTaxRate').value); var longTermCapitalGainsRate = parseFloat(getElement('longTermCapitalGainsRate').value); if (!grantDate) { updateError('grantDateError', 'Grant date is required.'); isValid = false; } if (!vestingDate) { updateError('vestingDateError', 'Vesting date is required.'); isValid = false; } if (!exerciseDate) { updateError('exerciseDateError', 'Exercise date is required.'); isValid = false; } if (!saleDate && optionType === 'NSO') { updateError('saleDateError', 'Sale date is required for NSO calculations.'); isValid = false; } if (!saleDate && optionType === 'ISO_AMT') { updateError('saleDateError', 'Sale date is required for ISO calculations.'); isValid = false; } if (!saleDate && optionType === 'ISO' && getElement('isQualifyingDisposition').value === 'false') { updateError('saleDateError', 'Sale date is required for disqualifying ISO dispositions.'); isValid = false; } if (isNaN(numberOfOptions) || numberOfOptions <= 0) { updateError('numberOfOptionsError', 'Enter a valid number of options.'); isValid = false; } if (isNaN(exercisePrice) || exercisePrice < 0) { updateError('exercisePriceError', 'Enter a valid exercise price.'); isValid = false; } if (isNaN(fairMarketValueAtExercise) || fairMarketValueAtExercise < 0) { updateError('fairMarketValueAtExerciseError', 'Enter a valid FMV at exercise.'); isValid = false; } if (optionType === 'ISO' || optionType === 'ISO_AMT') { if (isNaN(fairMarketValueAtGrant) || fairMarketValueAtGrant < 0) { updateError('fairMarketValueAtGrantError', 'Enter a valid FMV at grant for ISOs.'); isValid = false; } } if (isNaN(fairMarketValueAtSale) || fairMarketValueAtSale < 0) { updateError('fairMarketValueAtSaleError', 'Enter a valid FMV at sale.'); isValid = false; } if (isNaN(federalTaxRate) || federalTaxRate 100) { updateError('federalTaxRateError', 'Enter a valid federal tax rate (0-100).'); isValid = false; } if (isNaN(stateTaxRate) || stateTaxRate 100) { updateError('stateTaxRateError', 'Enter a valid state tax rate (0-100).'); isValid = false; } if (isNaN(longTermCapitalGainsRate) || longTermCapitalGainsRate 100) { updateError('longTermCapitalGainsRateError', 'Enter a valid LTCG rate (0-100).'); isValid = false; } if (exerciseDate && vestingDate && new Date(exerciseDate) < new Date(vestingDate)) { updateError('exerciseDateError', 'Exercise date cannot be before vesting date.'); isValid = false; } if (exerciseDate && grantDate && new Date(exerciseDate) < new Date(grantDate)) { updateError('exerciseDateError', 'Exercise date cannot be before grant date.'); isValid = false; } if (saleDate && exerciseDate && new Date(saleDate) = 365) { // Long-term capital gain capitalGainsTax = capitalGains * longTermCapitalGainsRate; } else { // Short-term capital gain capitalGainsTax = capitalGains * (federalTaxRate + stateTaxRate); // Using income tax rate for short-term } totalTax = ordinaryIncomeTax + capitalGainsTax; eventTableRows.push({ event: 'NSO Exercise', date: exerciseDate, fmvPerShare: fairMarketValueAtExercise, strikePrice: exercisePrice, bargainElementPerShare: bargainElementPerShare > 0 ? bargainElementPerShare : 0, totalBargainElement: ordinaryIncome > 0 ? ordinaryIncome : 0, ordinaryIncomeTax: ordinaryIncomeTax, capitalGainPerShare: 0, totalCapitalGain: 0, capitalGainsTax: 0, amtAdjustmentPerShare: 0, totalAmtAdjustment: 0 }); eventTableRows.push({ event: 'Stock Sale', date: saleDate, fmvPerShare: fairMarketValueAtSale, strikePrice: exercisePrice, // Base for calculation, not sale price bargainElementPerShare: 0, totalBargainElement: 0, ordinaryIncomeTax: 0, capitalGainPerShare: capitalGains > 0 ? capitalGains / numberOfOptions : (capitalGains = 365 && holdPeriodAfterGrant >= 730) { qualifyingDisposition = true; } } if (qualifyingDisposition) { // Qualifying Disposition: Entire gain is LTCG ordinaryIncome = 0; // No ordinary income at exercise ordinaryIncomeTax = 0; costBasisPerShare = exercisePrice; var saleProceeds = numberOfOptions * fairMarketValueAtSale; var totalCapitalGain = saleProceeds – totalExerciseCost; capitalGains = totalCapitalGain; capitalGainsTax = capitalGains * longTermCapitalGainsRate; totalTax = capitalGainsTax; eventTableRows.push({ event: 'ISO Exercise (Qualifying)', date: exerciseDate, fmvPerShare: fairMarketValueAtExercise, strikePrice: exercisePrice, bargainElementPerShare: 0, // Not taxed as ordinary income totalBargainElement: 0, ordinaryIncomeTax: 0, capitalGainPerShare: 0, // Gain calculated at sale totalCapitalGain: 0, capitalGainsTax: 0, amtAdjustmentPerShare: bargainElementPerShare > 0 ? bargainElementPerShare : 0, // For AMT totalAmtAdjustment: numberOfOptions * (bargainElementPerShare > 0 ? bargainElementPerShare : 0) // For AMT }); eventTableRows.push({ event: 'Stock Sale (Qualifying)', date: saleDate, fmvPerShare: fairMarketValueAtSale, strikePrice: exercisePrice, bargainElementPerShare: 0, totalBargainElement: 0, ordinaryIncomeTax: 0, capitalGainPerShare: capitalGains > 0 ? capitalGains / numberOfOptions : (capitalGains = 365) { // Long-term capital gain on remaining gain capitalGainsTax = capitalGains * longTermCapitalGainsRate; } else { // Short-term capital gain capitalGainsTax = capitalGains * (federalTaxRate + stateTaxRate); } totalTax = ordinaryIncomeTax + capitalGainsTax; eventTableRows.push({ event: 'ISO Exercise (Disqualifying)', date: exerciseDate, fmvPerShare: fairMarketValueAtExercise, strikePrice: exercisePrice, bargainElementPerShare: bargainElementPerShare > 0 ? bargainElementPerShare : 0, totalBargainElement: ordinaryIncome > 0 ? ordinaryIncome : 0, ordinaryIncomeTax: ordinaryIncomeTax, capitalGainPerShare: 0, totalCapitalGain: 0, capitalGainsTax: 0, amtAdjustmentPerShare: 0, // Not taxed as ordinary income, but still potentially AMT relevant totalAmtAdjustment: 0 }); eventTableRows.push({ event: 'Stock Sale (Disqualifying)', date: saleDate, fmvPerShare: fairMarketValueAtSale, strikePrice: exercisePrice, bargainElementPerShare: 0, totalBargainElement: 0, ordinaryIncomeTax: 0, capitalGainPerShare: capitalGains > 0 ? capitalGains / numberOfOptions : (capitalGains 0 ? bargainElementPerShare : 0); } else if (optionType === 'ISO_AMT') { // This option focuses only on the AMT impact, assuming shares are NOT sold yet. // For simplicity, we'll calculate the potential AMT adjustment. // A full AMT calculation is complex and depends on total income. ordinaryIncome = 0; ordinaryIncomeTax = 0; capitalGains = 0; capitalGainsTax = 0; totalTax = 0; // Assume no immediate tax if not selling amtAdjustment = numberOfOptions * (bargainElementPerShare > 0 ? bargainElementPerShare : 0); eventTableRows.push({ event: 'ISO Exercise (AMT Focus)', date: exerciseDate, fmvPerShare: fairMarketValueAtExercise, strikePrice: exercisePrice, bargainElementPerShare: 0, // Not ordinary income tax totalBargainElement: 0, ordinaryIncomeTax: 0, capitalGainPerShare: 0, totalCapitalGain: 0, capitalGainsTax: 0, amtAdjustmentPerShare: bargainElementPerShare > 0 ? bargainElementPerShare : 0, totalAmtAdjustment: amtAdjustment }); // No sale event for this specific calculation path } // Dynamically update the main result and intermediate results display var mainTaxLabel = "Estimated Total Tax:"; if (optionType === 'ISO_AMT') { mainTaxLabel = "Estimated AMT Adjustment:"; setText('mainTaxResult', formatCurrency(amtAdjustment)); setDisplay('exerciseCostDiv', 'none'); setDisplay('ordinaryIncomeDiv', 'none'); setDisplay('capitalGainsDiv', 'none'); setDisplay('amtAdjustmentDiv', 'block'); setText('amtAdjustment', formatCurrency(amtAdjustment)); } else { setText('mainTaxResult', formatCurrency(totalTax)); setDisplay('amtAdjustmentDiv', 'block'); setText('amtAdjustment', formatCurrency(amtAdjustment)); setDisplay('exerciseCostDiv', 'block'); setText('exerciseCost', formatCurrency(totalExerciseCost)); setDisplay('ordinaryIncomeDiv', 'block'); setText('ordinaryIncome', formatCurrency(ordinaryIncome)); setDisplay('capitalGainsDiv', 'block'); setText('capitalGains', formatCurrency(capitalGains)); } getElement('results').style.display = 'flex'; populateTable(eventTableRows); updateChart(eventTableRows, optionType, isQualifyingDisposition); } function populateTable(rows) { var tableBody = getElement('taxEventsTable').getElementsByTagName('tbody')[0]; tableBody.innerHTML = "; // Clear previous rows rows.forEach(function(row) { var tr = tableBody.insertRow(); var cellEvent = tr.insertCell(); cellEvent.textContent = row.event; var cellDate = tr.insertCell(); cellDate.textContent = row.date ? new Date(row.date).toLocaleDateString() : '-'; var cellFMV = tr.insertCell(); cellFMV.textContent = formatCurrency(row.fmvPerShare); var cellStrike = tr.insertCell(); cellStrike.textContent = formatCurrency(row.strikePrice); var cellBargainElementPS = tr.insertCell(); cellBargainElementPS.textContent = formatCurrency(row.bargainElementPerShare); var cellTotalBargainElement = tr.insertCell(); cellTotalBargainElement.textContent = formatCurrency(row.totalBargainElement); var cellOrdinaryIncomeTax = tr.insertCell(); cellOrdinaryIncomeTax.textContent = formatCurrency(row.ordinaryIncomeTax); var cellCapitalGainPS = tr.insertCell(); cellCapitalGainPS.textContent = formatCurrency(row.capitalGainPerShare); var cellTotalCapitalGain = tr.insertCell(); cellTotalCapitalGain.textContent = formatCurrency(row.totalCapitalGain); var cellCapitalGainsTax = tr.insertCell(); cellCapitalGainsTax.textContent = formatCurrency(row.capitalGainsTax); var cellAmtAdjustmentPS = tr.insertCell(); cellAmtAdjustmentPS.textContent = formatCurrency(row.amtAdjustmentPerShare); var cellTotalAmtAdjustment = tr.insertCell(); cellTotalAmtAdjustment.textContent = formatCurrency(row.totalAmtAdjustment); }); } function updateChart(eventRows, optionType, isQualifyingDisposition) { var ctx = getElement('taxImpactChart').getContext('2d'); if (window.taxChartInstance) { window.taxChartInstance.destroy(); // Destroy previous chart instance } // Prepare data for chart var labels = []; var ordinaryIncomeTaxData = []; var capitalGainsTaxData = []; var amtAdjustmentData = []; var exerciseDate = null; var saleDate = null; // Find exercise and sale dates eventRows.forEach(function(row) { if (row.event.includes('Exercise')) { exerciseDate = row.date; } if (row.event.includes('Sale')) { saleDate = row.date; } }); // Generate labels and data points var currentDate = exerciseDate ? new Date(exerciseDate) : new Date(); var endDate = saleDate ? new Date(saleDate) : new Date(currentDate.getTime() + 365 * 24 * 60 * 60 * 1000); // Default to 1 year if no sale date var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; // Add exercise date point if (exerciseDate) { labels.push(months[new Date(exerciseDate).getMonth()] + ' ' + new Date(exerciseDate).getFullYear()); var ordIncomeTaxAtExercise = 0; var capGainsTaxAtExercise = 0; var amtAdjAtExercise = 0; eventRows.forEach(function(row) { if (row.event.includes('Exercise') && row.date === exerciseDate) { ordIncomeTaxAtExercise = row.ordinaryIncomeTax; amtAdjAtExercise = row.totalAmtAdjustment; } }); ordinaryIncomeTaxData.push(ordIncomeTaxAtExercise); capitalGainsTaxData.push(capGainsTaxAtExercise); // Usually 0 at exercise unless disqualifying amtAdjustmentData.push(amtAdjAtExercise); } // Add sale date point if applicable if (saleDate && saleDate !== exerciseDate) { labels.push(months[new Date(saleDate).getMonth()] + ' ' + new Date(saleDate).getFullYear()); var ordIncomeTaxAtSale = 0; var capGainsTaxAtSale = 0; var amtAdjAtSale = 0; // AMT adjustment is typically tied to exercise year eventRows.forEach(function(row) { if (row.event.includes('Sale') && row.date === saleDate) { ordIncomeTaxAtSale = row.ordinaryIncomeTax; // For disqualifying ISO sales capGainsTaxAtSale = row.capitalGainsTax; } }); ordinaryIncomeTaxData.push(ordIncomeTaxAtSale); capitalGainsTaxData.push(capGainsTaxAtSale); amtAdjustmentData.push(amtAdjAtSale); } // Create chart window.taxChartInstance = new Chart(ctx, { type: 'bar', // Use bar chart for clarity of discrete events data: { labels: labels, datasets: [ { label: 'Ordinary Income Tax', data: ordinaryIncomeTaxData, backgroundColor: 'rgba(255, 99, 132, 0.6)', // Reddish for income tax borderColor: 'rgba(255, 99, 132, 1)', borderWidth: 1 }, { label: 'Capital Gains Tax', data: capitalGainsTaxData, backgroundColor: 'rgba(54, 162, 235, 0.6)', // Blueish for capital gains borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 }, { label: 'AMT Adjustment (ISO)', data: amtAdjustmentData, backgroundColor: 'rgba(255, 206, 86, 0.6)', // Yellowish for AMT borderColor: 'rgba(255, 206, 86, 1)', borderWidth: 1, hidden: optionType === 'NSO' // Hide if NSO } ] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, title: { display: true, text: 'Tax Amount ($)' } }, x: { title: { display: true, text: 'Event Timing' } } }, plugins: { title: { display: true, text: 'Estimated Tax Impact at Key Events' }, legend: { position: 'top', } } } }); } function copyResults() { var mainResult = getElement('mainTaxResult').innerText; var exerciseCost = getElement('exerciseCost').innerText; var ordinaryIncome = getElement('ordinaryIncome').innerText; var capitalGains = getElement('capitalGains').innerText; var amtAdjustment = getElement('amtAdjustment').innerText; var assumptions = []; var optionType = getElement('optionType').options[getElement('optionType').selectedIndex].text; var numberOfOptions = getElement('numberOfOptions').value; var exercisePrice = formatCurrency(parseFloat(getElement('exercisePrice').value)); var fmvAtExercise = formatCurrency(parseFloat(getElement('fairMarketValueAtExercise').value)); var fmvAtSale = formatCurrency(parseFloat(getElement('fairMarketValueAtSale').value)); var federalRate = getElement('federalTaxRate').value + '%'; var stateRate = getElement('stateTaxRate').value + '%'; var ltcgRate = getElement('longTermCapitalGainsRate').value + '%'; var isQualifying = getElement('isQualifyingDisposition').value === 'true' ? 'Yes' : 'No'; var copyText = "— Stock Option Tax Calculation Summary —\n\n"; copyText += "Primary Result: " + mainResult + "\n\n"; copyText += "Key Details:\n"; copyText += "- Exercise Cost: " + exerciseCost + "\n"; copyText += "- Ordinary Income: " + ordinaryIncome + "\n"; copyText += "- Capital Gains: " + capitalGains + "\n"; copyText += "- AMT Adjustment (ISO): " + amtAdjustment + "\n\n"; copyText += "Key Assumptions:\n"; copyText += "- Option Type: " + optionType + "\n"; copyText += "- Number of Options: " + numberOfOptions + "\n"; copyText += "- Exercise Price: " + exercisePrice + "\n"; copyText += "- FMV at Exercise: " + fmvAtExercise + "\n"; copyText += "- FMV at Sale: " + fmvAtSale + "\n"; copyText += "- Federal Income Tax Rate: " + federalRate + "\n"; copyText += "- State Income Tax Rate: " + stateRate + "\n"; copyText += "- Long-Term Capital Gains Rate: " + ltcgRate + "\n"; if (optionType.startsWith('ISO')) { copyText += "- Qualifying Disposition: " + isQualifying + "\n"; } // Add table data for more detail copyText += "\n— Detailed Tax Events —\n"; var table = getElement('taxEventsTable'); var rows = table.rows; for (var i = 0; i < rows.length; i++) { var cells = rows[i].cells; var rowText = []; for (var j = 0; j < cells.length; j++) { rowText.push(cells[j].innerText); } copyText += rowText.join('\t') + '\n'; // Use tab for separation, easier to paste into columns } // Use the modern Clipboard API navigator.clipboard.writeText(copyText).then(function() { alert('Results copied to clipboard!'); }, function(err) { console.error('Could not copy text: ', err); // Fallback for older browsers or if permission denied try { var textArea = document.createElement("textarea"); textArea.value = copyText; textArea.style.position = "fixed"; // Avoid scrolling to bottom document.body.appendChild(textArea); textArea.focus(); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); alert('Results copied to clipboard! (Fallback method)'); } catch (e) { alert('Failed to copy results. Please copy manually.'); } }); } function resetForm() { getElement('optionType').value = 'NSO'; getElement('grantDate').value = ''; getElement('vestingDate').value = ''; getElement('exerciseDate').value = ''; getElement('numberOfOptions').value = '1000'; getElement('exercisePrice').value = '5.00'; getElement('fairMarketValueAtExercise').value = '20.00'; getElement('fairMarketValueAtGrant').value = '5.00'; getElement('fairMarketValueAtSale').value = '30.00'; getElement('saleDate').value = ''; getElement('federalTaxRate').value = '24'; getElement('stateTaxRate').value = '5'; getElement('longTermCapitalGainsRate').value = '15'; getElement('isQualifyingDisposition').value = 'true'; clearErrors(); getElement('results').style.display = 'none'; // Reset chart placeholder if it exists var canvas = getElement('taxImpactChart'); if (canvas) { var ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); } // Clear table var tableBody = getElement('taxEventsTable').getElementsByTagName('tbody')[0]; tableBody.innerHTML = ''; } function updateCalculator() { // Optionally call calculateTaxes to update in real-time, or just validate visuals // For performance, might only want to calculate on button click, but updating visuals is good. // Let's call validate and update some placeholder if needed, but actual calc on button. validateInputs(); // Run validation to show errors as user types } // Initial setup or load example data if needed document.addEventListener('DOMContentLoaded', function() { // Set default date values if desired, e.g., today's date for current exercise/sale scenarios var today = new Date().toISOString().split('T')[0]; // getElement('exerciseDate').value = today; // getElement('saleDate').value = today; // Load initial calculation based on default values calculateTaxes(); });

Leave a Comment