%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%20datetime%20import%20date%2C%20timedelta%0A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20polars%20as%20pl%0A%0A%20%20%20%20from%20jquantstats%20import%20Portfolio%0A%0A%0A%40app.cell%0Adef%20cell_intro()%3A%0A%20%20%20%20%22%22%22Render%20the%20analytics%20demo%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%93%8A%20jquantstats%20%E2%80%94%20Portfolio%20Analytics%20Demo%0A%0A%20%20%20%20%20%20%20%20This%20notebook%20demonstrates%20the%20**Portfolio%20analytics**%20subpackage%20from%20%60jquantstats%60.%0A%0A%20%20%20%20%20%20%20%20It%20covers%3A%0A%20%20%20%20%20%20%20%201.%20%F0%9F%93%88%20**Synthetic%20data%20generation**%20%E2%80%94%20create%20a%202-asset%20price%20and%20position%20series%0A%20%20%20%20%20%20%20%202.%20%F0%9F%8F%97%EF%B8%8F%20**Portfolio%20construction**%20%E2%80%94%20use%20%60Portfolio.from_cash_position(...)%60%0A%20%20%20%20%20%20%20%203.%20%F0%9F%93%89%20**Portfolio%20analytics**%20%E2%80%94%20NAV%2C%20drawdown%2C%20statistics%2C%20and%20visualisations%0A%20%20%20%20%20%20%20%204.%20%F0%9F%93%8B%20**HTML%20report%20generation**%20%E2%80%94%20self-contained%20report%20via%20%60portfolio.report.to_html()%60%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_data()%3A%0A%20%20%20%20%22%22%22Generate%20synthetic%202-asset%20price%20and%20position%20data.%22%22%22%0A%20%20%20%20n%20%3D%20120%0A%20%20%20%20start%20%3D%20date(2020%2C%201%2C%201)%0A%20%20%20%20end%20%3D%20start%20%2B%20timedelta(days%3Dn%20-%201)%0A%20%20%20%20dates%20%3D%20pl.date_range(start%3Dstart%2C%20end%3Dend%2C%20interval%3D%221d%22%2C%20eager%3DTrue).cast(pl.Date)%0A%0A%20%20%20%20rng%20%3D%20np.random.default_rng(42)%0A%0A%20%20%20%20%23%20Asset%20A%3A%20trending%20upward%20with%20small%20noise%0A%20%20%20%20price_a%20%3D%20pl.Series(%0A%20%20%20%20%20%20%20%20%5B100.0%20*%20(1.001**i)%20*%20(1%20%2B%200.005%20*%20rng.standard_normal())%20for%20i%20in%20range(n)%5D%2C%0A%20%20%20%20%20%20%20%20dtype%3Dpl.Float64%2C%0A%20%20%20%20)%0A%20%20%20%20%23%20Asset%20B%3A%20mean-reverting%20sine%20pattern%0A%20%20%20%20price_b%20%3D%20pl.Series(%0A%20%20%20%20%20%20%20%20%5B200.0%20%2B%2010.0%20*%20np.sin(0.1%20*%20i)%20%2B%202.0%20*%20rng.standard_normal()%20for%20i%20in%20range(n)%5D%2C%0A%20%20%20%20%20%20%20%20dtype%3Dpl.Float64%2C%0A%20%20%20%20)%0A%0A%20%20%20%20prices%20%3D%20pl.DataFrame(%7B%22date%22%3A%20dates%2C%20%22A%22%3A%20price_a%2C%20%22B%22%3A%20price_b%7D)%0A%0A%20%20%20%20pos_a%20%3D%20pl.Series(%5B1000.0%20%2B%205.0%20*%20i%20for%20i%20in%20range(n)%5D%2C%20dtype%3Dpl.Float64)%0A%20%20%20%20pos_b%20%3D%20pl.Series(%5B500.0%20%2B%20float(i%20%25%205)%20*%2050.0%20for%20i%20in%20range(n)%5D%2C%20dtype%3Dpl.Float64)%0A%20%20%20%20positions%20%3D%20pl.DataFrame(%7B%22date%22%3A%20dates%2C%20%22A%22%3A%20pos_a%2C%20%22B%22%3A%20pos_b%7D)%0A%0A%20%20%20%20mo.md(f%22Generated%20**%7Bn%7D-day**%20synthetic%20portfolio%20with%20**2%20assets**%20(A%2C%20B).%22)%0A%20%20%20%20return%20positions%2C%20prices%0A%0A%0A%40app.cell%0Adef%20cell_portfolio(positions%2C%20prices)%3A%0A%20%20%20%20%22%22%22Build%20the%20Portfolio%20from%20cash%20positions.%22%22%22%0A%20%20%20%20portfolio%20%3D%20Portfolio.from_cash_position(%0A%20%20%20%20%20%20%20%20prices%3Dprices%2C%0A%20%20%20%20%20%20%20%20cash_position%3Dpositions%2C%0A%20%20%20%20%20%20%20%20aum%3D1_000_000.0%2C%0A%20%20%20%20)%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**Portfolio%20created**%20%E2%9C%85%0A%0A%20%20%20%20%20%20%20%20-%20Assets%3A%20%60%7Bportfolio.assets%7D%60%0A%20%20%20%20%20%20%20%20-%20AUM%3A%20%60%7Bportfolio.aum%3A%2C.0f%7D%60%0A%20%20%20%20%20%20%20%20-%20Periods%3A%20%60%7Bprices.height%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(portfolio%2C)%0A%0A%0A%40app.cell%0Adef%20cell_stats(portfolio)%3A%0A%20%20%20%20%22%22%22Display%20portfolio%20statistics%20summary.%22%22%22%0A%20%20%20%20summary%20%3D%20portfolio.stats.summary()%0A%20%20%20%20mo.md(%22%23%23%20%F0%9F%93%8A%20Statistics%20Summary%22)%0A%20%20%20%20return%20(summary%2C)%0A%0A%0A%40app.cell%0Adef%20cell_stats_table(summary)%3A%0A%20%20%20%20%22%22%22Show%20the%20stats%20table.%22%22%22%0A%20%20%20%20mo.plain_text(str(summary))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_snapshot(portfolio)%3A%0A%20%20%20%20%22%22%22Render%20the%20portfolio%20snapshot%20chart.%22%22%22%0A%20%20%20%20mo.md(%22%23%23%20%F0%9F%93%88%20Portfolio%20Snapshot%22)%0A%20%20%20%20fig%20%3D%20portfolio.plots.snapshot()%0A%20%20%20%20return%20(fig%2C)%0A%0A%0A%40app.cell%0Adef%20cell_snapshot_plot(fig)%3A%0A%20%20%20%20%22%22%22Display%20snapshot%20figure.%22%22%22%0A%20%20%20%20fig%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_lead_lag(portfolio)%3A%0A%20%20%20%20%22%22%22Render%20the%20lead%2Flag%20IR%20chart.%22%22%22%0A%20%20%20%20mo.md(%22%23%23%20%F0%9F%94%80%20Lead%2FLag%20Information%20Ratio%22)%0A%20%20%20%20fig_ll%20%3D%20portfolio.plots.lead_lag_ir_plot()%0A%20%20%20%20return%20(fig_ll%2C)%0A%0A%0A%40app.cell%0Adef%20cell_lead_lag_plot(fig_ll)%3A%0A%20%20%20%20%22%22%22Display%20lead%2Flag%20figure.%22%22%22%0A%20%20%20%20fig_ll%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20cell_report(portfolio)%3A%0A%20%20%20%20%22%22%22Generate%20and%20display%20the%20HTML%20report.%22%22%22%0A%20%20%20%20mo.md(%22%23%23%20%F0%9F%93%8B%20HTML%20Report%22)%0A%20%20%20%20html%20%3D%20portfolio.report.to_html(title%3D%22Analytics%20Demo%20Report%22)%0A%20%20%20%20mo.md(f%22Report%20generated%3A%20**%7Blen(html)%3A%2C%7D**%20characters%20of%20HTML.%22)%0A%20%20%20%20return%20(html%2C)%0A%0A%0A%40app.cell%0Adef%20cell_report_preview(html)%3A%0A%20%20%20%20%22%22%22Show%20a%20snippet%20of%20the%20report%20HTML.%22%22%22%0A%20%20%20%20snippet%20%3D%20html%5B%3A500%5D%20%2B%20%22...%22%0A%20%20%20%20mo.plain_text(snippet)%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
ca46e1ca5c1cfd71d84f194eb10bc839