You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
_Disclaimer: nothing about this project constitues investment advice,
@@ -255,79 +337,45 @@ The covariance matrix encodes not just the volatility of an asset, but also how
255
337
256
338
- Long/short: by default all of the mean-variance optimization methods in PyPortfolioOpt are long-only, but they can be initialised to allow for short positions by changing the weight bounds:
257
339
258
-
```python
259
-
>>> ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1))
340
+
<!--pytest-codeblocks:cont-->
260
341
342
+
```python
343
+
ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1))
261
344
```
262
345
263
346
- Market neutrality: for the `efficient_risk` and `efficient_return` methods, PyPortfolioOpt provides an option to form a market-neutral portfolio (i.e weights sum to zero). This is not possible for the max Sharpe portfolio and the min volatility portfolio because in those cases because they are not invariant with respect to leverage. Market neutrality requires negative weights:
264
347
265
-
```python
266
-
>>> ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1))
267
-
>>>for name, value in ef.efficient_return(target_return=0.2, market_neutral=True).items():
268
-
...print(f"{name}: {value:.4f}")
269
-
GOOG: 0.0747
270
-
AAPL: 0.0532
271
-
FB: 0.0664
272
-
BABA: 0.0116
273
-
AMZN: 0.0518
274
-
GE: -0.0595
275
-
AMD: -0.0679
276
-
WMT: -0.0817
277
-
BAC: -0.1413
278
-
GM: -0.1402
279
-
T: -0.1371
280
-
UAA: 0.0003
281
-
SHLD: -0.0706
282
-
XOM: -0.0775
283
-
RRC: -0.0510
284
-
BBY: 0.0349
285
-
MA: 0.3758
286
-
PFE: 0.1112
287
-
JPM: 0.0141
288
-
SBUX: 0.0330
348
+
<!--pytest-codeblocks:cont-->
289
349
350
+
```python
351
+
ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1))
352
+
for name, value in ef.efficient_return(target_return=0.2, market_neutral=True).items():
353
+
print(f"{name}: {value:.4f}")
354
+
print("***")
290
355
```
291
356
292
357
- Minimum/maximum position size: it may be the case that you want no security to form more than 10% of your portfolio. This is easy to encode:
293
358
294
-
```python
295
-
>>> ef = EfficientFrontier(mu, S, weight_bounds=(0, 0.1))
359
+
<!--pytest-codeblocks:cont-->
296
360
361
+
```python
362
+
ef = EfficientFrontier(mu, S, weight_bounds=(0, 0.1))
297
363
```
298
364
299
365
One issue with mean-variance optimization is that it leads to many zero-weights. While these are
300
366
"optimal" in-sample, there is a large body of research showing that this characteristic leads
301
367
mean-variance portfolios to underperform out-of-sample. To that end, I have introduced an
302
368
objective function that can reduce the number of negligible weights for any of the objective functions. Essentially, it adds a penalty (parameterised by `gamma`) on small weights, with a term that looks just like L2 regularisation in machine learning. It may be necessary to try several `gamma` values to achieve the desired number of non-negligible weights. For the test portfolio of 20 securities, `gamma ~ 1` is sufficient
@@ -338,38 +386,20 @@ posterior estimate. This results in much better estimates of expected returns th
338
386
the mean historical return. Check out the [docs](https://pyportfolioopt.readthedocs.io/en/latest/BlackLitterman.html) for a discussion of the theory, as well as advice
0 commit comments