1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
Global Const Pi = 3.14159265358979
'// The normal distribution function
Public Function ND(X As Double) As Double
ND = 1 / Sqr(2 * Pi) * Exp(-X ^ 2 / 2)
End Function
'// Cummulative double precision algorithm based on Hart 1968
'// Based on implementation by Graham
Function CND(X As Double) As Double
Dim Y As Double, Exponential As Double, SumA As Double, SumB As Double
Y = Abs(X)
If Y > 37 Then
CND = 0
Else
Exponential = Exp(-Y ^ 2 / 2)
If Y < 7.07106781186547 Then
SumA = 3.52624965998911E-02 * Y + 0.700383064443688
SumA = SumA * Y + 6.37396220353165
SumA = SumA * Y + 33.912866078383
SumA = SumA * Y + 112.079291497871
SumA = SumA * Y + 221.213596169931
SumA = SumA * Y + 220.206867912376
SumB = 8.83883476483184E-02 * Y + 1.75566716318264
SumB = SumB * Y + 16.064177579207
SumB = SumB * Y + 86.7807322029461
SumB = SumB * Y + 296.564248779674
SumB = SumB * Y + 637.333633378831
SumB = SumB * Y + 793.826512519948
SumB = SumB * Y + 440.413735824752
CND = Exponential * SumA / SumB
Else
SumA = Y + 0.65
SumA = Y + 4 / SumA
SumA = Y + 3 / SumA
SumA = Y + 2 / SumA
SumA = Y + 1 / SumA
CND = Exponential / (SumA * 2.506628274631)
End If
End If
If X > 0 Then CND = 1 - CND
End Function
Public Function GImpliedVolatilityNR(CallPutFlag As String, S As Double, X _
As Double, T As Double, r As Double, B As Double, cm As Double, epsilon As Double)
Dim vi As Double, ci As Double
Dim vegai As Double
Dim minDiff As Double
'Manaster and Koehler seed value (vi)
vi = Sqr(Abs(Log(S / X) + r * T) * 2 / T)
ci = GBlackScholes(CallPutFlag, S, X, T, r, B, vi)
vegai = GVega(S, X, T, r, B, vi)
minDiff = Abs(cm - ci)
While Abs(cm - ci) >= epsilon And Abs(cm - ci) <= minDiff
vi = vi - (ci - cm) / vegai
ci = GBlackScholes(CallPutFlag, S, X, T, r, B, vi)
vegai = GVega(S, X, T, r, B, vi)
minDiff = Abs(cm - ci)
Wend
If Abs(cm - ci) < epsilon Then GImpliedVolatilityNR = vi Else GImpliedVolatilityNR = "NA"
End Function
'// The generalized Black and Scholes formula
Public Function GBlackScholes(CallPutFlag As String, S As Double, X _
As Double, T As Double, r As Double, B As Double, v As Double) As Double
Dim d1 As Double, d2 As Double
d1 = (Log(S / X) + (B + v ^ 2 / 2) * T) / (v * Sqr(T))
d2 = d1 - v * Sqr(T)
If CallPutFlag = "c" Then
GBlackScholes = S * Exp((B - r) * T) * CND(d1) - X * Exp(-r * T) * CND(d2)
ElseIf CallPutFlag = "p" Then
GBlackScholes = X * Exp(-r * T) * CND(-d2) - S * Exp((B - r) * T) * CND(-d1)
End If
End Function
'// Vega for the generalized Black and Scholes formula
Public Function GVega(S As Double, X As Double, T As Double, r As Double, B As Double, v As Double) As Double
Dim d1 As Double
d1 = (Log(S / X) + (B + v ^ 2 / 2) * T) / (v * Sqr(T))
GVega = S * Exp((B - r) * T) * ND(d1) * Sqr(T)
End Function
Public Function SkewKurtCorradoSuModified(CallPutFlag As String, S As Double, X As Double, _
T As Double, r As Double, B As Double, v As Double, Skew As Double, Kurt As Double) As Double
Dim Q3 As Double, Q4 As Double
Dim d As Double, w As Double
Dim CallValue As Double
w = Skew / 6 * v ^ 3 * T ^ 1.5 + Kurt / 24 * v ^ 4 * T ^ 2
d = (Log(S / X) + (B + v ^ 2 / 2) * T - Log(1 + w)) / (v * Sqr(T))
Q3 = 1 / (6 * (1 + w)) * S * v * Sqr(T) * (2 * v * Sqr(T) - d) * ND(d)
Q4 = 1 / (24 * 1 + w) * S * v * Sqr(T) * (d ^ 2 - 3 * d * v * Sqr(T) + 3 * v ^ 2 * T - 1) * ND(d)
CallValue = GBlackScholes("c", S, X, T, r, B, v) + Skew * Q3 + (Kurt - 3) * Q4
If CallPutFlag = "c" Then
SkewKurtCorradoSuModified = CallValue
Else '// Use put-call parity to find put value
SkewKurtCorradoSuModified = CallValue - S * Exp((B - r) * T) + X * Exp(-r * T)
End If
End Function
Public Function ESkewKurtCorradoSuModified(OutPutFlag As String, CallPutFlag As String, S As Double, X As Double, T As Double, _
r As Double, B As Double, v As Double, Skew As Double, Kurt As Double, Optional dS)
If IsMissing(dS) Then
dS = 0.1
End If
If OutPutFlag = "p" Then ' Value
ESkewKurtCorradoSuModified = SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r, B, v, Skew, Kurt)
ElseIf OutPutFlag = "d" Then 'Delta
ESkewKurtCorradoSuModified = (SkewKurtCorradoSuModified(CallPutFlag, S + dS, X, T, r, B, v, Skew, Kurt) - SkewKurtCorradoSuModified(CallPutFlag, S - dS, X, T, r, B, v, Skew, Kurt)) / (2 * dS)
ElseIf OutPutFlag = "g" Then 'Gamma
ESkewKurtCorradoSuModified = (SkewKurtCorradoSuModified(CallPutFlag, S + dS, X, T, r, B, v, Skew, Kurt) - 2 * SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r, B, v, Skew, Kurt) + SkewKurtCorradoSuModified(CallPutFlag, S - dS, X, T, r, B, v, Skew, Kurt)) / dS ^ 2
ElseIf OutPutFlag = "v" Then 'Vega
ESkewKurtCorradoSuModified = (SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r, B, v + 0.01, Skew, Kurt) - SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r, B, v - 0.01, Skew, Kurt)) / 2
ElseIf OutPutFlag = "t" Then 'Theta
If T <= 1 / 365 Then
ESkewKurtCorradoSuModified = SkewKurtCorradoSuModified(CallPutFlag, S, X, 0.00001, r, B, v, Skew, Kurt) - SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r, B, v, Skew, Kurt)
Else
ESkewKurtCorradoSuModified = SkewKurtCorradoSuModified(CallPutFlag, S, X, T - 1 / 365, r, B, v, Skew, Kurt) - SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r, B, v, Skew, Kurt)
End If
ElseIf OutPutFlag = "r" Then 'Rho
ESkewKurtCorradoSuModified = (SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r + 0.01, B + 0.01, v, Skew, Kurt) - SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r - 0.01, B - 0.01, v, Skew, Kurt)) / (2)
ElseIf OutPutFlag = "fr" Then 'Futures options rho
ESkewKurtCorradoSuModified = (SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r + 0.01, B, v, Skew, Kurt) - SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r - 0.01, B, v, Skew, Kurt)) / (2)
ElseIf OutPutFlag = "f" Then 'Rho2
ESkewKurtCorradoSuModified = (SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r, B - 0.01, v, Skew, Kurt) - SkewKurtCorradoSuModified(CallPutFlag, S, X, T, r, B + 0.01, v, Skew, Kurt)) / (2)
End If
End Function
|