import%20marimo%0A%0A__generated_with%20%3D%20%220.18.4%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0Awith%20app.setup%3A%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20import%20plotly.graph_objects%20as%20go%0A%20%20%20%20from%20plotly.subplots%20import%20make_subplots%0A%0A%20%20%20%20from%20qsmile%20import%20(%0A%20%20%20%20%20%20%20%20OptionChain%2C%0A%20%20%20%20%20%20%20%20SABRModel%2C%0A%20%20%20%20%20%20%20%20SVIModel%2C%0A%20%20%20%20%20%20%20%20XCoord%2C%0A%20%20%20%20%20%20%20%20YCoord%2C%0A%20%20%20%20%20%20%20%20fit%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_intro()%3A%0A%20%20%20%20%22%22%22Render%20the%20notebook%20introduction.%22%22%22%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20%23%20SABR%20Model%20Demo%0A%0A%20%20%20%20%20%20%20%20This%20notebook%20demonstrates%20the%20**SABR**%20(Stochastic%20Alpha%20Beta%20Rho)%0A%20%20%20%20%20%20%20%20model%20implemented%20in%20qsmile%20using%20the%20Hagan%20et%20al.%20(2002)%20lognormal%0A%20%20%20%20%20%20%20%20implied%20volatility%20approximation.%0A%0A%20%20%20%20%20%20%20%20The%20SABR%20model%20describes%20the%20joint%20dynamics%20of%20a%20forward%20price%20%24F%24%0A%20%20%20%20%20%20%20%20and%20its%20stochastic%20volatility%20%24%5Calpha%24%3A%0A%0A%20%20%20%20%20%20%20%20%24%24%0A%20%20%20%20%20%20%20%20%5Cbegin%7Baligned%7D%0A%20%20%20%20%20%20%20%20dF%20%26%3D%20%5Calpha%5C%2C%20F%5E%5Cbeta%5C%2C%20dW_1%20%5C%5C%0A%20%20%20%20%20%20%20%20d%5Calpha%20%26%3D%20%5Cnu%5C%2C%20%5Calpha%5C%2C%20dW_2%20%5C%5C%0A%20%20%20%20%20%20%20%20%5Clangle%20dW_1%2C%20dW_2%20%5Crangle%20%26%3D%20%5Crho%5C%2C%20dt%0A%20%20%20%20%20%20%20%20%5Cend%7Baligned%7D%0A%20%20%20%20%20%20%20%20%24%24%0A%0A%20%20%20%20%20%20%20%20We%20cover%3A%0A%20%20%20%20%20%20%20%201.%20**Synthetic%20exploration**%20%E2%80%94%20how%20each%20parameter%20shapes%20the%20smile%0A%20%20%20%20%20%20%20%202.%20**Fitting%20to%20real%20SPX%20data**%20%E2%80%94%20%60fit(sd%2C%20SABRModel)%60%20end-to-end%0A%20%20%20%20%20%20%20%203.%20**Comparison%20with%20SVI**%20%E2%80%94%20overlay%20both%20fitted%20smiles%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_explore_intro()%3A%0A%20%20%20%20%22%22%22Introduce%20parameter%20exploration.%22%22%22%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20---%0A%20%20%20%20%20%20%20%20%23%23%201.%20Parameter%20Exploration%0A%0A%20%20%20%20%20%20%20%20Explore%20how%20each%20SABR%20parameter%20affects%20the%20implied%20volatility%20smile.%0A%20%20%20%20%20%20%20%20A%20reference%20model%20is%20shown%20alongside%20a%20varied%20parameter.%0A%0A%20%20%20%20%20%20%20%20%7C%20Parameter%20%7C%20Meaning%20%7C%20Range%20%7C%0A%20%20%20%20%20%20%20%20%7C-----------%7C---------%7C-------%7C%0A%20%20%20%20%20%20%20%20%7C%20%24%5Calpha%24%20%7C%20Initial%20volatility%20level%20%7C%20%24%3E%200%24%20%7C%0A%20%20%20%20%20%20%20%20%7C%20%24%5Cbeta%24%20%7C%20CEV%20exponent%20(backbone)%20%7C%20%24%5B0%2C%201%5D%24%20%7C%0A%20%20%20%20%20%20%20%20%7C%20%24%5Crho%24%20%7C%20Fwd%E2%80%93vol%20correlation%20(skew)%20%7C%20%24(-1%2C%201)%24%20%7C%0A%20%20%20%20%20%20%20%20%7C%20%24%5Cnu%24%20%7C%20Vol-of-vol%20(smile%20curvature)%20%7C%20%24%5Cgeq%200%24%20%7C%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_reference_model()%3A%0A%20%20%20%20%22%22%22Define%20reference%20SABR%20parameters%20and%20log-moneyness%20grid.%22%22%22%0A%20%20%20%20k_grid%20%3D%20np.linspace(-0.3%2C%200.3%2C%20200)%0A%0A%20%20%20%20ref%20%3D%20SABRModel(alpha%3D0.2%2C%20beta%3D0.5%2C%20rho%3D-0.25%2C%20nu%3D0.4%2C%20expiry%3D1.0%2C%20forward%3D100.0)%0A%20%20%20%20ref_iv%20%3D%20ref.evaluate(k_grid)%0A%20%20%20%20return%20k_grid%2C%20ref%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_param_plots(k_grid%2C%20ref)%3A%0A%20%20%20%20%22%22%22Plot%20the%20effect%20of%20varying%20each%20SABR%20parameter.%22%22%22%0A%20%20%20%20param_configs%20%3D%20%5B%0A%20%20%20%20%20%20%20%20(%22alpha%22%2C%20%5B0.10%2C%200.20%2C%200.35%5D%2C%20%22%CE%B1%20%E2%80%94%20volatility%20level%22)%2C%0A%20%20%20%20%20%20%20%20(%22rho%22%2C%20%5B-0.6%2C%20-0.25%2C%200.1%5D%2C%20%22%CF%81%20%E2%80%94%20skew%22)%2C%0A%20%20%20%20%20%20%20%20(%22nu%22%2C%20%5B0.1%2C%200.4%2C%200.8%5D%2C%20%22%CE%BD%20%E2%80%94%20vol-of-vol%20(curvature)%22)%2C%0A%20%20%20%20%20%20%20%20(%22beta%22%2C%20%5B0.0%2C%200.5%2C%201.0%5D%2C%20%22%CE%B2%20%E2%80%94%20CEV%20backbone%22)%2C%0A%20%20%20%20%5D%0A%20%20%20%20colors%20%3D%20%5B%22%232196F3%22%2C%20%22%23E74C3C%22%2C%20%22%232FA4A9%22%5D%0A%0A%20%20%20%20_fig%20%3D%20make_subplots(%0A%20%20%20%20%20%20%20%20rows%3D2%2C%0A%20%20%20%20%20%20%20%20cols%3D2%2C%0A%20%20%20%20%20%20%20%20subplot_titles%3D%5Bc%5B2%5D%20for%20c%20in%20param_configs%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20for%20idx%2C%20(param%2C%20values%2C%20_title)%20in%20enumerate(param_configs)%3A%0A%20%20%20%20%20%20%20%20row%2C%20col%20%3D%20divmod(idx%2C%202)%0A%20%20%20%20%20%20%20%20for%20i%2C%20val%20in%20enumerate(values)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20kwargs%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22alpha%22%3A%20ref.alpha%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22beta%22%3A%20ref.beta%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22rho%22%3A%20ref.rho%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22nu%22%3A%20ref.nu%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22expiry%22%3A%20ref.expiry%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22forward%22%3A%20ref.forward%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20kwargs%5Bparam%5D%20%3D%20val%0A%20%20%20%20%20%20%20%20%20%20%20%20m%20%3D%20SABRModel(**kwargs)%0A%20%20%20%20%20%20%20%20%20%20%20%20iv%20%3D%20m.evaluate(k_grid)%0A%20%20%20%20%20%20%20%20%20%20%20%20_fig.add_trace(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20go.Scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3Dk_grid%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3Dnp.asarray(iv)%20*%20100%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22lines%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20line%3D%7B%22color%22%3A%20colors%5Bi%5D%2C%20%22width%22%3A%202%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3Df%22%7Bparam%7D%3D%7Bval%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20showlegend%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20legendgroup%3Dparam%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20row%3Drow%20%2B%201%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20col%3Dcol%20%2B%201%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20_fig.update_xaxes(title_text%3D%22log-moneyness%20k%22%2C%20row%3Drow%20%2B%201%2C%20col%3Dcol%20%2B%201)%0A%20%20%20%20%20%20%20%20_fig.update_yaxes(title_text%3D%22IV%20(%25)%22%2C%20row%3Drow%20%2B%201%2C%20col%3Dcol%20%2B%201)%0A%0A%20%20%20%20_fig.update_layout(%0A%20%20%20%20%20%20%20%20title%3D%22SABR%20Parameter%20Sensitivity%22%2C%0A%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20height%3D700%2C%0A%20%20%20%20%20%20%20%20legend%3D%7B%22x%22%3A%201.02%2C%20%22y%22%3A%201.0%7D%2C%0A%20%20%20%20)%0A%20%20%20%20mo.ui.plotly(_fig)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_fit_intro()%3A%0A%20%20%20%20%22%22%22Introduce%20the%20fitting%20section.%22%22%22%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20---%0A%20%20%20%20%20%20%20%20%23%23%202.%20Fit%20SABR%20to%20Real%20SPX%20Data%0A%0A%20%20%20%20%20%20%20%20We%20load%20the%20same%20real%20SPX%20option%20chain%20used%20in%20the%20chain%20demo%2C%0A%20%20%20%20%20%20%20%20build%20a%20%60SmileData%60%20container%2C%20and%20calibrate%20SABR%20via%0A%20%20%20%20%20%20%20%20%60fit(sd%2C%20SABRModel)%60.%0A%0A%20%20%20%20%20%20%20%20The%20fitting%20engine%20automatically%3A%0A%20%20%20%20%20%20%20%20-%20transforms%20to%20SABR's%20native%20coordinates%20(log-moneyness%2C%20implied%20vol)%0A%20%20%20%20%20%20%20%20-%20passes%20%60expiry%60%20and%20%60forward%60%20context%20from%20%60SmileData.metadata%60%0A%20%20%20%20%20%20%20%20-%20runs%20least-squares%20optimisation%20with%20Hagan's%20formula%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_load_data()%3A%0A%20%20%20%20%22%22%22Load%20real%20SPX%20option%20chain%20and%20build%20SmileData.%22%22%22%0A%20%20%20%20_root%20%3D%20Path(__file__).resolve().parent.parent.parent.parent%0A%20%20%20%20_pq%20%3D%20sorted(_root.glob(%22parquet%2Fchains%2F*.parquet%22))%5B-1%5D%0A%20%20%20%20df_raw%20%3D%20pd.read_parquet(_pq)%0A%0A%20%20%20%20expiry%20%3D%20float(df_raw%5B%22daysToExpiry%22%5D.iloc%5B0%5D)%20%2F%20365.0%0A%0A%20%20%20%20_cols%20%3D%20%5B%22strike%22%2C%20%22bid%22%2C%20%22ask%22%2C%20%22volume%22%2C%20%22openInterest%22%5D%0A%20%20%20%20calls%20%3D%20df_raw%5Bdf_raw%5B%22optionType%22%5D%20%3D%3D%20%22call%22%5D%5B_cols%5D.set_index(%22strike%22)%0A%20%20%20%20puts%20%3D%20df_raw%5Bdf_raw%5B%22optionType%22%5D%20%3D%3D%20%22put%22%5D%5B_cols%5D.set_index(%22strike%22)%0A%20%20%20%20merged%20%3D%20calls.join(puts%2C%20lsuffix%3D%22_call%22%2C%20rsuffix%3D%22_put%22%2C%20how%3D%22inner%22).sort_index()%0A%0A%20%20%20%20strikes%20%3D%20merged.index.values.astype(np.float64)%0A%20%20%20%20call_bid%20%3D%20merged%5B%22bid_call%22%5D.values.astype(np.float64)%0A%20%20%20%20call_ask%20%3D%20merged%5B%22ask_call%22%5D.values.astype(np.float64)%0A%20%20%20%20put_bid%20%3D%20merged%5B%22bid_put%22%5D.values.astype(np.float64)%0A%20%20%20%20put_ask%20%3D%20merged%5B%22ask_put%22%5D.values.astype(np.float64)%0A%0A%20%20%20%20prices%20%3D%20OptionChain(%0A%20%20%20%20%20%20%20%20strikes%3Dstrikes%2C%0A%20%20%20%20%20%20%20%20call_bid%3Dcall_bid%2C%0A%20%20%20%20%20%20%20%20call_ask%3Dcall_ask%2C%0A%20%20%20%20%20%20%20%20put_bid%3Dput_bid%2C%0A%20%20%20%20%20%20%20%20put_ask%3Dput_ask%2C%0A%20%20%20%20%20%20%20%20expiry%3Dexpiry%2C%0A%20%20%20%20).denoise()%0A%0A%20%20%20%20sd%20%3D%20prices.to_smile_data().transform(XCoord.FixedStrike%2C%20YCoord.Volatility)%0A%20%20%20%20return%20expiry%2C%20sd%0A%0A%0A%40app.cell%0Adef%20cell_sabr_fit(sd)%3A%0A%20%20%20%20%22%22%22Fit%20SABR%20to%20market%20data.%22%22%22%0A%20%20%20%20sabr_result%20%3D%20fit(sd%2C%20SABRModel)%0A%20%20%20%20sabr_p%20%3D%20sabr_result.params%0A%20%20%20%20return%20sabr_p%2C%20sabr_result%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_sabr_params(sabr_p%2C%20sabr_result)%3A%0A%20%20%20%20%22%22%22Display%20fitted%20SABR%20parameters.%22%22%22%0A%20%20%20%20mo.vstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22%23%23%23%20Fitted%20SABR%20Parameters%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22%22%22%0A%20%20%20%20%7C%20Parameter%20%7C%20Value%20%7C%20Description%20%7C%0A%20%20%20%20%7C-----------%7C------%3A%7C-------------%7C%0A%20%20%20%20%7C%20%24%5C%5Calpha%24%20%7C%20%7Bsabr_p.alpha%3A.6f%7D%20%7C%20Initial%20volatility%20%7C%0A%20%20%20%20%7C%20%24%5C%5Cbeta%24%20%7C%20%7Bsabr_p.beta%3A.6f%7D%20%7C%20CEV%20exponent%20%7C%0A%20%20%20%20%7C%20%24%5C%5Crho%24%20%7C%20%7Bsabr_p.rho%3A.6f%7D%20%7C%20Fwd%E2%80%93vol%20correlation%20%7C%0A%20%20%20%20%7C%20%24%5C%5Cnu%24%20%7C%20%7Bsabr_p.nu%3A.6f%7D%20%7C%20Vol-of-vol%20%7C%0A%0A%20%20%20%20**RMSE%3A**%20%7Bsabr_result.rmse%3A.2e%7D%20%26nbsp%3B%26nbsp%3B%20**Converged%3A**%20%7B%22Yes%22%20if%20sabr_result.success%20else%20%22No%22%7D%0A%0A%20%20%20%20*Context%3A*%20expiry%20%3D%20%7Bsabr_p.expiry%3A.4f%7Dy%2C%20forward%20%3D%20%7Bsabr_p.forward%3A.2f%7D%0A%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_sabr_fit_plot(sabr_result%2C%20sd)%3A%0A%20%20%20%20%22%22%22Plot%20market%20vols%20with%20SABR%20fitted%20curve.%22%22%22%0A%20%20%20%20_fwd%20%3D%20sd.metadata.forward%0A%20%20%20%20_strikes_fine%20%3D%20np.linspace(sd.x.min()%20*%200.95%2C%20sd.x.max()%20*%201.05%2C%20300)%0A%20%20%20%20_k_fine%20%3D%20np.log(_strikes_fine%20%2F%20_fwd)%0A%20%20%20%20_iv_sabr%20%3D%20sabr_result.params.evaluate(_k_fine)%0A%0A%20%20%20%20_fig%20%3D%20go.Figure()%0A%20%20%20%20_fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dsd.x%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dsd.y_mid%20*%20100%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20error_y%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22type%22%3A%20%22data%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22symmetric%22%3A%20False%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22array%22%3A%20((sd.y_ask%20-%20sd.y_mid)%20*%20100).tolist()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22arrayminus%22%3A%20((sd.y_mid%20-%20sd.y_bid)%20*%20100).tolist()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3D%7B%22size%22%3A%208%2C%20%22color%22%3A%20%22%23E74C3C%22%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Market%20(bid%2Fask)%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20_fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D_strikes_fine%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dnp.asarray(_iv_sabr)%20*%20100%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22lines%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20line%3D%7B%22color%22%3A%20%22%232196F3%22%2C%20%22width%22%3A%202.5%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22SABR%20Fit%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20_fig.update_layout(%0A%20%20%20%20%20%20%20%20title%3D%22Market%20Implied%20Vols%20vs%20SABR%20Fit%22%2C%0A%20%20%20%20%20%20%20%20xaxis_title%3D%22Strike%22%2C%0A%20%20%20%20%20%20%20%20yaxis_title%3D%22Implied%20Volatility%20(%25)%22%2C%0A%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20height%3D450%2C%0A%20%20%20%20%20%20%20%20legend%3D%7B%22x%22%3A%200.02%2C%20%22y%22%3A%200.98%7D%2C%0A%20%20%20%20)%0A%20%20%20%20mo.ui.plotly(_fig)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_compare_intro()%3A%0A%20%20%20%20%22%22%22Introduce%20the%20comparison%20section.%22%22%22%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20---%0A%20%20%20%20%20%20%20%20%23%23%203.%20SVI%20vs%20SABR%20Comparison%0A%0A%20%20%20%20%20%20%20%20Both%20models%20are%20fitted%20to%20the%20same%20market%20data.%20We%20overlay%20the%0A%20%20%20%20%20%20%20%20fitted%20curves%20and%20compare%20fit%20quality.%0A%0A%20%20%20%20%20%20%20%20%7C%20Model%20%7C%20Native%20Y%20%7C%20Parameters%20%7C%0A%20%20%20%20%20%20%20%20%7C-------%7C----------%7C------------%7C%0A%20%20%20%20%20%20%20%20%7C%20SVI%20%7C%20Total%20Variance%20%24w%20%3D%20%5Csigma%5E2%20T%24%20%7C%20%24a%2C%20b%2C%20%5Crho%2C%20m%2C%20%5Csigma%24%20%7C%0A%20%20%20%20%20%20%20%20%7C%20SABR%20%7C%20Implied%20Volatility%20%24%5Csigma%24%20%7C%20%24%5Calpha%2C%20%5Cbeta%2C%20%5Crho%2C%20%5Cnu%24%20%7C%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_svi_fit(sd)%3A%0A%20%20%20%20%22%22%22Fit%20SVI%20to%20the%20same%20market%20data.%22%22%22%0A%20%20%20%20svi_result%20%3D%20fit(sd%2C%20SVIModel)%0A%20%20%20%20svi_p%20%3D%20svi_result.params%0A%20%20%20%20return%20(svi_result%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_comparison_table(sabr_result%2C%20svi_result)%3A%0A%20%20%20%20%22%22%22Compare%20fit%20quality%20metrics.%22%22%22%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20f%22%22%22%0A%20%20%20%20%23%23%23%20Fit%20Quality%20Comparison%0A%0A%20%20%20%20%7C%20Metric%20%7C%20SVI%20%7C%20SABR%20%7C%0A%20%20%20%20%7C--------%7C----%3A%7C-----%3A%7C%0A%20%20%20%20%7C%20RMSE%20%7C%20%7Bsvi_result.rmse%3A.2e%7D%20%7C%20%7Bsabr_result.rmse%3A.2e%7D%20%7C%0A%20%20%20%20%7C%20Converged%20%7C%20%7B%22Yes%22%20if%20svi_result.success%20else%20%22No%22%7D%20%7C%20%7B%22Yes%22%20if%20sabr_result.success%20else%20%22No%22%7D%20%7C%0A%20%20%20%20%7C%20%23%20Parameters%20%7C%20%7Blen(SVIModel.param_names)%7D%20%7C%20%7Blen(SABRModel.param_names)%7D%20%7C%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_comparison_plot(expiry%2C%20sabr_result%2C%20sd%2C%20svi_result)%3A%0A%20%20%20%20%22%22%22Overlay%20SVI%20and%20SABR%20fits%20on%20market%20data.%22%22%22%0A%20%20%20%20_fwd%20%3D%20sd.metadata.forward%0A%20%20%20%20_strikes_fine%20%3D%20np.linspace(sd.x.min()%20*%200.95%2C%20sd.x.max()%20*%201.05%2C%20300)%0A%20%20%20%20_k_fine%20%3D%20np.log(_strikes_fine%20%2F%20_fwd)%0A%0A%20%20%20%20_iv_sabr%20%3D%20np.asarray(sabr_result.params.evaluate(_k_fine))%0A%20%20%20%20_iv_svi%20%3D%20np.asarray(svi_result.params.implied_vol(_k_fine%2C%20expiry))%0A%0A%20%20%20%20_fig%20%3D%20go.Figure()%0A%20%20%20%20%23%20Market%20data%0A%20%20%20%20_fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dsd.x%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dsd.y_mid%20*%20100%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20error_y%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22type%22%3A%20%22data%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22symmetric%22%3A%20False%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22array%22%3A%20((sd.y_ask%20-%20sd.y_mid)%20*%20100).tolist()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22arrayminus%22%3A%20((sd.y_mid%20-%20sd.y_bid)%20*%20100).tolist()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3D%7B%22size%22%3A%208%2C%20%22color%22%3A%20%22%23999999%22%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Market%20(bid%2Fask)%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20%23%20SVI%0A%20%20%20%20_fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D_strikes_fine%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D_iv_svi%20*%20100%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22lines%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20line%3D%7B%22color%22%3A%20%22%232FA4A9%22%2C%20%22width%22%3A%202.5%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22SVI%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20%23%20SABR%0A%20%20%20%20_fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D_strikes_fine%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D_iv_sabr%20*%20100%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22lines%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20line%3D%7B%22color%22%3A%20%22%232196F3%22%2C%20%22width%22%3A%202.5%2C%20%22dash%22%3A%20%22dash%22%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22SABR%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20_fig.update_layout(%0A%20%20%20%20%20%20%20%20title%3D%22SVI%20vs%20SABR%20%E2%80%94%20Implied%20Volatility%20Fit%22%2C%0A%20%20%20%20%20%20%20%20xaxis_title%3D%22Strike%22%2C%0A%20%20%20%20%20%20%20%20yaxis_title%3D%22Implied%20Volatility%20(%25)%22%2C%0A%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20height%3D480%2C%0A%20%20%20%20%20%20%20%20legend%3D%7B%22x%22%3A%200.02%2C%20%22y%22%3A%200.98%7D%2C%0A%20%20%20%20)%0A%20%20%20%20mo.ui.plotly(_fig)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_residuals_plot(sabr_result%2C%20sd%2C%20svi_result)%3A%0A%20%20%20%20%22%22%22Plot%20fit%20residuals%20for%20both%20models.%22%22%22%0A%20%20%20%20_fig%20%3D%20go.Figure()%0A%20%20%20%20_fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Bar(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dsd.x%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dsvi_result.residuals%20*%201e4%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22SVI%20residuals%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3D%7B%22color%22%3A%20%22%232FA4A9%22%2C%20%22opacity%22%3A%200.7%7D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20_fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Bar(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dsd.x%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dsabr_result.residuals%20*%201e4%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22SABR%20residuals%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3D%7B%22color%22%3A%20%22%232196F3%22%2C%20%22opacity%22%3A%200.7%7D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20_fig.update_layout(%0A%20%20%20%20%20%20%20%20title%3D%22Fit%20Residuals%20(native%20coordinates)%22%2C%0A%20%20%20%20%20%20%20%20xaxis_title%3D%22Strike%22%2C%0A%20%20%20%20%20%20%20%20yaxis_title%3D%22Residual%20(%C3%9710%E2%81%B4)%22%2C%0A%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20height%3D380%2C%0A%20%20%20%20%20%20%20%20barmode%3D%22group%22%2C%0A%20%20%20%20%20%20%20%20legend%3D%7B%22x%22%3A%200.02%2C%20%22y%22%3A%200.98%7D%2C%0A%20%20%20%20)%0A%20%20%20%20mo.ui.plotly(_fig)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20cell_summary()%3A%0A%20%20%20%20%22%22%22Render%20the%20conclusion.%22%22%22%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20---%0A%20%20%20%20%20%20%20%20%23%23%20Summary%0A%0A%20%20%20%20%20%20%20%20%7C%20Step%20%7C%20Code%20%7C%0A%20%20%20%20%20%20%20%20%7C------%7C------%7C%0A%20%20%20%20%20%20%20%20%7C%20Construct%20SABR%20model%20%7C%20%60SABRModel(alpha%2C%20beta%2C%20rho%2C%20nu%2C%20expiry%2C%20forward)%60%20%7C%0A%20%20%20%20%20%20%20%20%7C%20Evaluate%20smile%20%7C%20%60model.evaluate(k)%60%20%E2%80%94%20Hagan%20(2002)%20implied%20vol%20%7C%0A%20%20%20%20%20%20%20%20%7C%20Fit%20to%20market%20data%20%7C%20%60fit(sd%2C%20SABRModel)%60%20%E2%80%94%20automatic%20coordinate%20transform%20%7C%0A%20%20%20%20%20%20%20%20%7C%20Compare%20models%20%7C%20Both%20%60SVIModel%60%20and%20%60SABRModel%60%20work%20with%20%60fit()%60%20%7C%0A%0A%20%20%20%20%20%20%20%20The%20**SABR%20model**%20is%20a%20natural%20complement%20to%20SVI%3A%0A%20%20%20%20%20%20%20%20-%20SVI%20operates%20in%20**total-variance**%20space%20%E2%80%94%20excellent%20for%20arbitrage-free%20interpolation%0A%20%20%20%20%20%20%20%20-%20SABR%20operates%20in%20**implied-vol**%20space%20with%20stochastic-vol%20dynamics%20%E2%80%94%20links%20to%20hedging%20and%20risk%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
d8cd62a3a9edbaa11c86c18e27382e02