%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%20risk%20metrics%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%E2%9A%A0%EF%B8%8F%20jquantstats%20%E2%80%94%20Risk%20Metrics%20Deep%20Dive%0A%0A%20%20%20%20%20%20%20%20This%20notebook%20explores%20the%20full%20breadth%20of%20**risk%20and%20downside%20metrics**%0A%20%20%20%20%20%20%20%20available%20in%20%60jquantstats%60.%20%20All%20metrics%20are%20computed%20on%20real%20AAPL%20%2B%20META%0A%20%20%20%20%20%20%20%20daily%20returns%20(%E2%89%88%2011%20k%20rows)%20with%20SPY%20as%20the%20benchmark.%0A%0A%20%20%20%20%20%20%20%20%7C%20Group%20%7C%20Metrics%20covered%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**Tail%20risk**%20%7C%20VaR%2C%20CVaR%2C%20tail%20ratio%2C%20serenity%20index%20%7C%0A%20%20%20%20%20%20%20%20%7C%20**Drawdown**%20%7C%20Max%20DD%2C%20avg%20DD%2C%20max%20DD%20duration%2C%20worst%20periods%20%7C%0A%20%20%20%20%20%20%20%20%7C%20**Win%2Floss**%20%7C%20Win%20rate%2C%20payoff%20ratio%2C%20profit%20factor%2C%20gain-to-pain%20%7C%0A%20%20%20%20%20%20%20%20%7C%20**Position%20sizing**%20%7C%20Kelly%20criterion%2C%20risk-of-ruin%20%7C%0A%20%20%20%20%20%20%20%20%7C%20**Distribution%20shape**%20%7C%20Skew%2C%20kurtosis%2C%20outlier%20ratios%20%7C%0A%20%20%20%20%20%20%20%20%7C%20**Autocorrelation**%20%7C%20ACF%2C%20autocorr%20penalty%2C%20smart%20ratios%20%7C%0A%20%20%20%20%20%20%20%20%7C%20**Benchmark**%20%7C%20Up%2Fdown%20capture%2C%20alpha%2C%20beta%2C%20information%20ratio%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_load_data()%3A%0A%20%20%20%20%22%22%22Load%20portfolio%20returns%20and%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-%20Benchmark%3A%20SPY%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%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_tail_header()%3A%0A%20%20%20%20%22%22%22Tail%20risk%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%20Tail%20risk%20%E2%80%94%20VaR%2C%20CVaR%2C%20tail%20ratio%2C%20serenity%20index%0A%0A%20%20%20%20%20%20%20%20-%20**VaR%20(5%25)**%20%E2%80%94%20the%20worst%20daily%20return%20we%20expect%20to%20beat%2095%20%25%20of%20the%20time%0A%20%20%20%20%20%20%20%20-%20**CVaR%20(5%25)**%20%E2%80%94%20expected%20loss%20*given*%20we%20are%20in%20the%20worst%205%20%25%20of%20days%0A%20%20%20%20%20%20%20%20-%20**Tail%20ratio**%20%E2%80%94%20abs(95th-pct%20gain)%20%2F%20abs(5th-pct%20loss)%3B%20%3E%201%20means%20fat%20right%20tail%0A%20%20%20%20%20%20%20%20-%20**Serenity%20index**%20%E2%80%94%20CAGR%20%2F%20(max%20drawdown%20%C3%97%20downside%20volatility)%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_tail_metrics(data)%3A%0A%20%20%20%20%22%22%22Compute%20tail%20risk%20metrics.%22%22%22%0A%20%20%20%20var_5%20%3D%20data.stats.value_at_risk(alpha%3D0.05)%0A%20%20%20%20cvar_5%20%3D%20data.stats.conditional_value_at_risk(confidence%3D0.95)%0A%20%20%20%20tail%20%3D%20data.stats.tail_ratio()%0A%20%20%20%20serenity%20%3D%20data.stats.serenity_index()%0A%20%20%20%20return%20cvar_5%2C%20serenity%2C%20tail%2C%20var_5%0A%0A%0A%40app.cell%0Adef%20cell_tail_table(cvar_5%2C%20data%2C%20serenity%2C%20tail%2C%20var_5)%3A%0A%20%20%20%20%22%22%22Display%20tail%20risk%20table.%22%22%22%0A%20%20%20%20_rows%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22VaR%20(5%25)%22%2C%20**%7Ba%3A%20f%22%7Bvar_5%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22CVaR%20(5%25)%22%2C%20**%7Ba%3A%20f%22%7Bcvar_5%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Tail%20Ratio%22%2C%20**%7Ba%3A%20f%22%7Btail%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Serenity%20Index%22%2C%20**%7Ba%3A%20f%22%7Bserenity%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%5D%0A%20%20%20%20mo.plain_text(str(pl.DataFrame(_rows)))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_var_chart(data)%3A%0A%20%20%20%20%22%22%22Plot%20daily%20return%20distribution%20with%20VaR%2FCVaR%20annotations.%22%22%22%0A%20%20%20%20_var_5%20%3D%20data.stats.value_at_risk(alpha%3D0.05)%0A%20%20%20%20_cvar_5%20%3D%20data.stats.conditional_value_at_risk(confidence%3D0.95)%0A%0A%20%20%20%20fig_var%20%3D%20go.Figure()%0A%20%20%20%20_all_df%20%3D%20data.all%0A%0A%20%20%20%20for%20_asset%20in%20data.assets%3A%0A%20%20%20%20%20%20%20%20_returns%20%3D%20_all_df%5B_asset%5D.drop_nulls().cast(pl.Float64).to_list()%0A%20%20%20%20%20%20%20%20fig_var.add_trace(%0A%20%20%20%20%20%20%20%20%20%20%20%20go.Histogram(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3D_returns%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3D_asset%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20opacity%3D0.6%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nbinsx%3D120%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20histnorm%3D%22probability%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20fig_var.add_vline(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D_var_5%5B_asset%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20line_dash%3D%22dash%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20annotation_text%3Df%22%7B_asset%7D%20VaR%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20annotation_position%3D%22top%20right%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20fig_var.add_vline(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D_cvar_5%5B_asset%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20line_dash%3D%22dot%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20annotation_text%3Df%22%7B_asset%7D%20CVaR%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20annotation_position%3D%22top%20left%22%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20fig_var.update_layout(%0A%20%20%20%20%20%20%20%20title%3D%22Daily%20Return%20Distribution%20with%20VaR%20(dashed)%20and%20CVaR%20(dotted)%20at%205%25%22%2C%0A%20%20%20%20%20%20%20%20xaxis_title%3D%22Daily%20Return%22%2C%0A%20%20%20%20%20%20%20%20yaxis_title%3D%22Probability%22%2C%0A%20%20%20%20%20%20%20%20barmode%3D%22overlay%22%2C%0A%20%20%20%20%20%20%20%20height%3D440%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(fig_var%2C)%0A%0A%0A%40app.cell%0Adef%20cell_var_chart_show(fig_var)%3A%0A%20%20%20%20%22%22%22Display%20VaR%20chart.%22%22%22%0A%20%20%20%20fig_var%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_dd_header()%3A%0A%20%20%20%20%22%22%22Drawdown%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%20Drawdown%20analysis%0A%0A%20%20%20%20%20%20%20%20-%20**Max%20drawdown**%20%E2%80%94%20peak-to-trough%20decline%0A%20%20%20%20%20%20%20%20-%20**Avg%20drawdown**%20%E2%80%94%20average%20of%20all%20underwater%20excursions%0A%20%20%20%20%20%20%20%20-%20**Max%20DD%20duration**%20%E2%80%94%20longest%20time-to-recovery%20in%20periods%0A%20%20%20%20%20%20%20%20-%20**Ulcer%20index**%20%E2%80%94%20RMS%20of%20drawdown%20series%20(penalises%20long%2C%20deep%20drawdowns)%0A%20%20%20%20%20%20%20%20-%20**Ulcer%20Performance%20Index**%20%E2%80%94%20return%20%2F%20ulcer%20index%0A%20%20%20%20%20%20%20%20-%20**Recovery%20factor**%20%E2%80%94%20total%20return%20%2F%20max%20drawdown%20magnitude%0A%20%20%20%20%20%20%20%20-%20**Calmar%20ratio**%20%E2%80%94%20CAGR%20%2F%20max%20drawdown%20magnitude%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_dd_metrics(data)%3A%0A%20%20%20%20%22%22%22Compute%20drawdown%20family%20metrics.%22%22%22%0A%20%20%20%20max_dd%20%3D%20data.stats.max_drawdown()%0A%20%20%20%20avg_dd%20%3D%20data.stats.avg_drawdown()%0A%20%20%20%20max_dur%20%3D%20data.stats.max_drawdown_duration()%0A%20%20%20%20ulcer%20%3D%20data.stats.ulcer_index()%0A%20%20%20%20upi%20%3D%20data.stats.ulcer_performance_index()%0A%20%20%20%20recovery%20%3D%20data.stats.recovery_factor()%0A%20%20%20%20calmar%20%3D%20data.stats.calmar()%0A%20%20%20%20return%20avg_dd%2C%20calmar%2C%20max_dd%2C%20max_dur%2C%20recovery%2C%20ulcer%2C%20upi%0A%0A%0A%40app.cell%0Adef%20cell_dd_table(avg_dd%2C%20calmar%2C%20data%2C%20max_dd%2C%20max_dur%2C%20recovery%2C%20ulcer%2C%20upi)%3A%0A%20%20%20%20%22%22%22Display%20drawdown%20metrics%20table.%22%22%22%0A%20%20%20%20_rows%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Max%20Drawdown%22%2C%20**%7Ba%3A%20f%22%7Bmax_dd%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Avg%20Drawdown%22%2C%20**%7Ba%3A%20f%22%7Bavg_dd%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Max%20DD%20Duration%20(days)%22%2C%20**%7Ba%3A%20f%22%7Bmax_dur%5Ba%5D%3A.0f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Ulcer%20Index%22%2C%20**%7Ba%3A%20f%22%7Bulcer%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Ulcer%20Performance%20Index%22%2C%20**%7Ba%3A%20f%22%7Bupi%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Recovery%20Factor%22%2C%20**%7Ba%3A%20f%22%7Brecovery%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Calmar%20Ratio%22%2C%20**%7Ba%3A%20f%22%7Bcalmar%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%5D%0A%20%20%20%20mo.plain_text(str(pl.DataFrame(_rows)))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_worst_periods(data)%3A%0A%20%20%20%20%22%22%22Show%20worst-5%20periods%20per%20asset.%22%22%22%0A%20%20%20%20mo.md(%22%23%23%23%20Worst%205%20periods%20per%20asset%22)%0A%20%20%20%20worst%20%3D%20data.stats.worst_n_periods(n%3D5)%0A%20%20%20%20%23%20worst%20is%20%7Basset%3A%20%5Bval1%2C%20val2%2C%20...%5D%7D%20%E2%80%94%20reformat%20as%20a%20DataFrame%0A%20%20%20%20max_len%20%3D%20max(len(v)%20for%20v%20in%20worst.values())%0A%20%20%20%20_rows%20%3D%20%5B%5D%0A%20%20%20%20for%20i%20in%20range(max_len)%3A%0A%20%20%20%20%20%20%20%20_row%20%3D%20%7B%22Rank%22%3A%20i%20%2B%201%7D%0A%20%20%20%20%20%20%20%20for%20asset%2C%20vals%20in%20worst.items()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_row%5Basset%5D%20%3D%20f%22%7Bvals%5Bi%5D%3A.4f%7D%22%20if%20i%20%3C%20len(vals)%20else%20%22%22%0A%20%20%20%20%20%20%20%20_rows.append(_row)%0A%20%20%20%20worst_df%20%3D%20pl.DataFrame(_rows)%0A%20%20%20%20return%20(worst_df%2C)%0A%0A%0A%40app.cell%0Adef%20cell_worst_periods_show(worst_df)%3A%0A%20%20%20%20%22%22%22Display%20worst%20periods.%22%22%22%0A%20%20%20%20mo.plain_text(str(worst_df))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_winloss_header()%3A%0A%20%20%20%20%22%22%22Win%2Floss%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%20Win%2Floss%20metrics%0A%0A%20%20%20%20%20%20%20%20-%20**Win%20rate**%20%E2%80%94%20fraction%20of%20positive%20periods%0A%20%20%20%20%20%20%20%20-%20**Monthly%20win%20rate**%20%E2%80%94%20fraction%20of%20positive%20months%0A%20%20%20%20%20%20%20%20-%20**Payoff%20ratio**%20%E2%80%94%20avg%20win%20%2F%20%7Cavg%20loss%7C%0A%20%20%20%20%20%20%20%20-%20**Profit%20factor**%20%E2%80%94%20sum%20of%20wins%20%2F%20%7Csum%20of%20losses%7C%0A%20%20%20%20%20%20%20%20-%20**Gain-to-pain%20ratio**%20%E2%80%94%20total%20gains%20%2F%20total%20%7Closses%7C%0A%20%20%20%20%20%20%20%20-%20**CPC%20index**%20%E2%80%94%20win%20rate%20%C3%97%20payoff%20ratio%20(common%20sense%20ratio%20variant)%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_winloss_metrics(data)%3A%0A%20%20%20%20%22%22%22Compute%20win%2Floss%20metrics.%22%22%22%0A%20%20%20%20win_rate%20%3D%20data.stats.win_rate()%0A%20%20%20%20monthly_win%20%3D%20data.stats.monthly_win_rate()%0A%20%20%20%20payoff%20%3D%20data.stats.payoff_ratio()%0A%20%20%20%20profit_f%20%3D%20data.stats.profit_factor()%0A%20%20%20%20g2p%20%3D%20data.stats.gain_to_pain_ratio()%0A%20%20%20%20cpc%20%3D%20data.stats.cpc_index()%0A%20%20%20%20return%20cpc%2C%20g2p%2C%20monthly_win%2C%20payoff%2C%20profit_f%2C%20win_rate%0A%0A%0A%40app.cell%0Adef%20cell_winloss_table(%0A%20%20%20%20cpc%2C%0A%20%20%20%20data%2C%0A%20%20%20%20g2p%2C%0A%20%20%20%20monthly_win%2C%0A%20%20%20%20payoff%2C%0A%20%20%20%20profit_f%2C%0A%20%20%20%20win_rate%2C%0A)%3A%0A%20%20%20%20%22%22%22Display%20win%2Floss%20metrics%20table.%22%22%22%0A%20%20%20%20_rows%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Win%20Rate%20(daily)%22%2C%20**%7Ba%3A%20f%22%7Bwin_rate%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Monthly%20Win%20Rate%22%2C%20**%7Ba%3A%20f%22%7Bmonthly_win%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Payoff%20Ratio%22%2C%20**%7Ba%3A%20f%22%7Bpayoff%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Profit%20Factor%22%2C%20**%7Ba%3A%20f%22%7Bprofit_f%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Gain-to-Pain%22%2C%20**%7Ba%3A%20f%22%7Bg2p%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22CPC%20Index%22%2C%20**%7Ba%3A%20f%22%7Bcpc%5Ba%5D%3A.3f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%5D%0A%20%20%20%20mo.plain_text(str(pl.DataFrame(_rows)))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_kelly_header()%3A%0A%20%20%20%20%22%22%22Kelly%20criterion%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%20Kelly%20criterion%20%26%20risk-of-ruin%0A%0A%20%20%20%20%20%20%20%20-%20**Kelly%20criterion**%20%E2%80%94%20theoretically%20optimal%20leverage%20fraction%3A%20%60win_rate%20-%20(1%20-%20win_rate)%20%2F%20payoff_ratio%60%0A%20%20%20%20%20%20%20%20-%20**Risk-of-ruin**%20%E2%80%94%20probability%20of%20losing%20a%20fixed%20fraction%20of%20capital%20under%20the%20current%20return%20distribution%0A%0A%20%20%20%20%20%20%20%20Kelly%20%3E%201%20means%20even%20full%20Kelly%20is%20under-leveraged%20relative%20to%20the%20edge%3B%0A%20%20%20%20%20%20%20%20in%20practice%20use%20half-Kelly%20or%20quarter-Kelly%20to%20account%20for%20estimation%20error.%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_kelly_metrics(data)%3A%0A%20%20%20%20%22%22%22Compute%20Kelly%20criterion%20and%20risk-of-ruin.%22%22%22%0A%20%20%20%20kelly%20%3D%20data.stats.kelly_criterion()%0A%20%20%20%20ror%20%3D%20data.stats.risk_of_ruin()%0A%20%20%20%20return%20kelly%2C%20ror%0A%0A%0A%40app.cell%0Adef%20cell_kelly_table(data%2C%20kelly%2C%20ror)%3A%0A%20%20%20%20%22%22%22Display%20Kelly%20%2F%20risk-of-ruin%20table.%22%22%22%0A%20%20%20%20_rows%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Kelly%20Criterion%22%2C%20**%7Ba%3A%20f%22%7Bkelly%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Risk%20of%20Ruin%22%2C%20**%7Ba%3A%20f%22%7Bror%5Ba%5D%3A.6f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%5D%0A%20%20%20%20mo.plain_text(str(pl.DataFrame(_rows)))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_shape_header()%3A%0A%20%20%20%20%22%22%22Distribution%20shape%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%205%20%C2%B7%20Distribution%20shape%20%E2%80%94%20skew%2C%20kurtosis%2C%20outliers%0A%0A%20%20%20%20%20%20%20%20A%20normal%20distribution%20has%20skew%20%3D%200%20and%20excess%20kurtosis%20%3D%200.%0A%20%20%20%20%20%20%20%20Financial%20returns%20typically%20exhibit%20**negative%20skew**%20(larger%20left%20tail)%20and%0A%20%20%20%20%20%20%20%20**positive%20excess%20kurtosis**%20(fat%20tails).%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_shape_metrics(data)%3A%0A%20%20%20%20%22%22%22Compute%20distribution%20shape%20metrics.%22%22%22%0A%20%20%20%20skew%20%3D%20data.stats.skew()%0A%20%20%20%20kurt%20%3D%20data.stats.kurtosis()%0A%20%20%20%20%23%20outliers()%20returns%20a%20Series%20of%20extreme%20returns%3B%20len%20gives%20the%20count%0A%20%20%20%20outlier_series%20%3D%20data.stats.outliers()%0A%20%20%20%20outlier_count%20%3D%20%7Ba%3A%20len(outlier_series%5Ba%5D)%20for%20a%20in%20data.assets%7D%0A%20%20%20%20out_win%20%3D%20data.stats.outlier_win_ratio()%0A%20%20%20%20out_loss%20%3D%20data.stats.outlier_loss_ratio()%0A%20%20%20%20return%20kurt%2C%20out_loss%2C%20out_win%2C%20outlier_count%2C%20skew%0A%0A%0A%40app.cell%0Adef%20cell_shape_table(data%2C%20kurt%2C%20out_loss%2C%20out_win%2C%20outlier_count%2C%20skew)%3A%0A%20%20%20%20%22%22%22Display%20distribution%20shape%20table.%22%22%22%0A%20%20%20%20_rows%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Skewness%22%2C%20**%7Ba%3A%20f%22%7Bskew%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Excess%20Kurtosis%22%2C%20**%7Ba%3A%20f%22%7Bkurt%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Outlier%20Count%20(%3EP95)%22%2C%20**%7Ba%3A%20str(outlier_count%5Ba%5D)%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Outlier%20Win%20Ratio%22%2C%20**%7Ba%3A%20f%22%7Bout_win%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Outlier%20Loss%20Ratio%22%2C%20**%7Ba%3A%20f%22%7Bout_loss%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%5D%0A%20%20%20%20mo.plain_text(str(pl.DataFrame(_rows)))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_acf_header()%3A%0A%20%20%20%20%22%22%22Autocorrelation%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%206%20%C2%B7%20Autocorrelation%20%26%20smart%20ratios%0A%0A%20%20%20%20%20%20%20%20Return%20autocorrelation%20matters%20for%20risk%3A%20a%20strategy%20with%20positively%0A%20%20%20%20%20%20%20%20autocorrelated%20returns%20(trending)%20has%20**higher%20true%20volatility**%20than%0A%20%20%20%20%20%20%20%20the%20i.i.d.%20estimate%20suggests.%20%20The%20%60autocorr_penalty%60%20adjusts%20for%20this.%0A%0A%20%20%20%20%20%20%20%20-%20**Lag-1%20autocorrelation**%20%E2%80%94%20correlation%20between%20consecutive%20returns%0A%20%20%20%20%20%20%20%20-%20**Autocorr%20penalty**%20%E2%80%94%20multiplicative%20adjustment%20to%20the%20Sharpe%20denominator%0A%20%20%20%20%20%20%20%20-%20**Smart%20Sharpe**%20%E2%80%94%20Sharpe%20%C3%97%20autocorr%20penalty%20(lower%20when%20returns%20are%20trending)%0A%20%20%20%20%20%20%20%20-%20**Smart%20Sortino**%20%E2%80%94%20Sortino%20%C3%97%20autocorr%20penalty%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_acf_metrics(data)%3A%0A%20%20%20%20%22%22%22Compute%20autocorrelation%20metrics.%22%22%22%0A%20%20%20%20ac1%20%3D%20data.stats.autocorr(lag%3D1)%0A%20%20%20%20penalty%20%3D%20data.stats.autocorr_penalty()%0A%20%20%20%20smart_sharpe%20%3D%20data.stats.smart_sharpe()%0A%20%20%20%20sharpe%20%3D%20data.stats.sharpe()%0A%20%20%20%20smart_sortino%20%3D%20data.stats.smart_sortino()%0A%20%20%20%20sortino%20%3D%20data.stats.sortino()%0A%20%20%20%20return%20ac1%2C%20penalty%2C%20sharpe%2C%20smart_sharpe%2C%20smart_sortino%2C%20sortino%0A%0A%0A%40app.cell%0Adef%20cell_acf_table(%0A%20%20%20%20ac1%2C%0A%20%20%20%20data%2C%0A%20%20%20%20penalty%2C%0A%20%20%20%20sharpe%2C%0A%20%20%20%20smart_sharpe%2C%0A%20%20%20%20smart_sortino%2C%0A%20%20%20%20sortino%2C%0A)%3A%0A%20%20%20%20%22%22%22Display%20autocorrelation%20metrics%20table.%22%22%22%0A%20%20%20%20_rows%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Lag-1%20Autocorrelation%22%2C%20**%7Ba%3A%20f%22%7Bac1%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Autocorr%20Penalty%22%2C%20**%7Ba%3A%20f%22%7Bpenalty%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Sharpe%20(standard)%22%2C%20**%7Ba%3A%20f%22%7Bsharpe%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Smart%20Sharpe%22%2C%20**%7Ba%3A%20f%22%7Bsmart_sharpe%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Sortino%20(standard)%22%2C%20**%7Ba%3A%20f%22%7Bsortino%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Smart%20Sortino%22%2C%20**%7Ba%3A%20f%22%7Bsmart_sortino%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%5D%0A%20%20%20%20mo.plain_text(str(pl.DataFrame(_rows)))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_bench_header()%3A%0A%20%20%20%20%22%22%22Benchmark%20analytics%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%207%20%C2%B7%20Benchmark%20analytics%20%E2%80%94%20alpha%2C%20beta%2C%20capture%20ratios%0A%0A%20%20%20%20%20%20%20%20Requires%20a%20benchmark%20series%20in%20the%20%60Data%60%20object%20(here%3A%20SPY).%0A%0A%20%20%20%20%20%20%20%20-%20**Alpha**%20%E2%80%94%20annualised%20return%20unexplained%20by%20the%20benchmark%0A%20%20%20%20%20%20%20%20-%20**Beta**%20%E2%80%94%20sensitivity%20of%20returns%20to%20benchmark%20movements%0A%20%20%20%20%20%20%20%20-%20**R%C2%B2**%20%E2%80%94%20fraction%20of%20variance%20explained%20by%20the%20benchmark%0A%20%20%20%20%20%20%20%20-%20**Up%20capture**%20%E2%80%94%20return%20in%20up-market%20months%20relative%20to%20benchmark%0A%20%20%20%20%20%20%20%20-%20**Down%20capture**%20%E2%80%94%20return%20in%20down-market%20months%20relative%20to%20benchmark%0A%20%20%20%20%20%20%20%20-%20**Information%20ratio**%20%E2%80%94%20(return%20%E2%88%92%20benchmark)%20%2F%20tracking%20error%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_bench_metrics(data)%3A%0A%20%20%20%20%22%22%22Compute%20benchmark-relative%20metrics.%22%22%22%0A%20%20%20%20bench_series%20%3D%20data.benchmark%5Bdata.benchmark.columns%5B0%5D%5D%0A%20%20%20%20greeks%20%3D%20data.stats.greeks()%0A%20%20%20%20up_cap%20%3D%20data.stats.up_capture(benchmark%3Dbench_series)%0A%20%20%20%20down_cap%20%3D%20data.stats.down_capture(benchmark%3Dbench_series)%0A%20%20%20%20ir%20%3D%20data.stats.information_ratio()%0A%20%20%20%20r2%20%3D%20data.stats.r_squared()%0A%20%20%20%20return%20bench_series%2C%20down_cap%2C%20greeks%2C%20ir%2C%20r2%2C%20up_cap%0A%0A%0A%40app.cell%0Adef%20cell_bench_table(data%2C%20down_cap%2C%20greeks%2C%20ir%2C%20r2%2C%20up_cap)%3A%0A%20%20%20%20%22%22%22Display%20benchmark%20metrics%20table.%22%22%22%0A%20%20%20%20_rows%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Alpha%20(ann.)%22%2C%20**%7Ba%3A%20f%22%7Bgreeks%5Ba%5D.get('alpha'%2C%20float('nan'))%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Beta%22%2C%20**%7Ba%3A%20f%22%7Bgreeks%5Ba%5D.get('beta'%2C%20float('nan'))%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22R%C2%B2%22%2C%20**%7Ba%3A%20f%22%7Br2%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Information%20Ratio%22%2C%20**%7Ba%3A%20f%22%7Bir%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Up%20Capture%22%2C%20**%7Ba%3A%20f%22%7Bup_cap%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Down%20Capture%22%2C%20**%7Ba%3A%20f%22%7Bdown_cap%5Ba%5D%3A.4f%7D%22%20for%20a%20in%20data.assets%7D%7D%2C%0A%20%20%20%20%5D%0A%20%20%20%20mo.plain_text(str(pl.DataFrame(_rows)))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_capture_chart(bench_series%2C%20data)%3A%0A%20%20%20%20%22%22%22Plot%20up%20vs%20down%20capture%20scatter.%22%22%22%0A%20%20%20%20_up_cap%20%3D%20data.stats.up_capture(benchmark%3Dbench_series)%0A%20%20%20%20_down_cap%20%3D%20data.stats.down_capture(benchmark%3Dbench_series)%0A%0A%20%20%20%20fig_cap%20%3D%20go.Figure()%0A%20%20%20%20for%20_asset%20in%20data.assets%3A%0A%20%20%20%20%20%20%20%20fig_cap.add_trace(%0A%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%20x%3D%5B_down_cap%5B_asset%5D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3D%5B_up_cap%5B_asset%5D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%2Btext%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3D_asset%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%3D%5B_asset%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20textposition%3D%22top%20center%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20marker%3D%7B%22size%22%3A%2014%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%23%20Diagonal%3A%20up%20%3D%20down%20capture%20(neutral)%0A%20%20%20%20lo%20%3D%20min(list(_down_cap.values())%20%2B%20list(_up_cap.values()))%20*%200.9%0A%20%20%20%20hi%20%3D%20max(list(_down_cap.values())%20%2B%20list(_up_cap.values()))%20*%201.1%0A%20%20%20%20fig_cap.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%5Blo%2C%20hi%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D%5Blo%2C%20hi%5D%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%20name%3D%22Benchmark%20(1%3A1)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20line%3D%7B%22dash%22%3A%20%22dash%22%2C%20%22color%22%3A%20%22grey%22%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20showlegend%3DTrue%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%0A%20%20%20%20fig_cap.update_layout(%0A%20%20%20%20%20%20%20%20title%3D%22Up%20vs%20Down%20Capture%20vs%20SPY%3Cbr%3E%3Csup%3EAbove%20the%20diagonal%20%3D%20better%20relative%20performance%3C%2Fsup%3E%22%2C%0A%20%20%20%20%20%20%20%20xaxis_title%3D%22Down%20Capture%20Ratio%22%2C%0A%20%20%20%20%20%20%20%20yaxis_title%3D%22Up%20Capture%20Ratio%22%2C%0A%20%20%20%20%20%20%20%20height%3D440%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(fig_cap%2C)%0A%0A%0A%40app.cell%0Adef%20cell_capture_chart_show(fig_cap)%3A%0A%20%20%20%20%22%22%22Display%20capture%20ratio%20chart.%22%22%22%0A%20%20%20%20fig_cap%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_rolling_risk_header()%3A%0A%20%20%20%20%22%22%22Rolling%20risk%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%208%20%C2%B7%20Rolling%20risk%20overview%0A%0A%20%20%20%20%20%20%20%20Rolling%20windows%20reveal%20how%20risk%20characteristics%20evolve%20through%20time.%0A%20%20%20%20%20%20%20%20A%20126-day%20(%E2%89%88%206-month)%20window%20is%20used%20here.%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_rolling_vol(data)%3A%0A%20%20%20%20%22%22%22Rolling%20volatility%20chart.%22%22%22%0A%20%20%20%20fig_rv%20%3D%20data.plots.rolling_volatility(rolling_period%3D126%2C%20title%3D%22Rolling%20Annualised%20Volatility%20(126-day)%22)%0A%20%20%20%20return%20(fig_rv%2C)%0A%0A%0A%40app.cell%0Adef%20cell_rolling_vol_show(fig_rv)%3A%0A%20%20%20%20%22%22%22Display%20rolling%20volatility%20chart.%22%22%22%0A%20%20%20%20fig_rv%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_rolling_beta(data)%3A%0A%20%20%20%20%22%22%22Rolling%20beta%20chart.%22%22%22%0A%20%20%20%20fig_rb%20%3D%20data.plots.rolling_beta(rolling_period%3D126%2C%20title%3D%22Rolling%20Beta%20vs%20SPY%20(126-day)%22)%0A%20%20%20%20return%20(fig_rb%2C)%0A%0A%0A%40app.cell%0Adef%20cell_rolling_beta_show(fig_rb)%3A%0A%20%20%20%20%22%22%22Display%20rolling%20beta%20chart.%22%22%22%0A%20%20%20%20fig_rb%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
ad3769ec523d1568df6c1b0245daf83a