One smile per expiry, and they must agree
Work with total variance w=σ²T against log-moneyness k=ln(K/F). The SVI smile is w(k)=a+b(ρ(k-m)+√((k-m)²+s²)) with five parameters: a lifts the level, b sets the angle of the wings, -1<ρ<1 tilts the smile (negative for equities), m moves the minimum and s rounds the bottom. Fitting it to quotes is a least-squares problem, but a delicate one: the parameters partly compensate each other and a bad start gets stuck. least_squares(residuals, x0, bounds=(lower, upper)) handles the bounds, which keep b>0, |ρ|<1 and s>0, and a robust answer comes from several starting points, keeping the one with the lowest cost.
A surface is one smile per expiry, and the smiles must agree across time. If total variance at some strike falls as the maturity grows, a calendar spread has a negative price, which is an arbitrage. The check is cheap: for consecutive expiries, evaluate both fitted smiles on a grid of k and count the points where w_T₂<w_T₁ (with a tiny tolerance). Remember to sort the expiries first, since a dictionary does not promise an order. The implied volatility of a fit is σ(k)=√(w(k)/T). In the lab, four expiries are fitted to quotes with 0.2% of noise: the rmse is of the size of that noise, the at-the-money volatility is recovered to within 1%, and the surface has no violation; swapping the parameters of two expiries gives 121 violations, one on every grid point.
- Bounds and several starts: SVI parameters trade off, so fit from three starting points and keep the lowest cost.
- Total variance, not volatility: compare maturities with w=σ²T, which must not fall as T grows.
- Sort the expiries before comparing neighbours; a dictionary has no promised order.
Lab · what's graded
- The SVI smile10 pts
- Fitting one smile25 pts
- Calibrating the surface20 pts
- Implied volatility10 pts
- Calendar arbitrage20 pts
- The surface study15 pts