import%20marimo%0A%0A__generated_with%20%3D%20%220.10.10%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%20Almost%20pairs%20trading%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%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%20This%20little%20exercise%20goes%20back%20to%20an%20idea%20by%20Stephen%20Boyd%3A%0A%0A%20%20%20%20%20%20%20%20The%20simulator%20should%20always%20be%20completely%20agnostic%20as%20to%20the%20trading%20policy.%0A%20%20%20%20%20%20%20%20You%20should%20even%20demonstrate%20this%20with%20silly%20policies.%0A%20%20%20%20%20%20%20%20Like%20here%E2%80%99s%20one%3A%20%20Each%20day%20choose%20names%20from%20the%20universe%20at%20random.%0A%20%20%20%20%20%20%20%20Buy%20one%20(say%200.1%20of%20your%20portfolio%20wealth)%20and%20short%20one%20the%20same%20amount.%0A%20%20%20%20%20%20%20%20Not%20a%20good%20strategy%2C%20but%20a%20valid%20one.%0A%20%20%20%20%20%20%20%20Of%20course%20the%20simulate%20will%20terminate%20if%20you%20go%20bust%20(which%20seems%20likely).%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%20_(__file__)%3A%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20from%20loguru%20import%20logger%0A%0A%20%20%20%20from%20cvx.simulator%20import%20Builder%0A%0A%20%20%20%20pd.options.plotting.backend%20%3D%20%22plotly%22%0A%20%20%20%20folder%20%3D%20Path(__file__).parent%0A%20%20%20%20return%20Builder%2C%20Path%2C%20folder%2C%20logger%2C%20np%2C%20pd%0A%0A%0A%40app.cell%0Adef%20_(Builder%2C%20folder%2C%20logger%2C%20np%2C%20pd)%3A%0A%20%20%20%20logger.info(%22Load%20prices%22)%0A%20%20%20%20prices%20%3D%20pd.read_csv(folder%20%2F%20%22data%22%20%2F%20%22stock-prices.csv%22%2C%20index_col%3D0%2C%20parse_dates%3DTrue%2C%20header%3D0)%0A%0A%20%20%20%20logger.info(%22Build%20portfolio%22)%0A%20%20%20%20b%20%3D%20Builder(prices%3Dprices%2C%20initial_aum%3D1e6)%0A%0A%20%20%20%20for%20t%2C%20state%20in%20b%3A%0A%20%20%20%20%20%20%20%20assert%20state.nav%20%3E%200%2C%20%22Game%20over%22%0A%0A%20%20%20%20%20%20%20%20%23%20pick%20two%20assets%20at%20random%0A%20%20%20%20%20%20%20%20pair%20%3D%20np.random.choice(state.assets%2C%202%2C%20replace%3DFalse)%0A%0A%20%20%20%20%20%20%20%20%23%20compute%20the%20pair%0A%20%20%20%20%20%20%20%20units%20%3D%20pd.Series(index%3Dstate.assets%2C%20data%3D0.0)%0A%20%20%20%20%20%20%20%20units%5Bpair%5D%20%3D%20%5Bstate.nav%2C%20-state.nav%5D%20%2F%20state.prices%5Bpair%5D.values%0A%20%20%20%20%20%20%20%20b.position%20%3D%200.1%20*%20units%0A%0A%20%20%20%20%20%20%20%20%23%201%20bps%20of%20the%20traded%20volume%20(measured%20in%20USD)%20are%20paid%20as%20fee%0A%20%20%20%20%20%20%20%20costs%20%3D%200.0001%20*%20(state.trades.abs()%20*%20state.prices).sum()%0A%20%20%20%20%20%20%20%20b.aum%20%3D%20state.aum%20-%20costs%0A%0A%20%20%20%20portfolio%20%3D%20b.build()%0A%20%20%20%20return%20b%2C%20costs%2C%20pair%2C%20portfolio%2C%20prices%2C%20state%2C%20t%2C%20units%0A%0A%0A%40app.cell%0Adef%20_(portfolio)%3A%0A%20%20%20%20portfolio.nav.plot()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20return%20(mo%2C)%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
2e4ba5521f12d766bc7357c971488aab198fe5bff189b9aa368b1aa5f65add5d