Calculate the partial derivative of an option based on the Black Scholes Model. The Black Scholes Model is a mathematical model used to estimate the price of European-style options. The partial derivative is the second derivative of the option price with respect to the strike price, the rate at which the dual delta changes with the strike.

Note that this uses a single, flat assumed volatility (the same value at every strike price) rather than the market’s actual implied volatility smile. This means it is NOT the Breeden-Litzenberger risk-neutral density – with a flat volatility input the second derivative can only ever recover a lognormal density, regardless of what the real market smile looks like, which defeats the entire purpose of that theorem. For the actual market-implied (smile-consistent) risk-neutral density, see get_risk_neutral_density, which uses this same second-derivative relationship but applied to a volatility surface calibrated to real market option prices instead of a flat assumption.

The formula is as follows:

\[\text{Partial Derivative} (\text{PD}) = e ^{- r \cdot t} \cdot (1 / K) \cdot (1 / \sqrt{2 \cdot \pi \cdot \sigma ^{2} \cdot t}) \cdot e ^{- (1 / (2 \cdot \sigma ^{2} \cdot t)) \cdot (\ln(K / S) - ((r - q) - (0.5 \cdot \sigma ^{2})) \cdot t) ^{2}}\]

Where S is the stock price, K is the strike price, r is the risk free rate, q is the dividend yield, σ is the volatility and t is the time to expiration. This expression is algebraically identical to e^(-r * t) * N’(d2) / (K * σ * sqrt(t)), i.e. to the Dual Gamma, since both are the second derivative of the option price with respect to the strike price.

Also known as: second strike derivative, lognormal risk-neutral density.

Partial Derivative in Python or via the MCP

Install the Finance Toolkit with:

pip install financetoolkit -U

Then call get_partial_derivative as shown below.

from financetoolkit import Toolkit

toolkit = Toolkit(
    ["BAC"],
    api_key="FINANCIAL_MODELING_PREP_KEY",
    start_date="2025-01-01",
    end_date="2025-12-31",
)

toolkit.options.get_partial_derivative(
    strike_price_range=0.2, strike_step_size=1
).loc["BAC", ["2026-01-07", "2026-01-14", "2026-01-28"]]

Or, after setting up the Finance Toolkit MCP, ask:

What was the second derivative of the price of Bank of America's call options with respect to the strike at the end of 2025 for the expiries of 7, 14 and 28 January 2026, for strikes within 20% of the share price in $1 steps?

Which returns:

Strike Price 2026-01-07 2026-01-14 2026-01-28
44 0 0 0.0014
45 0 0.0001 0.0032
46 0 0.0005 0.0066
47 0 0.0019 0.0124
48 0.0003 0.0056 0.0213
49 0.0017 0.014 0.0332
50 0.008 0.0296 0.0478
51 0.0269 0.0536 0.0635
52 0.0665 0.0833 0.0783
53 0.1241 0.1125 0.09
54 0.1769 0.1328 0.0967
55 0.1956 0.1382 0.0975
56 0.1701 0.1275 0.0927
57 0.1178 0.105 0.0832
58 0.0657 0.0776 0.0708
59 0.0299 0.0518 0.0573
60 0.0112 0.0314 0.0441
61 0.0035 0.0173 0.0325
62 0.0009 0.0088 0.0229
63 0.0002 0.0041 0.0155
64 0 0.0018 0.0101
65 0 0.0007 0.0063

Parameters

get_partial_derivative accepts the following parameters.

ParameterTypeDescriptionExample
start_datestr | NoneThe date whose price, volatility and rates the values start from; a date without prices (a weekend or a holiday) uses the last trading day before it, and a ticker without a price on that day is left out with a warning. Defaults to None, which uses the last date of the historical data."2021-01-01"
strike_price_rangefloatThe percentage range to use for the strike prices. Defaults to 0.25 which equals 25% and thus results in strike prices from 75 to 125 if the current stock price is 100.0.1
strike_step_sizeintThe step size to use for the strike prices. Defaults to 5 which means that the strike prices will be 75, 80, 85, 90, 95, 100, 105, 110, 115 and 120 if the current stock price is 100.1
expiration_time_rangeintThe number of days to use for the time to expiration: the columns are the expirations 1 up to expiration_time_range - 1 days after the start date. Defaults to 30, which gives expirations of 1 to 29 days.90
risk_free_ratefloatThe risk free rate to use for the calculation. Defaults to None, which uses the Toolkit’s risk-free rate on the pricing date: the 10-year Treasury yield unless the Toolkit’s risk_free_rate parameter selects ‘13w’, ‘5y’ or ‘30y’, converted from its semi-annual bond-equivalent quote to continuous compounding. A rate passed here is used as given, as a continuously compounded rate.0.04
dividend_yieldfloatThe dividend yield to use for the calculation. Defaults to None which means it will use the current dividend yield.0.02
show_input_infoboolWhether to show the input information. Defaults to False.True
roundingint | NoneThe number of decimals to round the results to. Defaults to None, which uses the rounding of the Toolkit (4 unless set otherwise).2
standardizeboolWhether to standardize (Z-Score) the result across the time to expiration columns for each ticker and strike price. Defaults to False.True
Share