Appendix: Some Source Codes
Total Page:16
File Type:pdf, Size:1020Kb
Appendix: Some Source Codes In VBA, (Visual Basic for Application) the code for a European call option with the binomial model can be written as: Function eCall(S, K, T, r, sigma, n) u ¼ Exp(sigma*((T/n)^0.5)) d ¼ 1/u r ¼ Exp(r*(T/n)) rp_u ¼ (r - d)/(r*(u - d)) rp_d ¼ 1/r - rp_u eCall ¼ 0 For i ¼ 0Ton eCall ¼ eCall + Application.Combin(n, i)*rp_u^i*rp_d^(n - i)* _ Application.Max(S*u^i*d^(n - i) - K, 0) Next i End Function A more general binomial model, which also handles American-type options, is given below. This code is written in VBA and handles some of the binomial models such as Cox–Ross–Rubenstein (with and without Black–Scholes smoothing) and the Leisen–Reimer model. The model also calculates the Greeks, delta, gamma and theta. To calculate rho and vega, two trees must be made with two different interest rates and volatilities, respectively © The Author(s) 2017 461 J.R.M. Röman, Analytical Finance: Volume I, DOI 10.1007/978-3-319-34027-2 462 Appendix: Some Source Codes ’ Input mBin ¼ Binomial model ’ mExe ¼ Put or Call (PUT_ or CALL_) ’ mTyp ¼ American or European Function Binom(mBin As Long, mTyp As Long, mExe As Long, S As Double, X As Double, T As Double, r As Double, v As Double, n As Long, mDelta As Double, mGamma As Double, mTheta As Double) Dim d1 As Double, d2 As Double, a As Double, b As Double Dim aa As Double, vv As Double, U As Double, D As Double Dim udd As Double, u_d As Double, p As Double, Dt As Double Dim disc As Double, pe As Double, my As Double, m As Double Dim q As Double, ermqdt As Double, pdash As Double, ans As Double Dim idx As Long, i As Long, j As Long Dim lSt1(0 To 2) As Double Dim lC1(0 To 2) As Double ReDim lSt(0 To n + 2) As Double ReDim lC(0 To n + 2) As Double d1 ¼ (Log(S / X) + (r +v*v/2)*T)/(v*Sqr(T)) d2 ¼ d1 - v * Sqr(T) Dt ¼ T/n disc ¼ Exp(-r * Dt) If (mBin ¼ CRR) Then U ¼ Exp(v * Sqr(Dt)) D ¼ 1/U udd ¼ U/D u_d ¼ U-D p ¼ (1 / disc - D) / u_d ElseIf (mBin ¼ PEG) Then pe ¼ (Log(X / S)) / n U ¼ Exp(pe + v * Sqr(Dt)) D ¼ Exp(pe - v * Sqr(Dt)) udd ¼ U/D u_d ¼ U-D p ¼ (1 / disc - D) / u_d ElseIf (mBin ¼ JR) Then ’ Remark pu ¼ pd ¼ 0.5! ’ In this method the calc. of delta and gamma (rho+) is more ’ difficult since S0 <> S0*u*d. Use ORC method in this case! my ¼ r-0.5*v*v U ¼ Exp(my * Dt + v * Sqr(Dt)) D ¼ Exp(my * Dt - v * Sqr(Dt)) p ¼ 0.5 udd ¼ U/D u_d ¼ U-D Appendix: Some Source Codes 463 ElseIf (mBin ¼ TIAN) Then m ¼ Exp(r * Dt) vv ¼ Exp(v *v*Dt) U ¼ 0.5*m*vv*(1+vv+Sqr(vv * vv +2*vv-3)) D ¼ 0.5*m*vv*(1+vv-Sqr(vv * vv +2*vv-3)) udd ¼ U/D u_d ¼ U-D p ¼ (1 / disc - D) / u_d ElseIf (mBin ¼ LR) Then q ¼ 0 ’ No yield ermqdt ¼ Exp((r - q) * Dt) d2 ¼ BSDTwo(S, X, r, q, T, v) p ¼ PPNormInv(d2, n) pdash ¼ PPNormInv(d2 + v * Sqr(T), n) U ¼ ermqdt * pdash / p D ¼ ermqdt * (1 - pdash) / (1 - p) udd ¼ U/D u_d ¼ U-D End If ’ initialize stock prices at maturity log(a^b) ¼ b*log(a) lSt(0) ¼ S*D^n For i ¼ 1Ton lSt(i) ¼ lSt(i - 1) * udd Next i ’ initialize option prices at maturity n For i ¼ 0Ton lC(i) ¼ Max(0, bC(mExe, lSt(i), X)) Next i idx ¼ find_opt_index(lSt, X, n) ’ step back through the tree For j ¼ n-1To2Step -1 For i ¼ 0Toj lC(i) ¼ disc * (p * lC(i + 1) + (1 - p) * lC(i)) lSt(i) ¼ lSt(i) / D If (mTyp ¼ AMERICAN) Then lC(i) ¼ Max(lC(i), bC(mExe, lSt(i), X)) End If If (BS_Smoothing) Then If (j ¼ n - 1) Then If (i >¼ idx And i <¼ idx + 4) Then 464 Appendix: Some Source Codes lC(i) ¼ GBlackScholes(mExe, lSt(i), X, T / n, r, r, v) End If End If End If Next i Next j ’ save option value, used for calculating hedge parameters mTheta ¼ lC(1) / Dt ’ For calculating Theta. For i ¼ 0To1 lC1(i) ¼ disc * (p * lC(i + 1) + (1 - p) * lC(i)) lSt1(i) ¼ lSt(i) / D If (mTyp ¼ AMERICAN) Then lC1(i) ¼ Max(lC1(i), bC(mExe, lSt1(i), X)) End If Next i ans ¼ disc * (p * lC1(1) + (1 - p) * lC1(0)) If (mTyp ¼ AMERICAN) Then ans ¼ Max(ans, bC(mExe, S, X)) mGamma ¼ ((lC(2) - lC(1)) / (lSt(2) - lSt(1)) - _ (lC(1) - lC(0)) / (lSt(1) - lSt(0))) / (0.5 * (lSt(2) - lSt(0))) mDelta ¼ (lC1(1) - lC1(0)) / (lSt1(1) - lSt1(0)) mTheta ¼ (mTheta - ans / Dt) / 2 If (mBin ¼ TIAN) Then mTheta ¼ mTheta / 2 Binom ¼ ans End Function To find the index closest to the strike for the Black–Scholes smoothing, we use the following function: Function find_opt_index(lSt() As Double, mX As Double, n As Long) Dim idx As Long, i As Long idx ¼ 0 For i ¼ 0Ton-1 If (lSt(i) >¼ mX) Then Exit For idx ¼ idx + 1 Next i find_opt_index ¼ idx - 2 End Function Appendix: Some Source Codes 465 The boundary for call and put, is given by: Function bC(aIsCall As Long, S As Double, X As Double) As Double If aIsCall Then bC ¼ S-X Else bC ¼ X-S End If End Function We also use two functions from the Black–Scholes model: Function BSDTwo(S As Double, X As Double, r As Double, q As Double, _ T As Double, v As Double) As Double BSDTwo ¼ (Log(S/X)+(r-q-0.5*v*v)*T)/(v*Sqr(T)) End Function double BSDTwo(double S, double X, double r, double q, double T, Function BlackScholes(mCall As Long, 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*v/2)*T)/(v*Sqr(T)) d2 ¼ d1 - v * Sqr(T) If (mCall) Then BlackScholes ¼ S*Exp((b - r) * T)*CND(d1) - X*Exp(-r*T)*CND(d2) Else BlackScholes ¼ X*Exp(-r*T)*CND(-d2) - S*Exp((b - r)*T)*CND(-d1) End If End Function In the Leisen–Reimer model we use the Peizer–Pratt inversion formula: Function PPNormInv(z As Double, n As Long) As Double Dim c1 As Double n ¼ 2 * Int(n / 2) + 1 ’ ¼¼ odd(n); c1 ¼ Exp(-((z / (n +1/3+0.1/(n+1))) * _ (z/(n+1/3+0.1/(n+1)))) * (n +1/6)) PPNormInv ¼ 0.5 + Sgn(z) * Sqr((0.25 * (1 - c1))) End Function 466 Appendix: Some Source Codes The function CND to calculate the cumulative normal eistribution is given in VBA below. This function below gives the normal distribution function À with a maximum error of 10 8: do Function CND(X As Double) As Double Dim sign As Long Dim x2, q0, q1, q2 As Double If (X < 0) Then X ¼ -X sign ¼ -1 ElseIf (X > 0) Then sign ¼ 1 Else ’ (x ¼ 0.0) CND ¼ 0.5 Exit Function End If If (X > 20) Then If (sign < 0) Then CND ¼ 0 Else CND ¼ 1 End If Exit Function End If X ¼ X*0.707106781186547 x2 ¼ X*X If (X < 0.46875) Then q1 ¼ 3209.37758913847 + x2*(377.485237685302 + x2* _ (113.86415415105 + x2*(3.16112374387057 + x2* _ 0.185777706184603))) q2 ¼ 2844.23683343917 + x2*(1282.61652607737 + x2* _ (244.024637934444 + x2*(23.6012909523441 + x2))) CND ¼ 0.5*(1 + sign*X*q1/q2) ElseIf (X < 4) Then q1 ¼ X*(8.88314979438838 + X*(0.56418849698867 + X* _ 2.15311535474404E-08)) q1 ¼ X*(881.952221241769 + X*(298.6351381974 + X* _ (66.1191906371416 + q1))) q1 ¼ 1230.339354798 + X*(2051.07837782607 + X*(1712.04761263407 _ + q1)) Appendix: Some Source Codes 467 q2 ¼ X*(117.693950891312 + X * (15.7449261107098 + X)) q2 ¼ X*(3290.79923573346 + X*(1621.38957456669 + X* _ (537.18110186201 + q2))) q2 ¼ 1230.33935480375 + X*(3439.36767414372 + X* _ (4362.61909014325 + q2)) CND ¼ 0.5*(1 + sign*(1 - Exp(-x2)*q1/q2)) Else q0 ¼ 1/x2 q1 ¼ 6.58749161529838E-04 + q0*(1.60837851487423E-02 + q0* _ (0.125781726111229 + q0*(0.360344899949804 + q0* _ (0.305326634961232 + q0*1.63153871373021E-02)))) q2 ¼ 2.33520497626869E-03 + q0*(6.05183413124413E-02 + q0* _ (0.527905102951428 + q0*(1.87295284992346 + q0*´_ (2.56852019228982 + q0)))) CND ¼ 0.5*(1 + sign*(1 - Exp(-x2)/X*(0.564189583547756 - _ q0*q1/q2))) End If End Function Function nd(X As Double) As Double nd ¼ 1/Sqr(2*3.141592654)*Exp(-X*X/2) End Function Below we give an example of how to write a C++ program to solve option prices with the Crank–Nicholson method. The model also calculates the Greeks, delta, gamma and theta. To calculate rho and vega, two grids must be made with two different interest rates and volatilities, respectively, The function bC is the same as for the binomial model. double CrNi(double S, double K, double T, double sig, double r, int N, int Nj, double div, int mIsCall, int mIsAmerican, double D, double &mDelta, double &mGamma, double &mTheta) { double dt ¼ T/N; double dx ¼ sig*sqrt(D*dt); double nu ¼ r - div - 0.5*sig*sig; double edx ¼ exp(dx); double pu ¼ -0.25*dt*((sig/dx)*(sig/dx) + nu/dx); double pm ¼ 1.0 + 0.5*dt*(sig/dx)*(sig/dx) + 0.5*r*dt; 468 Appendix: Some Source Codes double pd ¼ -0.25*dt*((sig/dx)*(sig/dx) - nu/dx); double *St, *C[2], lambda_U, lambda_L; St ¼ new double [2*Nj + 3]; C[0] ¼ new double [2*Nj + 3]; C[1] ¼ new double [2*Nj + 3]; // Initialize the asset prices at maturity.