import%20marimo%0A%0A__generated_with%20%3D%20%220.14.17%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0Awith%20app.setup%3A%0A%20%20%20%20import%20cvxpy%20as%20cp%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pandas%20as%20pd%0A%0A%20%20%20%20from%20cvxrisk.portfolio%20import%20minrisk_problem%0A%20%20%20%20from%20cvxrisk.random%20import%20rand_cov%0A%20%20%20%20from%20cvxrisk.sample%20import%20SampleCovariance%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20This%20notebook%20is%20based%20on%20an%20idea%20by%20Nicholas%20Gunther%0A%0A%20%20%20%20We%20welcome%20such%20ideas%20very%20much%20as%20they%20help%20to%20improve%20our%20tools%0A%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%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20Can%20you%20give%20some%20guidance%20on%20how%20to%20include%20constraints%20in%20cvxrisk%3F%0A%20%20%20%20It%20doesn't%20seem%20to%20appear%20in%20the%20short%20documentation.%0A%20%20%20%20For%20specificity%2C%20here's%20a%20question%20related%20to%20price-earnings%20%22tilts%22.%0A%20%20%20%20I%20illustrate%20it%20with%20a%20toy%20example.%0A%0A%20%20%20%20Let%20S%20be%20a%20sample%20covariance%20matrix%2C%20let%20w_SP%20be%20the%20(market%20cap)%20weights%20of%20stocks%20in%20the%20S%26P%20500%20index%0A%20%20%20%20and%20let%20V%20be%20a%20vector%20of%20earning-price%20normalized%20%22z-scores%22.%20%20I%20want%20to%20solve%20the%20following%20for%20w%3A%0A%0A%20%20%20%20Minimize%20(w%20-%20w_SP).transpose%20%40%20S%20%40%20(w%20-%20w_SP)%0A%0A%20%20%20%20subject%20to%3A%0A%0A%20%20%20%20w%20%3E%3D%200%0A%0A%20%20%20%20sum(w)%20%3D%201%0A%0A%20%20%20%20w.dot(V)%20%3D%200.5%0A%0A%20%20%20%20The%20exercise%20is%20to%20find%20a%20portfolio%20that%20is%20%22close%22%20to%20the%20S%26P%20500%20index%20but%0A%20%20%20%20has%20lower%20price-earnings%20ratios%2C%20a%20%22value%22%20tilt.%20%20I%20can%20work%20through%20this%20in%20cvxpy%2C%0A%20%20%20%20somewhat%20laboriously%2C%20but%20can%20cvxrisk%20accommodate%20these%20constraints%20easily%3F%0A%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%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20We%20shall%20first%20observe%20that%20if%20we%20drop%20the%20constraint%20w.dot(V)%0A%20%20%20%20the%20optimal%20vector%20is%20just%20w%20%3D%20w_SP%20assuming%20that%20w_SP%20%3E%3D%200%20and%20sum(w_SP)%20%3D%201.%0A%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%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20For%20this%20problem%20we%20have%20enhanced%20the%20builtin%20minrisk%20function.%0A%20%20%20%20One%20can%20now%20inject%20convex%20constraints.%0A%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%20%23%20Let's%20start%20without%20the%20tilting%20constraint%0A%20%20%20%20assets%20%3D%20%5B%22A%22%2C%20%22B%22%2C%20%22C%22%2C%20%22D%22%2C%20%22E%22%5D%0A%20%20%20%20s%20%3D%20pd.DataFrame(index%3Dassets%2C%20columns%3Dassets%2C%20data%3Drand_cov(len(assets)))%0A%0A%20%20%20%20%23%20those%20are%20the%20market%20weights%20for%20our%205%20markets%0A%20%20%20%20w_sp%20%3D%20pd.Series(index%3Dassets%2C%20data%3D%5B0.1%2C%200.2%2C%200.3%2C%200.1%2C%200.3%5D)%0A%0A%20%20%20%20%23%20we%20need%20the%20cvxpy%20variable%20for%20the%20weights%0A%20%20%20%20weights%20%3D%20cp.Variable(name%3D%22weights%22%2C%20shape%3Dlen(assets))%0A%0A%20%20%20%20%23%20Let's%20define%20a%20sample%20covariance%20riskmodel%0A%20%20%20%20riskmodel%20%3D%20SampleCovariance(num%3Dlen(assets))%0A%20%20%20%20riskmodel.update(cov%3Ds.to_numpy()%2C%20lower_assets%3Dnp.zeros(len(assets))%2C%20upper_assets%3Dnp.ones(len(assets)))%0A%0A%20%20%20%20%23%20the%20tilting%20vector%0A%20%20%20%20v%20%3D%20pd.Series(index%3Dassets%2C%20data%3D%5B0.1%2C%200.1%2C%200.5%2C%200.0%2C%200.5%5D)%0A%20%20%20%20return%20assets%2C%20riskmodel%2C%20v%2C%20w_sp%2C%20weights%0A%0A%0A%40app.cell%0Adef%20_(assets%2C%20riskmodel%2C%20w_sp%2C%20weights)%3A%0A%20%20%20%20%23%20without%20the%20tilting%20constraint.%20We%20reproduce%20(as%20predicted)%20w_sp.%0A%20%20%20%20problem%20%3D%20minrisk_problem(riskmodel%3Driskmodel%2C%20weights%3Dweights%2C%20base%3Dw_sp.values%2C%20constraints%3D%5B%5D)%0A%0A%20%20%20%20print(problem)%0A%20%20%20%20problem.solve(solver%3D%22CLARABEL%22)%0A%0A%20%20%20%20solution%20%3D%20pd.Series(index%3Dassets%2C%20data%3Dweights.value)%0A%20%20%20%20print(solution)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(assets%2C%20riskmodel%2C%20v%2C%20w_sp%2C%20weights)%3A%0A%20%20%20%20%23%20Now%20we%20specify%20the%20tilting%20constraint%0A%20%20%20%20constraints%20%3D%20%5Bv.to_numpy()%20%40%20weights%20%3D%3D%200.5%5D%0A%20%20%20%20%23%20We%20inject%20the%20constraints%0A%20%20%20%20problem_tilt%20%3D%20minrisk_problem(riskmodel%3Driskmodel%2C%20weights%3Dweights%2C%20base%3Dw_sp.values%2C%20constraints%3Dconstraints)%0A%0A%20%20%20%20print(problem_tilt)%0A%20%20%20%20problem_tilt.solve(solver%3D%22CLARABEL%22)%0A%0A%20%20%20%20%23%20The%20solution%20is%20different%20from%20the%20previous%20problem%0A%20%20%20%20solution_tilt%20%3D%20pd.Series(index%3Dassets%2C%20data%3Dweights.value)%0A%20%20%20%20print(solution_tilt)%0A%20%20%20%20%23%20We%20check%20whether%20the%20tilting%20constraint%20is%20respected%0A%20%20%20%20print(%22Tilting%20value.%20Should%20be%20close%20to%200.5%3A%22)%0A%20%20%20%20print(solution_tilt.to_numpy()%20%40%20v.to_numpy())%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
a752a263280714a436481704776239bacb84716858d7144541f361a29dfbf0f3