-
Notifications
You must be signed in to change notification settings - Fork 3
/
portfolio-optimization.py
172 lines (125 loc) · 3.35 KB
/
portfolio-optimization.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import marimo
__generated_with = "0.7.21-dev18"
app = marimo.App()
@app.cell
def __():
import numpy as np
import cvxpy as cp
return cp, np
@app.cell(hide_code=True)
def __(mo):
mo.md(r"""_This notebook accompanies [Lecture 2, Disciplined Convex Programming](https://www.cvxgrp.org/nasa/pdf/lecture2.pdf), of the Convex Optimization Short Course, which was held at NASA in the summer of 2024._""")
return
@app.cell(hide_code=True)
def __(mo):
mo.md(
r"""
**Portfolio optimization** Imagine we have a budget
$B$ (dollars). We can purchase
$n$ different assets (e.g. stocks, bonds) with current prices
$p$ (dollars per unit), expected returns
$\mu$ (dollars per unit), and covariance
$\Sigma$ (dollars squared per unit squared). Your goal is to ensure the standard deviation of your portfolio to be less than
$S$ (dollars). We are only buying assets, not borrowing them, so we cannot “short” stocks and have a “long”-only portfolio. Lastly, we don’t want to end up over-invested in a single asset, so, let’s ensure we never put more than
$5%$ of our budget into a single asset.
"""
)
return
@app.cell(hide_code=True)
def __(mo, np):
# Define constants, B, n, p, mu, Sigma, S
rng = np.random.default_rng(0xEE364A)
B = 100
n = 100
p = rng.uniform(0, 2, n) ** 2 + 0.5
mu = rng.normal(0.01, 1, n)
Sigma = (Z := rng.normal(0, 1 / np.sqrt(n), (n, n))).T @ Z + 0.1 * np.eye(n)
S = 15
mo.md("This cell defines constants `B`, `n`, `p`, `mu`, `Sigma`, `S`")
return B, S, Sigma, Z, mu, n, p, rng
@app.cell(hide_code=True)
def __(mo):
mo.md(
"""
Define your optimization variables.
*Hint: it should be cp.Variable*
"""
)
return
@app.cell
def __():
x = ...
return x,
@app.cell(hide_code=True)
def __(mo):
mo.md(
"""
Define the objective.
*Hint: it should be either cp.Maximize or cp.Minimize*
"""
)
return
@app.cell
def __():
obj = ...
return obj,
@app.cell(hide_code=True)
def __(mo):
mo.md("""Create a standard deviation constraint""")
return
@app.cell
def __():
stddev_constraint = ...
return stddev_constraint,
@app.cell(hide_code=True)
def __(mo):
mo.md("""Add your budget constraint""")
return
@app.cell
def __():
budget_constraint = ...
return budget_constraint,
@app.cell
def __(mo):
mo.md(rf"Add your long only constraint")
return
@app.cell
def __():
long_only_constraint = ...
return long_only_constraint,
@app.cell(hide_code=True)
def __(mo):
mo.md("""Add your asset diversity constraint""")
return
@app.cell
def __():
asset_diversity_constraint = ...
return asset_diversity_constraint,
@app.cell(hide_code=True)
def __(mo):
mo.md("""Make and run your CVXPY problem!""")
return
@app.cell
def __(
asset_diversity_constraint,
budget_constraint,
cp,
long_only_constraint,
obj,
stddev_constraint,
):
constr = [
stddev_constraint,
budget_constraint,
long_only_constraint,
asset_diversity_constraint,
]
prob = cp.Problem(obj, constr)
prob.solve()
return constr, prob
@app.cell
def __():
import marimo as mo
return mo,
if __name__ == "__main__":
app.run()