# 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

-
Implied vols for equities show skew. There is nothing wrong with IV being so different for different strikes. Having said that there might be something definitely wrong with your code. Hence my comment instead of answer –  Chinmay Patil Mar 20 '13 at 3:17
You can format code on Stack Exchange simply by highlighting it and clicking Ctrl-K. We support Markdown for formatting here. –  chrisaycock Mar 20 '13 at 3:28
becareful for rounding errors.. and no options series will have all the same implieds across the strike space.. –  cdcaveman Mar 20 '13 at 4:33
I vote to close it as long as the table on top isn't cleaned up. A clear table will allow simple answering by anyone with a implied vol calculator –  Bob Jansen Mar 20 '13 at 13:17
I know and often do but these dumps without coming back are quite irritating. Despite heavy editing by other editors there still was an error. This doesn't help anyone :( –  Bob Jansen Mar 23 '13 at 19:42

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))
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/delta

-

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

-