[R-SIG-Finance] RQuantLib: AmericanOptionImpliedVolatility bug

Charles Duranceau cduranceau at nial.ky
Wed May 31 01:01:28 CEST 2017

Hi Robert,
Thank you for your feedback. I don’t disagree with you. There must be a (positive) time value in the option in order to have an implied volatility. But the implied volatility is function of the model (pricing engine).
I now think the problem is located to the engine="BaroneAdesiWhaley" when risk free rate is negative.

Let me take another approach by calculating the premium for the same option (with the same parameter) using an arbitrary volatility of 30% (below I paste the example) so using directly the option valuation to calculate the premium I will get

Option intrinsic value = 14.49957
EuropeanOption = 14.5019 => this is expected:  very little time value due to deep in-the-money and little time before expiration
AmericanOption, engine="CrankNicolson"= 14.5019 => it is floored to European option value but the early exercise has no value as rate is negative
AmericanOption, engine="BaroneAdesiWhaley" = error message => this is not expected

 “Error in americanOptionEngine(type, underlying, strike, dividendYield,  : forward + displacement (-8.68397e+012 + 0) must be positive”

I suspect here the engine="BaroneAdesiWhaley" does not behave well under a negative rate. I don’t have this error when rate is positive. Adding a positive (and higher) dividend yield does not help either which isolate the problem to the rate side.
My understanding of BAW approximation for non-dividend American put is that it is not optimal to exercise when rates are negative (negative carry) and thus should default to the European option value.


Replication in R

strike = 65
Spot= 50.5
Rate = -0.00361
DividendYield = 0
Volatility = 0.3
YearToMaturity = 3/365

(strike-Spot)*exp((Rate-DividendYield)*YearToMaturity) # intrinsic value
EuropeanOption("put", Spot, strike,DividendYield, Rate,YearToMaturity, Volatility)
AmericanOption("put", Spot, strike, DividendYield, Rate,YearToMaturity, Volatility,timeSteps=150, gridPoints=149, engine="CrankNicolson")
AmericanOption("put", Spot, strike, DividendYield, Rate,YearToMaturity, Volatility,timeSteps=150, gridPoints=149, engine="BaroneAdesiWhaley") # error

From: Robert Harlow [mailto:rharlow86 at gmail.com]
Sent: Saturday, May 27, 2017 6:10 AM
To: Charles Duranceau
Cc: r-sig-finance at r-project.org
Subject: Re: [R-SIG-Finance] RQuantLib: AmericanOptionImpliedVolatility bug

Doesn't the error message say root not bracketed? That is informative because it means there is no root, or no implied volatility, that gives you back your price of 14.5- this is what you should expect given your inputs.  In order for a volatility to exist an option must have a positive time value.


On May 26, 2017, at 6:55 PM, Charles Duranceau <cduranceau at nial.ky<mailto:cduranceau at nial.ky>> wrote:
Thank you Robert,
I agree with you this is an extreme case and I don’t expect too much accuracy from the implied volatility I get, but my concern was more about the error message (a NA would have been more desirable)
By changing the engine I managed a workaround but I thought RQL team (or someone else having the same problem) could be interested with that non-desirable behavior.


From: Robert Harlow [mailto:rharlow86 at gmail.com]
Sent: Friday, May 26, 2017 3:32 PM
To: Charles Duranceau
Cc: r-sig-finance at r-project.org<mailto:r-sig-finance at r-project.org>
Subject: Re: [R-SIG-Finance] RQuantLib: AmericanOptionImpliedVolatility bug

Charles, my suggestion (which I doubt you will like) is to wrap your calls to implied volatility root finders (quant lib or any others) in a try block that returns NA on error.  Your example (very little or no time value) can be common if you are using mid prices from bid-ask quotes.  Note that when you plug the answer from your sum of squares root finding routine back into AmericanOption you get a value slightly above 14.5.

On Fri, May 26, 2017 at 11:46 AM, Charles Duranceau <cduranceau at nial.ky<mailto:cduranceau at nial.ky>> wrote:

I found a problem with the function "AmericanOptionImpliedVolatility" in RQantLib which return an error for a specific set of conditions (but cannot identifies exactly what are these).
I present a case related to a short term, very deep in-the-money put with negative interest rate that generate error message. I present a reproducible example below.
I found the related function "AmericanOption" with default produce similar error when use in a routine to back-out the implied volatility.
However, I found good result (no error)  when using the engine="CrankNicolson" :  a naïve routine for backing-out the implied vol with this function return a volatility.
There's a work around but think this information may add more stability to RQL.

Best Regards

RQuantLib Version 4.2

R version 3.3.2 (64bits)


price = 14.5
strike = 65
Spot= 50.5
Rate = -0.00361
DividendYield = 0
Volatility = 0.296
YearToMaturity = 3/365

# error when Implied Vol
AmericanOptionImpliedVolatility("put", price,Spot, strike, DividendYield, Rate,YearToMaturity, Volatility)

Error in americanOptionImpliedVolatilityEngine(type, value, underlying,  :

../../../QuantLib-1.6.2/ql/math/solver1d.hpp:202: In function `QuantLib::Real QuantLib::Solver1D<Impl>::solve(const F&, QuantLib::Real, QuantLib::Real, QuantLib::Real, QuantLib::Real) const [with F = QuantLib::{anonymous}::PriceError; Impl = QuantLib::Brent; QuantLib::Real = double]':
root not bracketed: f[1e-007,4] -> [1.955446e-003,3.006858e+000]

#also generate error
AmericanOption("put", Spot, strike, DividendYield, Rate,YearToMaturity, Volatility)

# works well
AmericanOption("put", Spot, strike, DividendYield, Rate,YearToMaturity, Volatility,timeSteps=150, gridPoints=149, engine="CrankNicolson")
# backing out the implied vol naively works
fImpliedVol(Volatility,price,"put", Spot, strike, DividendYield, Rate,YearToMaturity)

fImpliedVol<-function(iniVol,Premium,Callput, Spot, Strike, DivYield, Rate,YrtoMat){
  ftm<-function(ImpVol,Premium,Callput, Spot, Strike, DivYield, Rate,YrtoMat, iVol)
    ov<-AmericanOption(type=Callput, underlying=Spot, strike=Strike,dividendYield=DivYield, riskFreeRate=Rate, maturity=YrtoMat,volatility=ImpVol,
                       timeSteps=150, gridPoints=149, engine= "CrankNicolson")
  imp<-optimize(f=ftm,c(lower = 0, upper = 1.5), tol = 1e-4,Premium,Callput,Spot, Strike, DivYield, Rate,YrtoMat)

> sessionInfo()
R version 3.3.2 (2016-10-31)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)

[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252    LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                           LC_TIME=English_United States.1252

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

other attached packages:
[1] RQuantLib_0.4.3 dplyr_0.5.0

loaded via a namespace (and not attached):
[1] zoo_1.8-0        magrittr_1.5     R6_2.1.2         assertthat_0.2.0 DBI_0.6-1        tools_3.3.2      tibble_1.0       Rcpp_0.12.10
 [9] grid_3.3.2       lattice_0.20-34


        [[alternative HTML version deleted]]

R-SIG-Finance at r-project.org<mailto:R-SIG-Finance at r-project.org> mailing list
-- Subscriber-posting only. If you want to post, subscribe first.
-- Also note that this is not the r-help list where general R questions should go.

	[[alternative HTML version deleted]]

More information about the R-SIG-Finance mailing list