|
6 | 6 |
|
7 | 7 | class GarchUncorrBaroneAdesi2004(sv.SvABC):
|
8 | 8 | """
|
9 |
| - The implementation of Barone-Adesi et al (2004)'s approximation pricing formula for European |
10 |
| - options under uncorrelated (rho=0) GARCH diffusion model. |
| 9 | + Barone-Adesi et al (2004)'s approximation pricing formula for European options under uncorrelated (rho=0) GARCH diffusion model. |
| 10 | + Up to 2nd order is implemented. |
11 | 11 |
|
12 | 12 | References:
|
13 | 13 | - Barone-Adesi G, Rasmussen H, Ravanelli C (2005) An option pricing formula for the GARCH diffusion model. Computational Statistics & Data Analysis 49:287–310. https://doi.org/10.1016/j.csda.2004.05.014
|
14 | 14 |
|
15 |
| - This method is only used to compare with the method GarchCondMC. |
| 15 | + See Also: OusvUncorrBallRoma1994, HestonUncorrBallRoma1994 |
16 | 16 | """
|
| 17 | + |
17 | 18 | model_type = "GarchDiff"
|
| 19 | + order = 2 |
18 | 20 |
|
19 |
| - def price(self, strike, spot, texp, cp=1): |
| 21 | + def avgvar_mv(self, var0, texp): |
| 22 | + """ |
| 23 | + Mean and variance of the average variance given V(0) = var0. |
| 24 | + Eqs. (12)-(13) in Barone-Adesi et al. (2005) |
20 | 25 |
|
21 |
| - if not np.isclose(self.rho, 0.0): |
22 |
| - print(f"Pricing ignores rho = {self.rho}.") |
| 26 | + Args: |
| 27 | + var0: initial variance |
| 28 | + texp: time step |
23 | 29 |
|
24 |
| - var0, mr, vov, theta = self.sigma, self.mr, self.vov, self.theta |
| 30 | + Returns: |
| 31 | + mean, variance |
| 32 | + """ |
| 33 | + |
| 34 | + mr, vov, theta = self.mr, self.vov, self.theta |
25 | 35 |
|
26 | 36 | mr2 = mr * mr
|
27 | 37 | vov2 = vov * vov
|
28 | 38 | theta2 = theta*theta
|
29 |
| - decay = np.exp(-mr * texp) |
| 39 | + mr_t = self.mr * texp |
| 40 | + e_mr = np.exp(-mr_t) |
30 | 41 |
|
31 | 42 | # Eq (12) of Barone-Adesi et al. (2005)
|
32 |
| - M1 = theta + (var0 - theta) * (1 - decay) / (mr * texp) |
| 43 | + M1 = theta + (var0 - theta) * (1 - e_mr) / mr_t |
33 | 44 |
|
34 | 45 | term1 = vov2 - mr
|
35 | 46 | term2 = vov2 - 2*mr
|
36 | 47 |
|
37 | 48 | # Eq (13)
|
38 |
| - M2c_1 = - (decay * (var0 - theta))**2 |
| 49 | + M2c_1 = -(e_mr * (var0 - theta))**2 |
39 | 50 | M2c_2 = 2*np.exp(term2 * texp) * (2*mr * theta * (mr * theta + term2 * var0) + term1 * term2 * var0**2)
|
40 |
| - M2c_3 = -vov2 * (theta2 * (4*mr * (3 - texp * mr) + (2*texp * mr - 5) * vov2) + term2 * var0 * (2*theta + var0)) |
| 51 | + M2c_3 = -vov2 * (theta2 * (4*mr * (3 - mr_t) + (2*mr_t - 5) * vov2) + term2 * var0 * (2*theta + var0)) |
41 | 52 |
|
42 |
| - M2c_4 = 2*decay * vov2 |
43 |
| - M2c_4 *= 2*theta2 * (texp * mr2 - (1 + texp * mr) * vov2) \ |
| 53 | + M2c_4 = 2*e_mr * vov2 |
| 54 | + M2c_4 *= 2*theta2 * (mr_t * mr - (1 + mr_t) * vov2) \ |
44 | 55 | + var0 * (2*mr * theta * (1 + texp * term1) + term1 * var0)
|
45 | 56 |
|
46 | 57 | M2c = M2c_1 / mr2 + M2c_2 / (term1 * term2)**2 + M2c_3 / mr2 / term2**2 + M2c_4 / mr2 / term1**2
|
47 | 58 | M2c /= texp**2
|
48 |
| - # M3c=None |
49 |
| - # M4c=None |
50 | 59 |
|
51 |
| - # Eq. (11) |
52 |
| - logk = np.log(spot / strike) |
53 |
| - sigma_std = np.sqrt(self.sigma * texp) |
| 60 | + return M1, M2c |
54 | 61 |
|
55 |
| - m = logk + (self.intr - self.divr) * texp |
56 |
| - d1 = logk / sigma_std + sigma_std / 2 |
| 62 | + def price(self, strike, spot, texp, cp=1): |
57 | 63 |
|
58 |
| - m_bs = bsm.Bsm(np.sqrt(M1), intr=self.intr, divr=self.divr) |
59 |
| - c_bs = m_bs.price(strike, spot, texp, cp) |
| 64 | + if not np.isclose(self.rho, 0.0): |
| 65 | + print(f"Pricing ignores rho = {self.rho}.") |
60 | 66 |
|
61 |
| - c_bs_p1 = np.exp(-self.divr * texp) * strike * np.sqrt(texp / 4 / M1) * spst.norm.pdf(d1) |
62 |
| - c_bs_p2 = c_bs_p1 * texp / 2 * ((m / M1 / texp)**2 - 1 / M1 / texp - 1 / 4) |
| 67 | + avgvar, var = self.avgvar_mv(self.sigma, texp) |
63 | 68 |
|
64 |
| - # C_bs_p3=C_bs_p1*(m**4/(4*(M1*texp)**4)-m**2*(12+M1*texp)/(8*(M1*texp)**3)+(48+8*M1*texp+(M1*texp)**2)/(64*(M1*texp)**2))*texp**2 |
65 |
| - # C_bs_p4=C_bs_p1*(m**6/(8*(M1*texp)**6)-3*m**4*(20+M1*texp)/(32*(M1*texp)**5)+3*m**2*(240+24*M1*texp+(M1*texp)**2)/(128*(M1*texp)**4)-(960+144*M1*texp+12*(M1*texp)**2+(M1*texp)**3)/(512*(M1*texp)**3))*texp**3 |
| 69 | + m_bs = bsm.Bsm(np.sqrt(avgvar), intr=self.intr, divr=self.divr) |
| 70 | + price = m_bs.price(strike, spot, texp, cp) |
66 | 71 |
|
67 |
| - c_ga_2 = c_bs + (M2c / 2) * c_bs_p2 |
68 |
| - # C_ga_3=C_ga_2+(M3c/6)*C_bs_p3 |
69 |
| - # C_ga_4=C_ga_3+(M4c/24)*C_bs_p4 |
| 72 | + if self.order == 2: |
| 73 | + price += 0.5 * var * m_bs.d2_var(strike, spot, texp, cp) |
| 74 | + elif self.order > 2: |
| 75 | + raise ValueError(f"Not implemented for approx order: {self.order}") |
70 | 76 |
|
71 |
| - return c_ga_2 |
| 77 | + return price |
72 | 78 |
|
73 | 79 |
|
74 | 80 | class GarchMcTimeStep(sv.SvABC, sv.CondMcBsmABC):
|
|
0 commit comments