Interpreting Implied Volatility Differences Across Option Strikes
Summary
The note addresses why implied volatilities calculated from option prices differ across strikes. It explains that Black–Scholes implied volatility is the volatility input that reproduces a given market price under the model; when the model assumes a single constant volatility, observed prices across strikes can imply different values. Such strike-dependent quotes are consistent with a volatility smile or skew and do not, by themselves, prove the numerical solver is faulty.
The discussion also identifies coding issues that can affect results. In Visual Basic, a type declaration applies only to the variable immediately before it, so declaring several variables in one statement can leave most with unintended types. A bisection routine should keep a valid price bracket and terminate when its price error or interval width is sufficiently small; the included example’s labels and missing put-pricing logic also complicate comparison. Newton iteration using vega is offered as another approach, with an initial existence check. The examples are specific to European Black–Scholes pricing and do not validate the input prices or assumptions.
Key ideas
- Different strikes can imply different volatilities because market option prices need not follow constant-volatility Black–Scholes prices.
- Strike-dependent implied volatility can reflect a smile or skew rather than a solver bug.
- In Visual Basic, each variable needs its own explicit type declaration.
- Bisection requires a valid bracket and clear stopping conditions; put prices need a put-pricing implementation.
- Newton’s method can use vega to update volatility but should check whether a valid implied volatility exists.
Tags
Full text
# Why the implied volatilities calculated are so different
# Why the implied volatilities calculated are so different
I Calculated facebook option(expired in 12/4/13) Implied Volatility with the Bisection Method. The program will be attached at the end. The results for different strike prices are so different:
```
call put call put put
Stock Price 26.55 26.55 26.55 26.55 26.55
Strike Price 26.5 26.5 27 27 28
Time to maturity 0.06301
Risk Free Rate 1.88E-02
Dividend Yield 0 0 0 0
Option Price 0.87 0.86 0.63 1.08 1.65
Result
Implied Volatility 0.312236566 0.308462006 0.306893589 0.477272194
0.840291866
```
Can any tell me what's wrong with the program?
```
Public TargetColume As Integer
Function BlackScholesCall( _
ByVal S As Double, _
ByVal X As Double, _
ByVal T As Double, _
ByVal r As Double, _
ByVal d As Double, _
ByVal v As Double) As Double
Dim d1 As Double
Dim d2 As Double
d1 = (Log(S / X) + (r - d + v ^ 2 / 2) * T) / v / Sqr(T)
d2 = d1 - v * Sqr(T)
BlackScholesCall = Exp(-d * T) * S * Application.NormSDist(d1) - X * Exp(-r * T) * Application.NormSDist(d2)
End Function
Function ImpliedVolatility( _
ByVal S As Double, _
ByVal X As Double, _
ByVal T As Double, _
ByVal r As Double, _
ByVal d As Double, _
ByVal Price As Double) As Double
Dim epsilonABS As Double
Dim epsilonSTEP As Double
Dim volMid As Double
Dim niter As Integer
Dim volLower As Double
Dim volUpper As Double
epsilonABS = 0.0000001
epsilonSTEP = 0.0000001
niter = 0
volLower = 0.001
volUpper = 1
Do While volUpper - volLower >= epsilonSTEP Or Abs(BlackScholesCall(S, X, T, r, d, volLower) - Price) >= epsilonABS And epsilonABS <= Abs(BlackScholesCall(S, X, T, r, d, volUpper) - Price) >= epsilonABS
volMid = (volLower + volUpper) / 2
If Abs(BlackScholesCall(S, X, T, r, d, volMid) - Price) <= epsilonABS Then
Exit Do
ElseIf ((BlackScholesCall(S, X, T, r, d, volLower) - Price) * (BlackScholesCall(S, X, T, r, d, volMid) - Price) < 0) Then
volUpper = volMid
Else
volLower = volMid
End If
niter = niter + 1
Loop
ImpliedVolatility = volLower
End Function
Function CalcImpliedVolatility()
Dim S, X, T, r, d, Price As Double
Dim volatility As Double
S = ActiveSheet.Cells(6, TargetColume).Value
X = ActiveSheet.Cells(7, TargetColume).Value
T = ActiveSheet.Cells(8, "B").Value
r = ActiveSheet.Cells(9, "B").Value
d = ActiveSheet.Cells(10, TargetColume).Value
Price = ActiveSheet.Cells(11, TargetColume).Value
volatility = ImpliedVolatility(S, X, T, r, d, Price)
ActiveSheet.Cells(14, TargetColume).Value = volatility
End Function
Private Sub CommandButton1_Click()
CalcImpliedVolatility
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
TargetColume = Target.Column
End Sub
```
## Answer by Bob Jansen (score 2)
https://quant.stackexchange.com/a/7592
The line
```
Dim S, X, T, r, d, Price As Double
```
is better written as
```
Dim S As Double, X As Double, T As Double, r As Double, d As Double, Price As Double
```
because 'as' only applies to the variable directly before it.
The bisection algorithm seems to work as advertised. You could check with an online calculator such as this one. I've rewritten the function to be more efficient and shorter although I believe the initial output was also correct but the column header are wrong, some puts are calls and the code for puts is not included. Anyway here is the code.
```
Private Const maxIter As Long = 100000#
Private Const epsilonABS As Double = 0.0000001
Private Const epsilonSTEP As Double = 0.0000001
Public Function ImpliedVolatility( _
S As Double, X As Double, T As Double, r As Double, d As Double, _
Price As Double _
) As Double
Dim volMid As Double, valMid As Double, diff As Double
Dim niter As Integer
volLower = 0.001
volUpper = 1
niter = 0
Do
volMid = (volLower + volUpper) / 2
valMid = BlackScholesCall(S, X, T, r, d, volMid)
diff = Abs(valMid - Price)
If valMid > Price Then
volUpper = volMid
Else
volLower = volMid
End If
niter = niter + 1
Loop While volUpper - volLower >= epsilonSTEP And diff > epsilonABS And _
niter < maxIter
ImpliedVolatility = volMid
End Function
```
## Answer by 4pie0 (score 1)
https://quant.stackexchange.com/a/7569
you can use this code from Uwe Wystup FX Options and Structured Products. you can find it online. it uses vega and taylor expansion (just to 1st derivative which is vega) to find vol. you have to have code for european call price, but you have it already
```
Function VanillaVolRetriever(spot As Double, rd As Double,rf As Double, strike As Double, T As Double, type As Integer, GivenValue As Double) As Double
Dim func As Double
Dim dfunc As Double
Dim maxit As Integer ’maximum number of iterations
Dim j As Integer
Dim s As Double
’first check if a volatility exists, otherwise set result to zero
If GivenValue<Application.Max(0,type*(spot*Exp(-rf*T)-strike*Exp(-rd * T)))Or(type = 1 And GivenValue > spot*Exp(-rf * T)) Or (type = -1 And GivenValue > strike * Exp(-rd * T)) Then VanillaVolRetriever = 0
Else
’ there exists a volatility yielding the given value,
’ now use Newton’s method:
’ the mapping vol to value has a saddle point.
’ First compute this saddle point:
saddle = Sqr(2/T * Abs(Log(spot / strike) + (rd - rf) * T))
If saddle > 0 Then
VanillaVolRetriever = saddle * 0.9
Else
VanillaVolRetriever = 0.1
End If
maxit = 100
For j = 1 To maxit Step 1
func = Vanilla(spot, strike, VanillaVolRetriever, rd, rf, T, type, value) - GivenValue
dfunc = Vanilla(spot, strike, VanillaVolRetriever,rd, rf, T, type, vega)
VanillaVolRetriever = VanillaVolRetriever - func / dfunc
If VanillaVolRetriever <= 0 Then
VanillaVolRetriever = 0.01
If Abs(func / dfunc) <= 0.0000001 Then j = maxit
Next j
End If
End Function
```
you can find it also here
it is absolutely OK that they are different dependent on strike, you would suspect there's bug in your function otherwise. this is reality: we use BS model with const vol assumption and we quote different vol for different strike/deltaShown 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.