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(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20%23%20The%201%2Fn%20family%0A%0A%20%20%20%20%20%20%20%20We%20play%20with%20the%20%241%2Fn%24%20portfolio.%20We%20start%20with%20a%20vanilla%20implementation%20using%20daily%20rebalancing.%0A%20%20%20%20%20%20%20%20Every%20portfolio%20should%20be%20the%20solution%20of%20a%20convex%20optimization%20problem%2C%0A%20%20%20%20%20%20%20%20see%20https%3A%2F%2Fwww.linkedin.com%2Fpulse%2Fstock-picking-convex-programs-thomas-schmelzer.%0A%20%20%20%20%20%20%20%20We%20do%20that%20and%20show%20methods%20to%20construct%20the%20portfolio%20with%0A%0A%20%20%20%20%20%20%20%20*%20the%20minimization%20of%20the%20Euclidean%20norm%20of%20the%20weights.%0A%20%20%20%20%20%20%20%20*%20the%20minimization%20of%20the%20%24%5Cinfty%24%20norm%20of%20the%20weights.%0A%20%20%20%20%20%20%20%20*%20and%20the%20maximization%20of%20the%20Entropy%20of%20the%20weights.%0A%20%20%20%20%20%20%20%20*%20the%20minimization%20of%20the%20tracking%20error%20to%20an%20%241%2Fn%24%20portfolio.%0A%0A%20%20%20%20%20%20%20%20We%20also%20play%20with%20sparse%20updates%2C%20e.g.%20rather%20than%20rebalancing%20daily%2C%0A%20%20%20%20%20%20%20%20we%20act%20only%20once%20the%20deviation%20of%20our%20drifted%20portfolio%20got%20too%20large%20from%20the%20target%20%241%2Fn%24%20portfolio.%0A%0A%20%20%20%20%20%20%20%20This%20problem%20has%20been%20discussed%20https%3A%2F%2Fwww.linkedin.com%2Ffeed%2Fupdate%2Furn%3Ali%3Aactivity%3A7149432321388064768%2F%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%0A%20%20%20%20from%20cvx.simulator%20import%20Builder%0A%0A%20%20%20%20folder%20%3D%20Path(__file__).parent%0A%20%20%20%20return%20Builder%2C%20Path%2C%20folder%2C%20np%2C%20pd%0A%0A%0A%40app.cell%0Adef%20_(folder%2C%20pd)%3A%0A%20%20%20%20%23%20load%20prices%20from%20flat%20csv%20file%0A%20%20%20%20prices%20%3D%20pd.read_csv(folder%20%2F%20%22data%22%20%2F%20%22stock-prices.csv%22%2C%20header%3D0%2C%20index_col%3D0%2C%20parse_dates%3DTrue)%0A%20%20%20%20return%20(prices%2C)%0A%0A%0A%40app.cell%0Adef%20_(Builder%2C%20np%2C%20prices)%3A%0A%20%20%20%20_builder%20%3D%20Builder(prices%3Dprices%2C%20initial_aum%3D1000000.0)%0A%20%20%20%20for%20_%2C%20_state%20in%20_builder%3A%0A%20%20%20%20%20%20%20%20_n%20%3D%20len(_state.assets)%0A%20%20%20%20%20%20%20%20_builder.weights%20%3D%20np.ones(_n)%20%2F%20_n%0A%20%20%20%20%20%20%20%20_builder.aum%20%3D%20_state.aum%0A%0A%20%20%20%20_portfolio%20%3D%20_builder.build()%0A%20%20%20%20_portfolio.snapshot(aggregate%3DTrue)%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%20%23%23%20With%20cvxpy%0A%0A%20%20%20%20%20%20%20%20Formulating%20the%20problem%20above%20as%20a%20convex%20program%20is%20most%20useful%20when%20additional%20constraints%20have%0A%20%20%20%20%20%20%20%20to%20be%20reflected.%20It%20also%20helps%20to%20link%20the%201%2Fn%20portfolio%20to%20Tikhonov%20regularization%20and%20interpret%0A%20%20%20%20%20%20%20%20its%20solution%20as%20a%20cornercase%20for%20more%20complex%20portfolios%20we%20are%20building%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_()%3A%0A%20%20%20%20import%20cvxpy%20as%20cp%0A%20%20%20%20return%20(cp%2C)%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%20%23%23%23%20Minimization%20of%20the%20Euclidean%20norm%0A%0A%20%20%20%20%20%20%20%20We%20minimize%20the%20Euclidean%20norm%20of%20the%20weight%20vector.%20Same%20results%20as%20above%20but%20we%0A%20%20%20%20%20%20%20%20open%20door%20to%20the%20world%20of%20convex%20paradise.%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_(Builder%2C%20cp%2C%20prices)%3A%0A%20%20%20%20_builder%20%3D%20Builder(prices%3Dprices%2C%20initial_aum%3D1000000.0)%0A%20%20%20%20for%20_%2C%20_state%20in%20_builder%3A%0A%20%20%20%20%20%20%20%20_n%20%3D%20len(_state.assets)%0A%20%20%20%20%20%20%20%20_weights%20%3D%20cp.Variable(_n)%0A%20%20%20%20%20%20%20%20_objective%20%3D%20cp.norm(_weights%2C%202)%0A%20%20%20%20%20%20%20%20_constraints%20%3D%20%5B_weights%20%3E%3D%200%2C%20cp.sum(_weights)%20%3D%3D%201%5D%0A%20%20%20%20%20%20%20%20cp.Problem(objective%3Dcp.Minimize(_objective)%2C%20constraints%3D_constraints).solve(solver%3Dcp.CLARABEL)%0A%20%20%20%20%20%20%20%20_builder.weights%20%3D%20_weights.value%0A%20%20%20%20%20%20%20%20_builder.aum%20%3D%20_state.aum%0A%20%20%20%20_portfolio%20%3D%20_builder.build()%0A%20%20%20%20_portfolio.snapshot(aggregate%3DTrue)%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%20%23%23%23%20Minimization%20of%20the%20%24%5Cinfty%24%20norm%0A%0A%20%20%20%20%20%20%20%20Based%20on%20an%20idea%20by%20Vladimir%20Markov%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_(Builder%2C%20cp%2C%20prices)%3A%0A%20%20%20%20_builder%20%3D%20Builder(prices%3Dprices%2C%20initial_aum%3D1000000.0)%0A%20%20%20%20for%20_%2C%20_state%20in%20_builder%3A%0A%20%20%20%20%20%20%20%20_n%20%3D%20len(_state.assets)%0A%20%20%20%20%20%20%20%20_weights%20%3D%20cp.Variable(_n)%0A%20%20%20%20%20%20%20%20_objective%20%3D%20cp.norm_inf(_weights)%0A%20%20%20%20%20%20%20%20_constraints%20%3D%20%5B_weights%20%3E%3D%200%2C%20cp.sum(_weights)%20%3D%3D%201%5D%0A%20%20%20%20%20%20%20%20cp.Problem(objective%3Dcp.Minimize(_objective)%2C%20constraints%3D_constraints).solve(solver%3Dcp.CLARABEL)%0A%20%20%20%20%20%20%20%20_builder.weights%20%3D%20_weights.value%0A%20%20%20%20%20%20%20%20_builder.aum%20%3D%20_state.aum%0A%20%20%20%20_portfolio%20%3D%20_builder.build()%0A%20%20%20%20_portfolio.snapshot(aggregate%3DTrue)%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%20%23%23%23%20Maximization%20of%20the%20entropy%0A%0A%20%20%20%20%20%20%20%20One%20can%20also%20maximize%20the%20entropy%20to%20arrive%20at%20the%20same%20result%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_(Builder%2C%20cp%2C%20prices)%3A%0A%20%20%20%20_builder%20%3D%20Builder(prices%3Dprices%2C%20initial_aum%3D1000000.0)%0A%20%20%20%20for%20_%2C%20_state%20in%20_builder%3A%0A%20%20%20%20%20%20%20%20_n%20%3D%20len(_state.assets)%0A%20%20%20%20%20%20%20%20_weights%20%3D%20cp.Variable(_n)%0A%20%20%20%20%20%20%20%20_objective%20%3D%20cp.sum(cp.entr(_weights))%0A%20%20%20%20%20%20%20%20_constraints%20%3D%20%5B_weights%20%3E%3D%200%2C%20cp.sum(_weights)%20%3D%3D%201%5D%0A%20%20%20%20%20%20%20%20cp.Problem(objective%3Dcp.Maximize(_objective)%2C%20constraints%3D_constraints).solve(solver%3Dcp.CLARABEL)%0A%20%20%20%20%20%20%20%20_builder.weights%20%3D%20_weights.value%0A%20%20%20%20%20%20%20%20_builder.aum%20%3D%20_state.aum%0A%20%20%20%20_portfolio%20%3D%20_builder.build()%0A%20%20%20%20_portfolio.snapshot(aggregate%3DTrue)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%23%23%20Minimization%20of%20the%20tracking%20error%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Builder%2C%20cp%2C%20np%2C%20prices)%3A%0A%20%20%20%20_builder%20%3D%20Builder(prices%3Dprices%2C%20initial_aum%3D1000000.0)%0A%20%20%20%20for%20_%2C%20_state%20in%20_builder%3A%0A%20%20%20%20%20%20%20%20_n%20%3D%20len(_state.assets)%0A%20%20%20%20%20%20%20%20_weights%20%3D%20cp.Variable(_n)%0A%20%20%20%20%20%20%20%20_objective%20%3D%20cp.norm(_weights%20-%20np.ones(_n)%20%2F%20_n%2C%202)%0A%20%20%20%20%20%20%20%20_constraints%20%3D%20%5B_weights%20%3E%3D%200%2C%20cp.sum(_weights)%20%3D%3D%201%5D%0A%20%20%20%20%20%20%20%20cp.Problem(objective%3Dcp.Minimize(_objective)%2C%20constraints%3D_constraints).solve(solver%3Dcp.CLARABEL)%0A%20%20%20%20%20%20%20%20_builder.weights%20%3D%20_weights.value%0A%20%20%20%20%20%20%20%20_builder.aum%20%3D%20_state.aum%0A%20%20%20%20_portfolio%20%3D%20_builder.build()%0A%20%20%20%20_portfolio.snapshot(aggregate%3DTrue)%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%20%23%23%20With%20sparse%20updates%0A%0A%20%20%20%20%20%20%20%20In%20practice%20we%20do%20not%20want%20to%20rebalance%20the%20portfolio%20every%20day.%20We%20tolerate%20our%20portfolio%0A%20%20%20%20%20%20%20%20is%20not%20an%20exact%20%241%2Fn%24%20portfolio.%20We%20may%20expect%20slightly%20weaker%20results%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_(Builder%2C%20np%2C%20prices)%3A%0A%20%20%20%20_builder%20%3D%20Builder(prices%3Dprices%2C%20initial_aum%3D1000000.0)%0A%20%20%20%20for%20_%2C%20_state%20in%20_builder%3A%0A%20%20%20%20%20%20%20%20_n%20%3D%20len(_state.assets)%0A%20%20%20%20%20%20%20%20target%20%3D%20np.ones(_n)%20%2F%20_n%0A%20%20%20%20%20%20%20%20drifted%20%3D%20_state.weights%5B_state.assets%5D.fillna(0.0)%0A%20%20%20%20%20%20%20%20delta%20%3D%20(target%20-%20drifted).abs().sum()%0A%20%20%20%20%20%20%20%20if%20delta%20%3E%200.2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_builder.weights%20%3D%20target%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_builder.position%20%3D%20_state.position%0A%20%20%20%20%20%20%20%20_builder.aum%20%3D%20_state.aum%0A%20%20%20%20_portfolio%20%3D%20_builder.build()%0A%20%20%20%20_portfolio.snapshot(aggregate%3DTrue)%0A%20%20%20%20return%20delta%2C%20drifted%2C%20target%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
c67b3ffd66973a6fb10b64f081b72f77712941677b9aee72028a10739b8ee81f