Fixing Negative Probabilities in QuantLib Option Pricing
Summary
The document describes a QuantLib American option pricing error that occurs for a deep out-of-the-money call. The accepted answer identifies a likely input-unit problem: the volatility appears to have been supplied as 57.829 rather than as a decimal representing 57.829 percent. Since pricing libraries generally expect volatility in decimal form, the misplaced scale can produce invalid intermediate values, including a negative probability error.
The answer also offers small date-handling conveniences for QuantLib, such as obtaining the current date from the library and parsing a date from a formatted string. The diagnosis is based on the sample input shown in the question, so it is not a general explanation of every negative-probability error. The key practical lesson is to check units and input conventions before changing the pricing engine or its numerical settings. The document does not provide a broader comparison of American option engines or independent validation of the proposed diagnosis.
Key ideas
- QuantLib volatility inputs should be checked for the expected decimal convention.
- A percentage entered as a whole number can cause invalid calculations in an option pricer.
- An error appearing during net present value calculation can originate from an earlier input-unit mismatch.
- QuantLib includes utilities for obtaining the current date and parsing formatted date strings.
- The diagnosis applies to the displayed example and does not explain every negative-probability error.
Tags
Full text
# QuantLib Error "=negative probability"
# QuantLib Error "=negative probability"
I am trying to calculate the price of an american option. The code works fine for some options but for an deep out of the money call, I get the above error. Below is my code that I am trying to run.
I am new to QuantLib so any pointers to resolve the issue, will be of great help. I see the error comes at the very last statement when calculating the NPV, but not sure how to resolve, if I need to tweak anything in my code?
```
def calc_scn_price(p_und_price,p_strike,p_imp_vol,p_op_type,p_exp_date,p_und_bbg_tckr,p_div_yield):
```
t_date = dt.datetime.today() day_count = ql.Actual365Fixed() calendar = ql.UnitedStates() calculation_date = ql.Date(t_date.day,t_date.month,t_date.year)
```
#print("Input to pricer :::",800,' Strike: ',1600.0,' Implied Vol: ',57.82902561325027,' Option Type: ','Call'," Exp Date: ","2021-09-17 00:00:00"," Underlier Ticker: ","TSLA US Equity")
# Settings for evaluation
ql.Settings.instance().evaluationDate = calculation_date
# Risk free rate
v_rfr = 0.0169
v_matur_dt = ql.Date(p_exp_date.day, p_exp_date.month, p_exp_date.year)
# Option Type
if p_op_type == 'Call':
v_op_type = ql.Option.Call
elif p_op_type == 'Put':
v_op_type = ql.Option.Put
else:
raise ValueError("Option Type must be only Call or Put")
# Setup the option
payoff = ql.PlainVanillaPayoff(v_op_type, float(p_strike))
settlement = calculation_date # Assume the transaction happens today since it is an American option
am_excercise = ql.AmericanExercise(settlement, v_matur_dt)
american_option = ql.VanillaOption(payoff, am_excercise)
# ***********Setup Black Scholes Process*********#
S = ql.QuoteHandle(ql.SimpleQuote(p_und_price)) # Underlier Spot Price
r = ql.YieldTermStructureHandle(ql.FlatForward(calculation_date, v_rfr, day_count)) # Risk free rate
v_div_yield = p_div_yield
#v_bbg = blp.bdp(tickers=p_und_bbg_tckr, flds=['PX_LAST','EQY_DVD_YLD_IND'])
#print("Here \n",v_bbg,p_und_bbg_tckr,v_bbg['px_last'].tolist()[0])
# dividend yield - fetch from bbg
#print(v_div_yield)
dividend_yield = ql.YieldTermStructureHandle(ql.FlatForward(calculation_date, float(v_div_yield), day_count))
sigma = ql.BlackVolTermStructureHandle(
ql.BlackConstantVol(calculation_date, calendar, p_imp_vol, day_count))
bsm_process = ql.BlackScholesMertonProcess(S, dividend_yield, r, sigma)
# Use derived implied vol to calculate scenario Option price
am_steps = 800
# Run the engine
binomial_engine = ql.BinomialVanillaEngine(bsm_process, "crr", am_steps)
american_option.setPricingEngine(binomial_engine)
v_op_price = american_option.NPV()
#print(v_op_price)
return v_op_price
```
## Answer by David Duarte (score 2, accepted)
https://quant.stackexchange.com/a/51380
Assuming you are using the inputs from this line:
```
#print("Input to pricer :::",800,' Strike: ',1600.0,' Implied Vol: ',57.82902561325027,' Option Type: ','Call'," Exp Date: ","2021-09-17 00:00:00"," Underlier Ticker: ","TSLA US Equity")
```
it seems you are using the volatility wrong, because your input should be 0.578290, which is 57.8290%, and not 57.829025613.
Additionally, as tips, QuantLib can:
- Get today's date: `ql.Date().todaysDate()`
- Parse dates from strings (ex: BBG dates): `ql.Date('27-02-2020', '%d-%m-%Y')`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.