Skip to content
All library documents

Choosing the Discrete Dividend Model for American Option Pricing

Article Quant Q&A · Author: Fermat

Summary

The document investigates why QuantLib’s finite-difference Black–Scholes engine produces American put prices that diverge from a reference spreadsheet when discrete cash dividends are scheduled near expiration. The question reports that call prices are close to the reference values, while put discrepancies grow for later dividend dates or larger dividends. It supplies sample inputs and outputs, but does not independently establish which prices are correct.

The response explains that the engine supports both a spot dividend model and an escrowed dividend model, with the spot model used by default. It suggests that the reference software appears to use the escrowed approach and shows how to select that model in the engine. This frames the mismatch as a difference in dividend-model assumptions rather than necessarily a defective implementation. The answer is limited: it infers the reference model from the sample results and does not verify the spreadsheet’s settings or compare the models across a broader range of contracts.

Key ideas

  • QuantLib’s finite-difference Black–Scholes engine supports spot and escrowed models for discrete dividends.
  • The spot dividend model is the engine’s default setting.
  • The response infers that the reference spreadsheet may use the escrowed dividend model.
  • Different dividend-model assumptions can produce materially different American option values.
  • The exchange does not verify the reference software’s settings or establish which model is preferable.

Tags

Full text
# QuantLib Inaccurate - American Put Option with Discrete Dividends


# QuantLib Inaccurate - American Put Option with Discrete Dividends












I'm trying to use the QuantLib library to price American options that pay discrete dividends.

The call options are priced with good accuracy (generally <0.1% error), however the same inputs for a put option have a large discrepancy (>50% error) compared to the expected values (obtained from Hoadley's excel software), especially for deep out-the-money put options.

The function I am using is defined as so:

```
import QuantLib as ql

def get_option_price(
    valuation_date = [1,7,2021],
    expiry_date = [1,7,2022],
    strike_price = 70,
    underlying_price = 100,
    volatility = 0.30,
    risk_free_rate = 0.06,
    dividends = [],
    is_american = True,
    is_call = True
    ):
    
    div_dates = []
    div_values = []
    for div in dividends:
        date = div[0]
        value = div[1]
        div_dates.append(ql.Date(*date))
        div_values.append(value)
    
    # Reformat dates from list into QL date format
    valuation_date = ql.Date(*valuation_date)
    expiry_date = ql.Date(*expiry_date)
    ql.Settings.instance().setEvaluationDate(valuation_date)
    day_count = ql.Actual365Fixed()
    calendar = ql.Australia()
    
    # Reformat prices and rates from list into QL format
    underlying_price = ql.QuoteHandle(ql.SimpleQuote(underlying_price))
    risk_free_rate = ql.YieldTermStructureHandle(
        ql.FlatForward(valuation_date, risk_free_rate, day_count))
    volatility = ql.BlackVolTermStructureHandle(
        ql.BlackConstantVol(valuation_date, calendar, volatility, day_count))
    
    # Create option
    if is_call:
        payoff = ql.PlainVanillaPayoff(ql.Option.Call, strike_price)
    else:
        payoff = ql.PlainVanillaPayoff(ql.Option.Put, strike_price)
    if is_american:
        exercise = ql.AmericanExercise(valuation_date, expiry_date)
    else:
        exercise = ql.EuropeanExercise(expiry_date)
    option = ql.DividendVanillaOption(payoff, exercise, div_dates,
                                          div_values)
    
    # Black Scholes process
    process = ql.BlackScholesProcess(underlying_price,
                                          risk_free_rate,
                                          volatility)
    
    # Create option's pricing engine
    precision_steps = 500
    engine = ql.FdBlackScholesVanillaEngine(process, precision_steps, precision_steps - 1)
    option.setPricingEngine(engine)
    
    # Price the option
    return option.NPV()
```

Here are some sample inputs/outputs for call options that generally do as I expect:

```
price = get_option_price(dividends = [[[1,7,2021], 30]], is_call = True)
print(price)
>> 29.999999999999044
# (Expected: 30.0004)

price = get_option_price(dividends = [[[1,1,2022], 30]], is_call = True)
print(price)
>> 32.32516446072868
# (Expected: 32.3034)

price = get_option_price(dividends = [[[30,6,2022], 30]], is_call = True)
print(price)
>> 34.969800332368024
# (Expected: 34.9839)
```

Here are the sample inputs/outputs for put options that are inaccurate:

```
price = get_option_price(dividends = [[[1,7,2021], 30]], is_call = False)
print(price)
>> 6.670681910486139
# (Expected: 6.6734)

price = get_option_price(dividends = [[[1,1,2022], 30]], is_call = False)
print(price)
>> 8.262009670450684
# (Expected: 6.2855)

price = get_option_price(dividends = [[[30,6,2022], 30]], is_call = False)
print(price)
>> 8.882930513922709
# (Expected: 5.6245)
```

The inaccuracy generally worsens as the dividend date approaches expiry, or if the dividend value increases.

- Is there something wrong with my implementation, or is this a limitation of the pricing engine I am using? If it's the latter:

- Are there alternative pricing engines that can handle discrete dividends? (as far as I'm aware QuantLib's BinomialVanillaEngine doesn't support discrete dividend scheduling)

## Answer by Klaus Spanderen (score 3)

https://quant.stackexchange.com/a/68014

The pricing engine FdBlackScholesVanillaEngine supports two types of discrete dividend models, the so called spot model and the escrowed dividend model. The default is the spot dividend model. I have to admit that I do not know your reference "Hoadley's excel software" in detail but looking at the results it seems that this software is using the escrowed dividend model. You can switch to the latter one in QuantLib with

```
engine = ql.FdBlackScholesVanillaEngine.make(
    process,
    tGrid=precision_steps,
    xGrid=precision_steps - 1,
    cashDividendModel=ql.FdBlackScholesVanillaEngine.Escrowed
)
```

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.