%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.11%22%0A%23%20dependencies%20%3D%20%5B%0A%23%20%20%20%20%20%22marimo%3D%3D0.20.4%22%2C%0A%23%20%20%20%20%20%22jquantstats%22%2C%0A%23%20%20%20%20%20%22numpy%3E%3D2.0.0%22%2C%0A%23%20%20%20%20%20%22polars%3E%3D1.0.0%22%2C%0A%23%20%20%20%20%20%22plotly%3E%3D6.0.0%22%2C%0A%23%20%20%20%20%20%22jinja2%3E%3D3.1.0%22%2C%0A%23%20%5D%0A%23%20%5Btool.uv.sources%5D%0A%23%20jquantstats%20%3D%20%7B%20path%20%3D%20%22..%2F..%2F..%22%2C%20editable%20%3D%20true%20%7D%0A%23%20%2F%2F%2F%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.20.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%20plotly.graph_objects%20as%20go%0A%20%20%20%20import%20polars%20as%20pl%0A%0A%20%20%20%20from%20jquantstats%20import%20Data%0A%0A%20%20%20%20NOTEBOOK_DIR%20%3D%20Path(__file__).parent%0A%0A%0A%40app.cell%0Adef%20cell_intro()%3A%0A%20%20%20%20%22%22%22Render%20the%20Monte%20Carlo%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%20%F0%9F%8E%B2%20jquantstats%20%E2%80%94%20Monte%20Carlo%20Simulation%0A%0A%20%20%20%20%20%20%20%20This%20notebook%20demonstrates%20the%20**block-bootstrap%20Monte%20Carlo**%20engine%20built%20into%20%60jquantstats%60.%0A%0A%20%20%20%20%20%20%20%20Block%20bootstrap%20preserves%20the%20autocorrelation%20structure%20of%20returns%20by%20resampling%0A%20%20%20%20%20%20%20%20contiguous%20blocks%20rather%20than%20individual%20observations%20%E2%80%94%20giving%20more%20realistic%0A%20%20%20%20%20%20%20%20simulated%20paths%20than%20plain%20i.i.d.%20resampling.%0A%0A%20%20%20%20%20%20%20%20%7C%20Section%20%7C%20What%20you%20get%20%7C%0A%20%20%20%20%20%20%20%20%7C---------%7C--------------%7C%0A%20%20%20%20%20%20%20%20%7C%20**Fan%20chart**%20%7C%20%60data.plots.montecarlo()%60%20%E2%80%94%20simulated%20paths%20vs%20observed%20%7C%0A%20%20%20%20%20%20%20%20%7C%20**Metric%20distributions**%20%7C%20%60data.plots.montecarlo_distribution()%60%20for%20Sharpe%2C%20drawdown%2C%20CAGR%20%7C%0A%20%20%20%20%20%20%20%20%7C%20**Raw%20simulation%20data**%20%7C%20%60data.stats.montecarlo_*()%60%20%E2%80%94%20percentile%20tables%20%7C%0A%0A%20%20%20%20%20%20%20%20**Data%3A**%20real%20AAPL%20%2B%20META%20daily%20returns%20(%E2%89%88%2011%20k%20rows)%20with%20SPY%20as%20benchmark.%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%20portfolio%20returns%20and%20SPY%20benchmark%20from%20CSV.%22%22%22%0A%20%20%20%20data_dir%20%3D%20NOTEBOOK_DIR%20%2F%20%22data%22%0A%0A%20%20%20%20returns_df%20%3D%20pl.read_csv(data_dir%20%2F%20%22portfolio.csv%22%2C%20try_parse_dates%3DTrue).with_columns(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22AAPL%22).cast(pl.Float64%2C%20strict%3DFalse)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22META%22).cast(pl.Float64%2C%20strict%3DFalse)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22Date%22).cast(pl.Date%2C%20strict%3DFalse)%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20benchmark_df%20%3D%20pl.read_csv(data_dir%20%2F%20%22benchmark.csv%22%2C%20try_parse_dates%3DTrue).select(%5B%22Date%22%2C%20%22SPY%20--%20Benchmark%22%5D)%0A%20%20%20%20data%20%3D%20Data.from_returns(returns%3Dreturns_df%2C%20benchmark%3Dbenchmark_df)%0A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20f%22%22%22%0A%20%20%20%20%20%20%20%20**Data%20loaded**%20%E2%9C%85%0A%0A%20%20%20%20%20%20%20%20-%20Assets%3A%20%60%7Bdata.assets%7D%60%0A%20%20%20%20%20%20%20%20-%20Rows%3A%20%60%7Breturns_df.height%3A%2C%7D%60%0A%20%20%20%20%20%20%20%20-%20Date%20range%3A%20%60%7Breturns_df%5B%22Date%22%5D.min()%7D%60%20%E2%86%92%20%60%7Breturns_df%5B%22Date%22%5D.max()%7D%60%0A%0A%20%20%20%20%20%20%20%20Each%20Monte%20Carlo%20run%20samples%20**block-bootstrap%20paths**%20of%20252%20trading-day%0A%20%20%20%20%20%20%20%20horizon%20from%20the%20full%20return%20history.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%20(data%2C)%0A%0A%0A%40app.cell%0Adef%20cell_fan_header()%3A%0A%20%20%20%20%22%22%22Fan%20chart%20section%20header.%22%22%22%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20---%0A%20%20%20%20%20%20%20%20%23%23%201%20%C2%B7%20Simulated%20paths%20vs%20observed%20%E2%80%94%20%60data.plots.montecarlo()%60%0A%0A%20%20%20%20%20%20%20%20Each%20faint%20line%20is%20one%20block-bootstrap%20simulation%3B%20the%20bold%20line%20is%20the%0A%20%20%20%20%20%20%20%20**observed%20trailing-year**%20cumulative%20return.%20%20The%20spread%20of%20the%20fan%0A%20%20%20%20%20%20%20%20represents%20the%20range%20of%20outcomes%20consistent%20with%20historical%20return%20dynamics.%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_fan_chart(data)%3A%0A%20%20%20%20%22%22%22Generate%20Monte%20Carlo%20fan%20chart%20(100%20paths%2C%20252-day%20horizon).%22%22%22%0A%20%20%20%20fig_fan%20%3D%20data.plots.montecarlo(%0A%20%20%20%20%20%20%20%20n%3D100%2C%0A%20%20%20%20%20%20%20%20period%3D252%2C%0A%20%20%20%20%20%20%20%20title%3D%22Monte%20Carlo%20Fan%20Chart%20%E2%80%94%20AAPL%20%26%20META%20(100%20paths%2C%201-year%20horizon)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(fig_fan%2C)%0A%0A%0A%40app.cell%0Adef%20cell_fan_chart_show(fig_fan)%3A%0A%20%20%20%20%22%22%22Display%20fan%20chart.%22%22%22%0A%20%20%20%20fig_fan%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_dist_header()%3A%0A%20%20%20%20%22%22%22Metric%20distributions%20section%20header.%22%22%22%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20---%0A%20%20%20%20%20%20%20%20%23%23%202%20%C2%B7%20Metric%20distributions%20%E2%80%94%20%60data.plots.montecarlo_distribution()%60%0A%0A%20%20%20%20%20%20%20%20Running%201%20000%20simulations%20and%20plotting%20the%20distribution%20of%20three%20key%20metrics%0A%20%20%20%20%20%20%20%20reveals%20the%20**uncertainty%20band**%20around%20each%20statistic.%20%20The%20vertical%20line%0A%20%20%20%20%20%20%20%20marks%20the%20historically%20observed%20value.%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_sharpe_dist(data)%3A%0A%20%20%20%20%22%22%22Monte%20Carlo%20Sharpe%20ratio%20distribution.%22%22%22%0A%20%20%20%20mo.md(%22%23%23%23%202a%20%C2%B7%20Sharpe%20ratio%20distribution%22)%0A%20%20%20%20fig_sharpe_dist%20%3D%20data.plots.montecarlo_distribution(%0A%20%20%20%20%20%20%20%20n%3D1000%2C%0A%20%20%20%20%20%20%20%20period%3D252%2C%0A%20%20%20%20%20%20%20%20metric%3D%22sharpe%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Simulated%20Sharpe%20Ratio%20Distribution%20(1%20000%20paths%2C%201-year)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(fig_sharpe_dist%2C)%0A%0A%0A%40app.cell%0Adef%20cell_sharpe_dist_show(fig_sharpe_dist)%3A%0A%20%20%20%20%22%22%22Display%20Sharpe%20distribution.%22%22%22%0A%20%20%20%20fig_sharpe_dist%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_dd_dist(data)%3A%0A%20%20%20%20%22%22%22Monte%20Carlo%20drawdown%20distribution.%22%22%22%0A%20%20%20%20mo.md(%22%23%23%23%202b%20%C2%B7%20Max%20drawdown%20distribution%22)%0A%20%20%20%20fig_dd_dist%20%3D%20data.plots.montecarlo_distribution(%0A%20%20%20%20%20%20%20%20n%3D1000%2C%0A%20%20%20%20%20%20%20%20period%3D252%2C%0A%20%20%20%20%20%20%20%20metric%3D%22drawdown%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Simulated%20Max%20Drawdown%20Distribution%20(1%20000%20paths%2C%201-year)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(fig_dd_dist%2C)%0A%0A%0A%40app.cell%0Adef%20cell_dd_dist_show(fig_dd_dist)%3A%0A%20%20%20%20%22%22%22Display%20drawdown%20distribution.%22%22%22%0A%20%20%20%20fig_dd_dist%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_cagr_dist(data)%3A%0A%20%20%20%20%22%22%22Monte%20Carlo%20CAGR%20distribution.%22%22%22%0A%20%20%20%20mo.md(%22%23%23%23%202c%20%C2%B7%20CAGR%20distribution%22)%0A%20%20%20%20fig_cagr_dist%20%3D%20data.plots.montecarlo_distribution(%0A%20%20%20%20%20%20%20%20n%3D1000%2C%0A%20%20%20%20%20%20%20%20period%3D252%2C%0A%20%20%20%20%20%20%20%20metric%3D%22cagr%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Simulated%20CAGR%20Distribution%20(1%20000%20paths%2C%201-year)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(fig_cagr_dist%2C)%0A%0A%0A%40app.cell%0Adef%20cell_cagr_dist_show(fig_cagr_dist)%3A%0A%20%20%20%20%22%22%22Display%20CAGR%20distribution.%22%22%22%0A%20%20%20%20fig_cagr_dist%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_raw_header()%3A%0A%20%20%20%20%22%22%22Raw%20simulation%20data%20section%20header.%22%22%22%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20---%0A%20%20%20%20%20%20%20%20%23%23%203%20%C2%B7%20Percentile%20tables%20from%20raw%20simulation%20data%0A%0A%20%20%20%20%20%20%20%20%60data.stats.montecarlo_*()%60%20returns%20a%20%60(n_simulations%20%C3%97%20n_assets)%60%20DataFrame.%0A%20%20%20%20%20%20%20%20We%20summarise%20it%20into%20percentile%20tables%20to%20answer%20questions%20like%3A%0A%20%20%20%20%20%20%20%20*%22What%20Sharpe%20can%20we%20expect%20in%20the%20worst%205%25%20of%20years%3F%22*%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_mc_sharpe(data)%3A%0A%20%20%20%20%22%22%22Run%20raw%20Monte%20Carlo%20Sharpe%20simulations.%22%22%22%0A%20%20%20%20mc_sharpe%20%3D%20data.stats.montecarlo_sharpe(n%3D2000%2C%20period%3D252)%0A%20%20%20%20return%20(mc_sharpe%2C)%0A%0A%0A%40app.cell%0Adef%20cell_mc_dd(data)%3A%0A%20%20%20%20%22%22%22Run%20raw%20Monte%20Carlo%20drawdown%20simulations.%22%22%22%0A%20%20%20%20mc_dd%20%3D%20data.stats.montecarlo_drawdown(n%3D2000%2C%20period%3D252)%0A%20%20%20%20return%20(mc_dd%2C)%0A%0A%0A%40app.cell%0Adef%20cell_mc_cagr(data)%3A%0A%20%20%20%20%22%22%22Run%20raw%20Monte%20Carlo%20CAGR%20simulations.%22%22%22%0A%20%20%20%20mc_cagr%20%3D%20data.stats.montecarlo_cagr(n%3D2000%2C%20period%3D252)%0A%20%20%20%20return%20(mc_cagr%2C)%0A%0A%0A%40app.cell%0Adef%20cell_percentile_table(data%2C%20mc_cagr%2C%20mc_dd%2C%20mc_sharpe)%3A%0A%20%20%20%20%22%22%22Build%20and%20display%20percentile%20summary%20table.%22%22%22%0A%20%20%20%20quantiles%20%3D%20%5B0.05%2C%200.25%2C%200.50%2C%200.75%2C%200.95%5D%0A%20%20%20%20rows%20%3D%20%5B%5D%0A%20%20%20%20for%20_asset%20in%20data.assets%3A%0A%20%20%20%20%20%20%20%20sharpe_q%20%3D%20mc_sharpe%5B_asset%5D.quantile(quantiles%2C%20interpolation%3D%22linear%22)%0A%20%20%20%20%20%20%20%20dd_q%20%3D%20mc_dd%5B_asset%5D.quantile(quantiles%2C%20interpolation%3D%22linear%22)%0A%20%20%20%20%20%20%20%20cagr_q%20%3D%20mc_cagr%5B_asset%5D.quantile(quantiles%2C%20interpolation%3D%22linear%22)%0A%20%20%20%20%20%20%20%20for%20i%2C%20q%20in%20enumerate(quantiles)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20rows.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Asset%22%3A%20_asset%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Percentile%22%3A%20f%22P%7Bint(q%20*%20100)%3A02d%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Sharpe%22%3A%20round(float(sharpe_q%5Bi%5D)%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Max%20Drawdown%20(%25)%22%3A%20round(float(dd_q%5Bi%5D)%20*%20100%2C%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22CAGR%20(%25)%22%3A%20round(float(cagr_q%5Bi%5D)%20*%20100%2C%202)%2C%0A%20%20%20%20%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%20)%0A%0A%20%20%20%20summary_df%20%3D%20pl.DataFrame(rows)%0A%20%20%20%20mo.md(%22%23%23%23%20Percentile%20summary%20across%202%20000%20simulations%20(1-year%20horizon)%22)%0A%20%20%20%20mo.plain_text(str(summary_df))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_horizon_header()%3A%0A%20%20%20%20%22%22%22Horizon%20sensitivity%20section%20header.%22%22%22%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20---%0A%20%20%20%20%20%20%20%20%23%23%204%20%C2%B7%20Horizon%20sensitivity%20%E2%80%94%20how%20uncertainty%20changes%20with%20time%0A%0A%20%20%20%20%20%20%20%20Shorter%20horizons%20mean%20more%20variance%20in%20outcomes.%20%20We%20run%20the%20same%20500-path%0A%20%20%20%20%20%20%20%20simulation%20across%20three%20horizons%20(63%2C%20126%2C%20252%20days)%20and%20compare%20the%0A%20%20%20%20%20%20%20%20interquartile%20range%20of%20the%20Sharpe%20distribution%20for%20each%20asset.%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_horizon_chart(data)%3A%0A%20%20%20%20%22%22%22Build%20horizon-sensitivity%20chart%20for%20Sharpe%20IQR.%22%22%22%0A%20%20%20%20_horizons%20%3D%20%7B%2263-day%20(Qtr)%22%3A%2063%2C%20%22126-day%20(6mo)%22%3A%20126%2C%20%22252-day%20(1yr)%22%3A%20252%7D%0A%20%20%20%20fig%20%3D%20go.Figure()%0A%0A%20%20%20%20for%20_label%2C%20_period%20in%20_horizons.items()%3A%0A%20%20%20%20%20%20%20%20_mc%20%3D%20data.stats.montecarlo_sharpe(n%3D500%2C%20period%3D_period)%0A%20%20%20%20%20%20%20%20for%20_asset%20in%20data.assets%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_s%20%3D%20_mc%5B_asset%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20fig.add_trace(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20go.Box(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3D_s.to_list()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3Df%22%7B_asset%7D%20%2F%20%7B_label%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20boxmean%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20fig.update_layout(%0A%20%20%20%20%20%20%20%20title%3D%22Sharpe%20Ratio%20Distribution%20by%20Horizon%20(500%20paths%20each)%22%2C%0A%20%20%20%20%20%20%20%20yaxis_title%3D%22Simulated%20Annualised%20Sharpe%22%2C%0A%20%20%20%20%20%20%20%20xaxis_title%3D%22Asset%20%2F%20Horizon%22%2C%0A%20%20%20%20%20%20%20%20height%3D480%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(fig%2C)%0A%0A%0A%40app.cell%0Adef%20cell_horizon_chart_show(fig)%3A%0A%20%20%20%20%22%22%22Display%20horizon%20sensitivity%20chart.%22%22%22%0A%20%20%20%20fig%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
76f01d8a5b808f18e800cd640ae3e0bd