skfolio 0.9.1__py3-none-any.whl → 0.10.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- skfolio/distribution/multivariate/_vine_copula.py +35 -34
- skfolio/distribution/univariate/_base.py +20 -15
- skfolio/exceptions.py +5 -0
- skfolio/measures/__init__.py +2 -0
- skfolio/measures/_measures.py +392 -155
- skfolio/optimization/_base.py +21 -4
- skfolio/optimization/cluster/hierarchical/_base.py +16 -13
- skfolio/optimization/cluster/hierarchical/_herc.py +6 -6
- skfolio/optimization/cluster/hierarchical/_hrp.py +8 -6
- skfolio/optimization/convex/_base.py +238 -144
- skfolio/optimization/convex/_distributionally_robust.py +32 -20
- skfolio/optimization/convex/_maximum_diversification.py +15 -15
- skfolio/optimization/convex/_mean_risk.py +26 -24
- skfolio/optimization/convex/_risk_budgeting.py +23 -21
- skfolio/optimization/ensemble/__init__.py +2 -4
- skfolio/optimization/ensemble/_stacking.py +1 -1
- skfolio/optimization/naive/_naive.py +2 -2
- skfolio/population/_population.py +30 -9
- skfolio/portfolio/_base.py +68 -26
- skfolio/portfolio/_multi_period_portfolio.py +5 -0
- skfolio/portfolio/_portfolio.py +5 -0
- skfolio/prior/__init__.py +6 -2
- skfolio/prior/_base.py +7 -3
- skfolio/prior/_black_litterman.py +14 -12
- skfolio/prior/_empirical.py +8 -7
- skfolio/prior/_entropy_pooling.py +1493 -0
- skfolio/prior/_factor_model.py +39 -22
- skfolio/prior/_opinion_pooling.py +475 -0
- skfolio/prior/_synthetic_data.py +10 -8
- skfolio/uncertainty_set/_bootstrap.py +4 -4
- skfolio/uncertainty_set/_empirical.py +6 -6
- skfolio/utils/equations.py +10 -4
- skfolio/utils/figure.py +185 -0
- skfolio/utils/tools.py +4 -2
- {skfolio-0.9.1.dist-info → skfolio-0.10.1.dist-info}/METADATA +105 -14
- {skfolio-0.9.1.dist-info → skfolio-0.10.1.dist-info}/RECORD +40 -38
- {skfolio-0.9.1.dist-info → skfolio-0.10.1.dist-info}/WHEEL +1 -1
- skfolio/synthetic_returns/__init__.py +0 -1
- /skfolio/{optimization/ensemble/_base.py → utils/composition.py} +0 -0
- {skfolio-0.9.1.dist-info → skfolio-0.10.1.dist-info}/licenses/LICENSE +0 -0
- {skfolio-0.9.1.dist-info → skfolio-0.10.1.dist-info}/top_level.txt +0 -0
@@ -23,7 +23,7 @@ from cvxpy.reductions.solvers.defines import MI_SOLVERS
|
|
23
23
|
import skfolio.typing as skt
|
24
24
|
from skfolio.measures import RiskMeasure, owa_gmd_weights
|
25
25
|
from skfolio.optimization._base import BaseOptimization
|
26
|
-
from skfolio.prior import BasePrior,
|
26
|
+
from skfolio.prior import BasePrior, ReturnDistribution
|
27
27
|
from skfolio.uncertainty_set import (
|
28
28
|
BaseCovarianceUncertaintySet,
|
29
29
|
BaseMuUncertaintySet,
|
@@ -96,7 +96,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
96
96
|
|
97
97
|
prior_estimator : BasePrior, optional
|
98
98
|
:ref:`Prior estimator <prior>`.
|
99
|
-
The prior estimator is used to estimate the :class:`~skfolio.prior.
|
99
|
+
The prior estimator is used to estimate the :class:`~skfolio.prior.ReturnDistribution`
|
100
100
|
containing the estimation of assets expected returns, covariance matrix,
|
101
101
|
returns and Cholesky decomposition of the covariance.
|
102
102
|
The default (`None`) is to use :class:`~skfolio.prior.EmpiricalPrior`.
|
@@ -227,7 +227,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
227
227
|
needs to be homogenous to the periodicity of :math:`\mu`. For example, if
|
228
228
|
the input `X` is composed of **daily** returns, the `transaction_costs` need
|
229
229
|
to be expressed as **daily** costs.
|
230
|
-
(See :ref:`
|
230
|
+
(See :ref:`sphx_glr_auto_examples_mean_risk_plot_6_transaction_costs.py`)
|
231
231
|
|
232
232
|
management_fees : float | dict[str, float] | array-like of shape (n_assets, ), default=0.0
|
233
233
|
Management fees of the assets. It is used to add linear management fees to the
|
@@ -319,23 +319,23 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
319
319
|
Linear constraints.
|
320
320
|
The linear constraints must match any of following patterns:
|
321
321
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
322
|
+
* `"ref1 >= a"`
|
323
|
+
* `"ref1 == b"`
|
324
|
+
* `"ref1 >= ref1"`
|
325
|
+
* `"a * ref1 + b * ref2 + c <= d * ref3"`
|
326
326
|
|
327
|
-
With "ref1"
|
327
|
+
With `"ref1"`, `"ref2"` ... the assets names or the groups names provided
|
328
328
|
in the parameter `groups`. Assets names can be referenced without the need of
|
329
329
|
`groups` if the input `X` of the `fit` method is a DataFrame with these
|
330
330
|
assets names in columns.
|
331
331
|
|
332
332
|
For example:
|
333
333
|
|
334
|
-
* "SPX >= 0.10" --> SPX weight must be greater than 10% (note that you can also use `min_weights`)
|
335
|
-
* "SX5E + TLT >= 0.2" --> the sum of SX5E and TLT weights must be greater than 20%
|
336
|
-
* "US == 0.7" --> the sum of all US weights must be equal to 70%
|
337
|
-
* "Equity == 3 * Bond" --> the sum of all Equity weights must be equal to 3 times the sum of all Bond weights.
|
338
|
-
* "2*SPX + 3*Europe <= Bond + 0.05" --> mixing assets and group constraints
|
334
|
+
* `"SPX >= 0.10"` --> SPX weight must be greater than 10% (note that you can also use `min_weights`)
|
335
|
+
* `"SX5E + TLT >= 0.2"` --> the sum of SX5E and TLT weights must be greater than 20%
|
336
|
+
* `"US == 0.7"` --> the sum of all US weights must be equal to 70%
|
337
|
+
* `"Equity == 3 * Bond"` --> the sum of all Equity weights must be equal to 3 times the sum of all Bond weights.
|
338
|
+
* `"2*SPX + 3*Europe <= Bond + 0.05"` --> mixing assets and group constraints
|
339
339
|
|
340
340
|
groups : dict[str, list[str]] or array-like of shape (n_groups, n_assets), optional
|
341
341
|
The assets groups referenced in `linear_constraints`.
|
@@ -345,8 +345,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
345
345
|
|
346
346
|
For example:
|
347
347
|
|
348
|
-
* groups = {"SX5E": ["Equity", "Europe"], "SPX": ["Equity", "US"], "TLT": ["Bond", "US"]}
|
349
|
-
* groups = [["Equity", "Equity", "Bond"], ["Europe", "US", "US"]]
|
348
|
+
* `groups = {"SX5E": ["Equity", "Europe"], "SPX": ["Equity", "US"], "TLT": ["Bond", "US"]}`
|
349
|
+
* `groups = [["Equity", "Equity", "Bond"], ["Europe", "US", "US"]]`
|
350
350
|
|
351
351
|
left_inequality : array-like of shape (n_constraints, n_assets), optional
|
352
352
|
Left inequality matrix :math:`A` of the linear
|
@@ -1035,11 +1035,11 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1035
1035
|
|
1036
1036
|
@cache_method("_cvx_cache")
|
1037
1037
|
def _cvx_expected_return(
|
1038
|
-
self,
|
1038
|
+
self, return_distribution: ReturnDistribution, w: cp.Variable
|
1039
1039
|
) -> cp.Expression:
|
1040
1040
|
"""Expected Return expression."""
|
1041
1041
|
if self.overwrite_expected_return is None:
|
1042
|
-
expected_return =
|
1042
|
+
expected_return = return_distribution.mu @ w
|
1043
1043
|
else:
|
1044
1044
|
expected_return = self._call_custom_func(
|
1045
1045
|
func=self.overwrite_expected_return,
|
@@ -1235,14 +1235,17 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1235
1235
|
|
1236
1236
|
@cache_method("_cvx_cache")
|
1237
1237
|
def _cvx_transaction_cost(
|
1238
|
-
self,
|
1238
|
+
self,
|
1239
|
+
return_distribution: ReturnDistribution,
|
1240
|
+
w: cp.Variable,
|
1241
|
+
factor: skt.Factor,
|
1239
1242
|
) -> cp.Expression:
|
1240
1243
|
"""Transaction cost expression.
|
1241
1244
|
|
1242
1245
|
Parameters
|
1243
1246
|
----------
|
1244
|
-
|
1245
|
-
|
1247
|
+
return_distribution : ReturnDistribution
|
1248
|
+
asset returns distribution DataModel.
|
1246
1249
|
|
1247
1250
|
w : cvxpy Variable
|
1248
1251
|
The CVXPY Variable representing assets weights.
|
@@ -1256,7 +1259,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1256
1259
|
expression : cvxpy Expression
|
1257
1260
|
The CVXPY Expression of transaction cost.
|
1258
1261
|
"""
|
1259
|
-
n_assets =
|
1262
|
+
n_assets = return_distribution.returns.shape[1]
|
1260
1263
|
|
1261
1264
|
transaction_costs = self._clean_input(
|
1262
1265
|
self.transaction_costs,
|
@@ -1285,14 +1288,14 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1285
1288
|
|
1286
1289
|
@cache_method("_cvx_cache")
|
1287
1290
|
def _cvx_management_fee(
|
1288
|
-
self,
|
1291
|
+
self, return_distribution: ReturnDistribution, w: cp.Variable
|
1289
1292
|
) -> cp.Expression:
|
1290
1293
|
"""Management fee expression.
|
1291
1294
|
|
1292
1295
|
Parameters
|
1293
1296
|
----------
|
1294
|
-
|
1295
|
-
|
1297
|
+
return_distribution : ReturnDistribution
|
1298
|
+
asset returns distribution DataModel.
|
1296
1299
|
|
1297
1300
|
w : cvxpy Variable
|
1298
1301
|
The CVXPY Variable representing assets weights.
|
@@ -1302,7 +1305,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1302
1305
|
expression : cvxpy Expression
|
1303
1306
|
The CVXPY Expression of management fee .
|
1304
1307
|
"""
|
1305
|
-
n_assets =
|
1308
|
+
n_assets = return_distribution.returns.shape[1]
|
1306
1309
|
|
1307
1310
|
management_fees = self._clean_input(
|
1308
1311
|
self.management_fees,
|
@@ -1318,13 +1321,15 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1318
1321
|
return management_fees @ w
|
1319
1322
|
|
1320
1323
|
@cache_method("_cvx_cache")
|
1321
|
-
def _cvx_returns(
|
1324
|
+
def _cvx_returns(
|
1325
|
+
self, return_distribution: ReturnDistribution, w: cp.Variable
|
1326
|
+
) -> cp.Expression:
|
1322
1327
|
"""Expression of the portfolio returns series.
|
1323
1328
|
|
1324
1329
|
Parameters
|
1325
1330
|
----------
|
1326
|
-
|
1327
|
-
|
1331
|
+
return_distribution : ReturnDistribution
|
1332
|
+
asset returns distribution DataModel.
|
1328
1333
|
|
1329
1334
|
w : cvxpy Variable
|
1330
1335
|
The CVXPY Variable representing assets weights.
|
@@ -1334,7 +1339,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1334
1339
|
expression : cvxpy Expression
|
1335
1340
|
The CVXPY Expression the portfolio returns series.
|
1336
1341
|
"""
|
1337
|
-
returns =
|
1342
|
+
returns = return_distribution.returns @ w
|
1338
1343
|
return returns
|
1339
1344
|
|
1340
1345
|
@cache_method("_cvx_cache")
|
@@ -1379,7 +1384,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1379
1384
|
@cache_method("_cvx_cache")
|
1380
1385
|
def _cvx_min_acceptable_return(
|
1381
1386
|
self,
|
1382
|
-
|
1387
|
+
return_distribution: ReturnDistribution,
|
1383
1388
|
w: cp.Variable,
|
1384
1389
|
min_acceptable_return: skt.Target = None,
|
1385
1390
|
) -> cp.Expression:
|
@@ -1387,8 +1392,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1387
1392
|
|
1388
1393
|
Parameters
|
1389
1394
|
----------
|
1390
|
-
|
1391
|
-
|
1395
|
+
return_distribution : ReturnDistribution
|
1396
|
+
asset returns distribution DataModel..
|
1392
1397
|
|
1393
1398
|
w : cvxpy Variable
|
1394
1399
|
The CVXPY Variable representing assets weights.
|
@@ -1403,25 +1408,28 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1403
1408
|
The CVXPY Expression the portfolio Minimum Acceptable Returns.
|
1404
1409
|
"""
|
1405
1410
|
if min_acceptable_return is None:
|
1406
|
-
min_acceptable_return =
|
1411
|
+
min_acceptable_return = return_distribution.mu
|
1407
1412
|
if not np.isscalar(min_acceptable_return) and min_acceptable_return.shape != (
|
1408
1413
|
len(min_acceptable_return),
|
1409
1414
|
1,
|
1410
1415
|
):
|
1411
1416
|
min_acceptable_return = min_acceptable_return[np.newaxis, :]
|
1412
|
-
mar = (
|
1417
|
+
mar = (return_distribution.returns - min_acceptable_return) @ w
|
1413
1418
|
return mar
|
1414
1419
|
|
1415
1420
|
@cache_method("_cvx_cache")
|
1416
1421
|
def __cvx_drawdown(
|
1417
|
-
self,
|
1422
|
+
self,
|
1423
|
+
return_distribution: ReturnDistribution,
|
1424
|
+
w: cp.Variable,
|
1425
|
+
factor: skt.Factor,
|
1418
1426
|
) -> tuple[cp.Variable, list[cp.Expression]]:
|
1419
1427
|
"""Expression of the portfolio drawdown.
|
1420
1428
|
|
1421
1429
|
Parameters
|
1422
1430
|
----------
|
1423
|
-
|
1424
|
-
|
1431
|
+
return_distribution : ReturnDistribution
|
1432
|
+
asset returns distribution DataModel.
|
1425
1433
|
|
1426
1434
|
w : cvxpy Variable
|
1427
1435
|
The CVXPY Variable representing assets weights.
|
@@ -1435,12 +1443,14 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1435
1443
|
expression : cvxpy Expression
|
1436
1444
|
The CVXPY Expression the portfolio drawdown.
|
1437
1445
|
"""
|
1438
|
-
n_observations =
|
1439
|
-
ptf_returns = self._cvx_returns(
|
1446
|
+
n_observations = return_distribution.returns.shape[0]
|
1447
|
+
ptf_returns = self._cvx_returns(return_distribution=return_distribution, w=w)
|
1440
1448
|
ptf_transaction_cost = self._cvx_transaction_cost(
|
1441
|
-
|
1449
|
+
return_distribution=return_distribution, w=w, factor=factor
|
1450
|
+
)
|
1451
|
+
ptf_management_fee = self._cvx_management_fee(
|
1452
|
+
return_distribution=return_distribution, w=w
|
1442
1453
|
)
|
1443
|
-
ptf_management_fee = self._cvx_management_fee(prior_model=prior_model, w=w)
|
1444
1454
|
v = cp.Variable(n_observations + 1)
|
1445
1455
|
constraints = [
|
1446
1456
|
v[1:] * self._scale_constraints
|
@@ -1454,7 +1464,10 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1454
1464
|
return v, constraints
|
1455
1465
|
|
1456
1466
|
def _cvx_drawdown(
|
1457
|
-
self,
|
1467
|
+
self,
|
1468
|
+
return_distribution: ReturnDistribution,
|
1469
|
+
w: cp.Variable,
|
1470
|
+
factor: skt.Factor,
|
1458
1471
|
) -> tuple[cp.Variable, list[cp.Expression]]:
|
1459
1472
|
"""Expression of the portfolio drawdown.
|
1460
1473
|
Wrapper around __cvx_drawdown to avoid re-adding the constraints when they
|
@@ -1462,8 +1475,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1462
1475
|
|
1463
1476
|
Parameters
|
1464
1477
|
----------
|
1465
|
-
|
1466
|
-
|
1478
|
+
return_distribution : ReturnDistribution
|
1479
|
+
asset returns distribution DataModel.
|
1467
1480
|
|
1468
1481
|
w : cvxpy Variable
|
1469
1482
|
The CVXPY Variable representing assets weights.
|
@@ -1478,19 +1491,27 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1478
1491
|
The CVXPY Expression the portfolio drawdown.
|
1479
1492
|
"""
|
1480
1493
|
if "__cvx_drawdown" in self._cvx_cache:
|
1481
|
-
v, _ = self.__cvx_drawdown(
|
1494
|
+
v, _ = self.__cvx_drawdown(
|
1495
|
+
return_distribution=return_distribution, w=w, factor=factor
|
1496
|
+
)
|
1482
1497
|
return v, []
|
1483
|
-
return self.__cvx_drawdown(
|
1498
|
+
return self.__cvx_drawdown(
|
1499
|
+
return_distribution=return_distribution, w=w, factor=factor
|
1500
|
+
)
|
1484
1501
|
|
1485
1502
|
def _tracking_error(
|
1486
|
-
self,
|
1503
|
+
self,
|
1504
|
+
return_distribution: ReturnDistribution,
|
1505
|
+
w: cp.Variable,
|
1506
|
+
y: np.ndarray,
|
1507
|
+
factor: skt.Factor,
|
1487
1508
|
) -> cp.Expression:
|
1488
1509
|
"""Expression of the portfolio tracking error.
|
1489
1510
|
|
1490
1511
|
Parameters
|
1491
1512
|
----------
|
1492
|
-
|
1493
|
-
|
1513
|
+
return_distribution : ReturnDistribution
|
1514
|
+
asset returns distribution DataModel.
|
1494
1515
|
|
1495
1516
|
w : cvxpy Variable
|
1496
1517
|
The CVXPY Variable representing assets weights.
|
@@ -1507,8 +1528,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1507
1528
|
expression : cvxpy Expression
|
1508
1529
|
The CVXPY Expression the portfolio tracking error.
|
1509
1530
|
"""
|
1510
|
-
n_observations =
|
1511
|
-
ptf_returns = self._cvx_returns(
|
1531
|
+
n_observations = return_distribution.returns.shape[0]
|
1532
|
+
ptf_returns = self._cvx_returns(return_distribution=return_distribution, w=w)
|
1512
1533
|
tracking_error = cp.norm(ptf_returns - y * factor, "fro") / cp.sqrt(
|
1513
1534
|
n_observations - 1
|
1514
1535
|
)
|
@@ -1518,14 +1539,17 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1518
1539
|
# They need to be named f'_{risk_measure}_risk' as they are loaded dynamically in
|
1519
1540
|
# mean_risk_optimization()
|
1520
1541
|
def _mean_absolute_deviation_risk(
|
1521
|
-
self,
|
1542
|
+
self,
|
1543
|
+
return_distribution: ReturnDistribution,
|
1544
|
+
w: cp.Variable,
|
1545
|
+
min_acceptable_return: skt.Target,
|
1522
1546
|
) -> skt.RiskResult:
|
1523
1547
|
"""Expression and Constraints of the Mean Absolute Deviation risk measure.
|
1524
1548
|
|
1525
1549
|
Parameters
|
1526
1550
|
----------
|
1527
|
-
|
1528
|
-
|
1551
|
+
return_distribution : ReturnDistribution
|
1552
|
+
asset returns distribution DataModel.
|
1529
1553
|
|
1530
1554
|
w : cvxpy Variable
|
1531
1555
|
The CVXPY Variable representing assets weights.
|
@@ -1540,12 +1564,19 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1540
1564
|
CVXPY Expression and Constraints of the Mean Absolute Deviation risk
|
1541
1565
|
measure.
|
1542
1566
|
"""
|
1543
|
-
n_observations =
|
1567
|
+
n_observations = return_distribution.returns.shape[0]
|
1544
1568
|
ptf_min_acceptable_return = self._cvx_min_acceptable_return(
|
1545
|
-
|
1569
|
+
return_distribution=return_distribution,
|
1570
|
+
w=w,
|
1571
|
+
min_acceptable_return=min_acceptable_return,
|
1546
1572
|
)
|
1547
1573
|
v = cp.Variable(n_observations, nonneg=True)
|
1548
|
-
|
1574
|
+
|
1575
|
+
if return_distribution.sample_weight is None:
|
1576
|
+
risk = 2 * cp.sum(v) / n_observations
|
1577
|
+
else:
|
1578
|
+
risk = 2 * cp.sum(cp.multiply(return_distribution.sample_weight, v))
|
1579
|
+
|
1549
1580
|
constraints = [
|
1550
1581
|
ptf_min_acceptable_return * self._scale_constraints
|
1551
1582
|
>= -v * self._scale_constraints
|
@@ -1554,7 +1585,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1554
1585
|
|
1555
1586
|
def _first_lower_partial_moment_risk(
|
1556
1587
|
self,
|
1557
|
-
|
1588
|
+
return_distribution: ReturnDistribution,
|
1558
1589
|
w: cp.Variable,
|
1559
1590
|
min_acceptable_return: skt.Target,
|
1560
1591
|
factor: skt.Factor,
|
@@ -1563,8 +1594,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1563
1594
|
|
1564
1595
|
Parameters
|
1565
1596
|
----------
|
1566
|
-
|
1567
|
-
|
1597
|
+
return_distribution : ReturnDistribution
|
1598
|
+
asset returns distribution DataModel.
|
1568
1599
|
|
1569
1600
|
w : cvxpy Variable
|
1570
1601
|
The CVXPY Variable representing assets weights.
|
@@ -1583,12 +1614,19 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1583
1614
|
CVXPY Expression and Constraints of the First Lower Partial Moment risk
|
1584
1615
|
measure.
|
1585
1616
|
"""
|
1586
|
-
n_observations =
|
1617
|
+
n_observations = return_distribution.returns.shape[0]
|
1587
1618
|
ptf_min_acceptable_return = self._cvx_min_acceptable_return(
|
1588
|
-
|
1619
|
+
return_distribution=return_distribution,
|
1620
|
+
w=w,
|
1621
|
+
min_acceptable_return=min_acceptable_return,
|
1589
1622
|
)
|
1590
1623
|
v = cp.Variable(n_observations, nonneg=True)
|
1591
|
-
|
1624
|
+
|
1625
|
+
if return_distribution.sample_weight is None:
|
1626
|
+
risk = cp.sum(v) / n_observations
|
1627
|
+
else:
|
1628
|
+
risk = cp.sum(cp.multiply(return_distribution.sample_weight, v))
|
1629
|
+
|
1592
1630
|
constraints = [
|
1593
1631
|
self.risk_free_rate * factor * self._scale_constraints
|
1594
1632
|
- ptf_min_acceptable_return * self._scale_constraints
|
@@ -1597,14 +1635,14 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1597
1635
|
return risk, constraints
|
1598
1636
|
|
1599
1637
|
def _standard_deviation_risk(
|
1600
|
-
self,
|
1638
|
+
self, return_distribution: ReturnDistribution, w: cp.Variable
|
1601
1639
|
) -> skt.RiskResult:
|
1602
1640
|
"""Expression and Constraints of the Standard Deviation risk measure.
|
1603
1641
|
|
1604
1642
|
Parameters
|
1605
1643
|
----------
|
1606
|
-
|
1607
|
-
|
1644
|
+
return_distribution : ReturnDistribution
|
1645
|
+
asset returns distribution DataModel.
|
1608
1646
|
|
1609
1647
|
w : cvxpy Variable
|
1610
1648
|
The CVXPY Variable representing assets weights.
|
@@ -1617,23 +1655,25 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1617
1655
|
v = cp.Variable(
|
1618
1656
|
nonneg=True
|
1619
1657
|
) # nonneg=True instead of constraint v>=0 is preferred for better DCP analysis
|
1620
|
-
if
|
1621
|
-
z =
|
1658
|
+
if return_distribution.cholesky is not None:
|
1659
|
+
z = return_distribution.cholesky
|
1622
1660
|
else:
|
1623
|
-
z = np.linalg.cholesky(
|
1661
|
+
z = np.linalg.cholesky(return_distribution.covariance)
|
1624
1662
|
risk = v
|
1625
1663
|
constraints = [
|
1626
1664
|
cp.SOC(v * self._scale_constraints, z.T @ w * self._scale_constraints)
|
1627
1665
|
]
|
1628
1666
|
return risk, constraints
|
1629
1667
|
|
1630
|
-
def _variance_risk(
|
1668
|
+
def _variance_risk(
|
1669
|
+
self, return_distribution: ReturnDistribution, w: cp.Variable
|
1670
|
+
) -> skt.RiskResult:
|
1631
1671
|
"""Expression and Constraints of the Variance risk measure.
|
1632
1672
|
|
1633
1673
|
Parameters
|
1634
1674
|
----------
|
1635
|
-
|
1636
|
-
|
1675
|
+
return_distribution : ReturnDistribution
|
1676
|
+
asset returns distribution DataModel.
|
1637
1677
|
|
1638
1678
|
w : cvxpy Variable
|
1639
1679
|
The CVXPY Variable representing assets weights.
|
@@ -1643,13 +1683,15 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1643
1683
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
1644
1684
|
CVXPY Expression and Constraints the Variance risk measure.
|
1645
1685
|
"""
|
1646
|
-
risk, constraints = self._standard_deviation_risk(
|
1686
|
+
risk, constraints = self._standard_deviation_risk(
|
1687
|
+
return_distribution=return_distribution, w=w
|
1688
|
+
)
|
1647
1689
|
risk = cp.square(risk)
|
1648
1690
|
return risk, constraints
|
1649
1691
|
|
1650
1692
|
def _worst_case_variance_risk(
|
1651
1693
|
self,
|
1652
|
-
|
1694
|
+
return_distribution: ReturnDistribution,
|
1653
1695
|
covariance_uncertainty_set: UncertaintySet,
|
1654
1696
|
w: cp.Variable,
|
1655
1697
|
factor: skt.Factor,
|
@@ -1658,8 +1700,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1658
1700
|
|
1659
1701
|
Parameters
|
1660
1702
|
----------
|
1661
|
-
|
1662
|
-
|
1703
|
+
return_distribution : ReturnDistribution
|
1704
|
+
asset returns distribution DataModel.
|
1663
1705
|
|
1664
1706
|
covariance_uncertainty_set : UncertaintySet
|
1665
1707
|
:ref:`Covariance Uncertainty set estimator <uncertainty_set_estimator>`.
|
@@ -1676,7 +1718,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1676
1718
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
1677
1719
|
CVXPY Expression and Constraints the Worst Case Variance.
|
1678
1720
|
"""
|
1679
|
-
n_assets =
|
1721
|
+
n_assets = return_distribution.returns.shape[1]
|
1680
1722
|
x = cp.Variable((n_assets, n_assets), symmetric=True)
|
1681
1723
|
y = cp.Variable((n_assets, n_assets), symmetric=True)
|
1682
1724
|
w_reshaped = cp.reshape(w, (n_assets, 1), order="F")
|
@@ -1688,9 +1730,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1688
1730
|
sc.linalg.sqrtm(covariance_uncertainty_set.sigma)
|
1689
1731
|
@ (cp.vec(x, order="F") + cp.vec(y, order="F")),
|
1690
1732
|
2,
|
1691
|
-
) + cp.trace(
|
1733
|
+
) + cp.trace(return_distribution.covariance @ (x + y))
|
1692
1734
|
# semi-definite positive constraints
|
1693
|
-
# noinspection PyTypeChecker
|
1694
1735
|
constraints = [
|
1695
1736
|
cp.hstack([z1, z2]) * self._scale_constraints >> 0,
|
1696
1737
|
y * self._scale_constraints >> 0,
|
@@ -1699,7 +1740,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1699
1740
|
|
1700
1741
|
def _semi_variance_risk(
|
1701
1742
|
self,
|
1702
|
-
|
1743
|
+
return_distribution: ReturnDistribution,
|
1703
1744
|
w: cp.Variable,
|
1704
1745
|
min_acceptable_return: skt.Target = None,
|
1705
1746
|
) -> skt.RiskResult:
|
@@ -1707,8 +1748,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1707
1748
|
|
1708
1749
|
Parameters
|
1709
1750
|
----------
|
1710
|
-
|
1711
|
-
|
1751
|
+
return_distribution : ReturnDistribution
|
1752
|
+
asset returns distribution DataModel.
|
1712
1753
|
|
1713
1754
|
w : cvxpy Variable
|
1714
1755
|
The CVXPY Variable representing assets weights.
|
@@ -1722,12 +1763,21 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1722
1763
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
1723
1764
|
CVXPY Expression and Constraints the Semi Variance risk measure.
|
1724
1765
|
"""
|
1725
|
-
n_observations =
|
1766
|
+
n_observations = return_distribution.returns.shape[0]
|
1726
1767
|
ptf_min_acceptable_return = self._cvx_min_acceptable_return(
|
1727
|
-
|
1768
|
+
return_distribution=return_distribution,
|
1769
|
+
w=w,
|
1770
|
+
min_acceptable_return=min_acceptable_return,
|
1728
1771
|
)
|
1729
1772
|
v = cp.Variable(n_observations, nonneg=True)
|
1730
|
-
|
1773
|
+
|
1774
|
+
if return_distribution.sample_weight is None:
|
1775
|
+
risk = cp.sum_squares(v) / (n_observations - 1)
|
1776
|
+
else:
|
1777
|
+
risk = cp.sum_squares(
|
1778
|
+
cp.multiply(np.sqrt(return_distribution.sample_weight), v)
|
1779
|
+
)
|
1780
|
+
|
1731
1781
|
constraints = [
|
1732
1782
|
ptf_min_acceptable_return * self._scale_constraints
|
1733
1783
|
>= -v * self._scale_constraints
|
@@ -1736,7 +1786,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1736
1786
|
|
1737
1787
|
def _semi_deviation_risk(
|
1738
1788
|
self,
|
1739
|
-
|
1789
|
+
return_distribution: ReturnDistribution,
|
1740
1790
|
w: cp.Variable,
|
1741
1791
|
min_acceptable_return: skt.Target = None,
|
1742
1792
|
) -> skt.RiskResult:
|
@@ -1744,8 +1794,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1744
1794
|
|
1745
1795
|
Parameters
|
1746
1796
|
----------
|
1747
|
-
|
1748
|
-
|
1797
|
+
return_distribution : ReturnDistribution
|
1798
|
+
asset returns distribution DataModel.
|
1749
1799
|
|
1750
1800
|
w : cvxpy Variable
|
1751
1801
|
The CVXPY Variable representing assets weights.
|
@@ -1759,12 +1809,21 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1759
1809
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
1760
1810
|
CVXPY Expression and Constraints the Semi Standard Deviation risk measure.
|
1761
1811
|
"""
|
1762
|
-
n_observations =
|
1812
|
+
n_observations = return_distribution.returns.shape[0]
|
1763
1813
|
ptf_min_acceptable_return = self._cvx_min_acceptable_return(
|
1764
|
-
|
1814
|
+
return_distribution=return_distribution,
|
1815
|
+
w=w,
|
1816
|
+
min_acceptable_return=min_acceptable_return,
|
1765
1817
|
)
|
1766
1818
|
v = cp.Variable(n_observations, nonneg=True)
|
1767
|
-
|
1819
|
+
|
1820
|
+
if return_distribution.sample_weight is None:
|
1821
|
+
risk = cp.norm(v, 2) / np.sqrt(n_observations - 1)
|
1822
|
+
else:
|
1823
|
+
risk = cp.norm(
|
1824
|
+
cp.multiply(np.sqrt(return_distribution.sample_weight), v), 2
|
1825
|
+
)
|
1826
|
+
|
1768
1827
|
constraints = [
|
1769
1828
|
ptf_min_acceptable_return * self._scale_constraints
|
1770
1829
|
>= -v * self._scale_constraints
|
@@ -1778,14 +1837,17 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1778
1837
|
raise NotImplementedError
|
1779
1838
|
|
1780
1839
|
def _worst_realization_risk(
|
1781
|
-
self,
|
1840
|
+
self,
|
1841
|
+
return_distribution: ReturnDistribution,
|
1842
|
+
w: cp.Variable,
|
1843
|
+
factor: skt.Factor,
|
1782
1844
|
) -> skt.RiskResult:
|
1783
1845
|
"""Expression and Constraints of the Worst Realization risk measure.
|
1784
1846
|
|
1785
1847
|
Parameters
|
1786
1848
|
----------
|
1787
|
-
|
1788
|
-
|
1849
|
+
return_distribution : ReturnDistribution
|
1850
|
+
asset returns distribution DataModel.
|
1789
1851
|
|
1790
1852
|
w : cvxpy Variable
|
1791
1853
|
The CVXPY Variable representing assets weights.
|
@@ -1799,11 +1861,13 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1799
1861
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
1800
1862
|
CVXPY Expression and Constraints the Worst Realization risk measure.
|
1801
1863
|
"""
|
1802
|
-
ptf_returns = self._cvx_returns(
|
1864
|
+
ptf_returns = self._cvx_returns(return_distribution=return_distribution, w=w)
|
1803
1865
|
ptf_transaction_cost = self._cvx_transaction_cost(
|
1804
|
-
|
1866
|
+
return_distribution=return_distribution, w=w, factor=factor
|
1867
|
+
)
|
1868
|
+
ptf_management_fee = self._cvx_management_fee(
|
1869
|
+
return_distribution=return_distribution, w=w
|
1805
1870
|
)
|
1806
|
-
ptf_management_fee = self._cvx_management_fee(prior_model=prior_model, w=w)
|
1807
1871
|
v = cp.Variable()
|
1808
1872
|
risk = v
|
1809
1873
|
constraints = [
|
@@ -1816,7 +1880,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1816
1880
|
|
1817
1881
|
def _cvar_risk(
|
1818
1882
|
self,
|
1819
|
-
|
1883
|
+
return_distribution: ReturnDistribution,
|
1820
1884
|
w: cp.Variable,
|
1821
1885
|
factor: skt.Factor,
|
1822
1886
|
) -> skt.RiskResult:
|
@@ -1824,8 +1888,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1824
1888
|
|
1825
1889
|
Parameters
|
1826
1890
|
----------
|
1827
|
-
|
1828
|
-
|
1891
|
+
return_distribution : ReturnDistribution
|
1892
|
+
asset returns distribution DataModel.
|
1829
1893
|
|
1830
1894
|
w : cvxpy Variable
|
1831
1895
|
The CVXPY Variable representing assets weights.
|
@@ -1839,16 +1903,23 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1839
1903
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
1840
1904
|
CVXPY Expression and Constraints the CVaR risk measure.
|
1841
1905
|
"""
|
1842
|
-
n_observations =
|
1843
|
-
ptf_returns = self._cvx_returns(
|
1906
|
+
n_observations = return_distribution.returns.shape[0]
|
1907
|
+
ptf_returns = self._cvx_returns(return_distribution=return_distribution, w=w)
|
1844
1908
|
ptf_transaction_cost = self._cvx_transaction_cost(
|
1845
|
-
|
1909
|
+
return_distribution=return_distribution, w=w, factor=factor
|
1910
|
+
)
|
1911
|
+
ptf_management_fee = self._cvx_management_fee(
|
1912
|
+
return_distribution=return_distribution, w=w
|
1846
1913
|
)
|
1847
|
-
ptf_management_fee = self._cvx_management_fee(prior_model=prior_model, w=w)
|
1848
1914
|
alpha = cp.Variable()
|
1849
1915
|
v = cp.Variable(n_observations, nonneg=True)
|
1850
|
-
|
1851
|
-
|
1916
|
+
if return_distribution.sample_weight is None:
|
1917
|
+
risk = alpha + cp.sum(v) / (n_observations * (1 - self.cvar_beta))
|
1918
|
+
else:
|
1919
|
+
risk = alpha + cp.sum(cp.multiply(return_distribution.sample_weight, v)) / (
|
1920
|
+
1 - self.cvar_beta
|
1921
|
+
)
|
1922
|
+
|
1852
1923
|
constraints = [
|
1853
1924
|
ptf_returns * self._scale_constraints
|
1854
1925
|
- ptf_transaction_cost * self._scale_constraints
|
@@ -1861,7 +1932,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1861
1932
|
|
1862
1933
|
def _evar_risk(
|
1863
1934
|
self,
|
1864
|
-
|
1935
|
+
return_distribution: ReturnDistribution,
|
1865
1936
|
w: cp.Variable,
|
1866
1937
|
factor: skt.Factor,
|
1867
1938
|
) -> skt.RiskResult:
|
@@ -1869,8 +1940,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1869
1940
|
|
1870
1941
|
Parameters
|
1871
1942
|
----------
|
1872
|
-
|
1873
|
-
|
1943
|
+
return_distribution : ReturnDistribution
|
1944
|
+
asset returns distribution DataModel.
|
1874
1945
|
|
1875
1946
|
w : cvxpy Variable
|
1876
1947
|
The CVXPY Variable representing assets weights.
|
@@ -1884,12 +1955,14 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1884
1955
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
1885
1956
|
CVXPY Expression and Constraints the EVaR risk measure.
|
1886
1957
|
"""
|
1887
|
-
n_observations =
|
1888
|
-
ptf_returns = self._cvx_returns(
|
1958
|
+
n_observations = return_distribution.returns.shape[0]
|
1959
|
+
ptf_returns = self._cvx_returns(return_distribution=return_distribution, w=w)
|
1889
1960
|
ptf_transaction_cost = self._cvx_transaction_cost(
|
1890
|
-
|
1961
|
+
return_distribution=return_distribution, w=w, factor=factor
|
1962
|
+
)
|
1963
|
+
ptf_management_fee = self._cvx_management_fee(
|
1964
|
+
return_distribution=return_distribution, w=w
|
1891
1965
|
)
|
1892
|
-
ptf_management_fee = self._cvx_management_fee(prior_model=prior_model, w=w)
|
1893
1966
|
# We don't include the transaction_cost in the constraint otherwise the problem
|
1894
1967
|
# is not DCP
|
1895
1968
|
if not isinstance(ptf_transaction_cost, cp.Constant):
|
@@ -1917,14 +1990,17 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1917
1990
|
return risk, constraints
|
1918
1991
|
|
1919
1992
|
def _max_drawdown_risk(
|
1920
|
-
self,
|
1993
|
+
self,
|
1994
|
+
return_distribution: ReturnDistribution,
|
1995
|
+
w: cp.Variable,
|
1996
|
+
factor: skt.Factor,
|
1921
1997
|
) -> skt.RiskResult:
|
1922
1998
|
"""Expression and Constraints of the EVaR risk measure.
|
1923
1999
|
|
1924
2000
|
Parameters
|
1925
2001
|
----------
|
1926
|
-
|
1927
|
-
|
2002
|
+
return_distribution : ReturnDistribution
|
2003
|
+
asset returns distribution DataModel.
|
1928
2004
|
|
1929
2005
|
w : cvxpy Variable
|
1930
2006
|
The CVXPY Variable representing assets weights.
|
@@ -1938,21 +2014,26 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1938
2014
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
1939
2015
|
CVXPY Expression and Constraints the EVaR risk measure.
|
1940
2016
|
"""
|
1941
|
-
v, constraints = self._cvx_drawdown(
|
2017
|
+
v, constraints = self._cvx_drawdown(
|
2018
|
+
return_distribution=return_distribution, w=w, factor=factor
|
2019
|
+
)
|
1942
2020
|
u = cp.Variable()
|
1943
2021
|
risk = u
|
1944
2022
|
constraints += [u * self._scale_constraints >= v[1:] * self._scale_constraints]
|
1945
2023
|
return risk, constraints
|
1946
2024
|
|
1947
2025
|
def _average_drawdown_risk(
|
1948
|
-
self,
|
2026
|
+
self,
|
2027
|
+
return_distribution: ReturnDistribution,
|
2028
|
+
w: cp.Variable,
|
2029
|
+
factor: skt.Factor,
|
1949
2030
|
) -> skt.RiskResult:
|
1950
2031
|
"""Expression and Constraints of the Average Drawdown risk measure.
|
1951
2032
|
|
1952
2033
|
Parameters
|
1953
2034
|
----------
|
1954
|
-
|
1955
|
-
|
2035
|
+
return_distribution : ReturnDistribution
|
2036
|
+
asset returns distribution DataModel.
|
1956
2037
|
|
1957
2038
|
w : cvxpy Variable
|
1958
2039
|
The CVXPY Variable representing assets weights.
|
@@ -1966,14 +2047,16 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1966
2047
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
1967
2048
|
CVXPY Expression and Constraints the Average Drawdown risk measure.
|
1968
2049
|
"""
|
1969
|
-
n_observations =
|
1970
|
-
v, constraints = self._cvx_drawdown(
|
2050
|
+
n_observations = return_distribution.returns.shape[0]
|
2051
|
+
v, constraints = self._cvx_drawdown(
|
2052
|
+
return_distribution=return_distribution, w=w, factor=factor
|
2053
|
+
)
|
1971
2054
|
risk = cp.sum(v[1:]) / n_observations
|
1972
2055
|
return risk, constraints
|
1973
2056
|
|
1974
2057
|
def _cdar_risk(
|
1975
2058
|
self,
|
1976
|
-
|
2059
|
+
return_distribution: ReturnDistribution,
|
1977
2060
|
w: cp.Variable,
|
1978
2061
|
factor: skt.Factor,
|
1979
2062
|
) -> skt.RiskResult:
|
@@ -1981,8 +2064,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1981
2064
|
|
1982
2065
|
Parameters
|
1983
2066
|
----------
|
1984
|
-
|
1985
|
-
|
2067
|
+
return_distribution : ReturnDistribution
|
2068
|
+
asset returns distribution DataModel.
|
1986
2069
|
|
1987
2070
|
w : cvxpy Variable
|
1988
2071
|
The CVXPY Variable representing assets weights.
|
@@ -1996,8 +2079,10 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
1996
2079
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
1997
2080
|
CVXPY Expression and Constraints the CDaR risk measure.
|
1998
2081
|
"""
|
1999
|
-
n_observations =
|
2000
|
-
v, constraints = self._cvx_drawdown(
|
2082
|
+
n_observations = return_distribution.returns.shape[0]
|
2083
|
+
v, constraints = self._cvx_drawdown(
|
2084
|
+
return_distribution=return_distribution, w=w, factor=factor
|
2085
|
+
)
|
2001
2086
|
alpha = cp.Variable()
|
2002
2087
|
z = cp.Variable(n_observations, nonneg=True)
|
2003
2088
|
risk = alpha + 1.0 / (n_observations * (1 - self.cdar_beta)) * cp.sum(z)
|
@@ -2009,7 +2094,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
2009
2094
|
|
2010
2095
|
def _edar_risk(
|
2011
2096
|
self,
|
2012
|
-
|
2097
|
+
return_distribution: ReturnDistribution,
|
2013
2098
|
w: cp.Variable,
|
2014
2099
|
factor: skt.Factor,
|
2015
2100
|
) -> skt.RiskResult:
|
@@ -2017,8 +2102,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
2017
2102
|
|
2018
2103
|
Parameters
|
2019
2104
|
----------
|
2020
|
-
|
2021
|
-
|
2105
|
+
return_distribution : ReturnDistribution
|
2106
|
+
asset returns distribution DataModel.
|
2022
2107
|
|
2023
2108
|
w : cvxpy Variable
|
2024
2109
|
The CVXPY Variable representing assets weights.
|
@@ -2032,8 +2117,10 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
2032
2117
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
2033
2118
|
CVXPY Expression and Constraints the EDaR risk measure.
|
2034
2119
|
"""
|
2035
|
-
n_observations =
|
2036
|
-
v, constraints = self._cvx_drawdown(
|
2120
|
+
n_observations = return_distribution.returns.shape[0]
|
2121
|
+
v, constraints = self._cvx_drawdown(
|
2122
|
+
return_distribution=return_distribution, w=w, factor=factor
|
2123
|
+
)
|
2037
2124
|
x = cp.Variable()
|
2038
2125
|
y = cp.Variable(nonneg=True)
|
2039
2126
|
z = cp.Variable(n_observations)
|
@@ -2050,7 +2137,7 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
2050
2137
|
|
2051
2138
|
def _ulcer_index_risk(
|
2052
2139
|
self,
|
2053
|
-
|
2140
|
+
return_distribution: ReturnDistribution,
|
2054
2141
|
w: cp.Variable,
|
2055
2142
|
factor: skt.Factor,
|
2056
2143
|
) -> skt.RiskResult:
|
@@ -2058,8 +2145,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
2058
2145
|
|
2059
2146
|
Parameters
|
2060
2147
|
----------
|
2061
|
-
|
2062
|
-
|
2148
|
+
return_distribution : ReturnDistribution
|
2149
|
+
asset returns distribution DataModel.
|
2063
2150
|
|
2064
2151
|
w : cvxpy Variable
|
2065
2152
|
The CVXPY Variable representing assets weights.
|
@@ -2073,13 +2160,18 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
2073
2160
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
2074
2161
|
CVXPY Expression and Constraints the Ulcer Index risk measure.
|
2075
2162
|
"""
|
2076
|
-
v, constraints = self._cvx_drawdown(
|
2077
|
-
|
2163
|
+
v, constraints = self._cvx_drawdown(
|
2164
|
+
return_distribution=return_distribution, w=w, factor=factor
|
2165
|
+
)
|
2166
|
+
n_observations = return_distribution.returns.shape[0]
|
2078
2167
|
risk = cp.norm(v[1:], 2) / (np.sqrt(n_observations))
|
2079
2168
|
return risk, constraints
|
2080
2169
|
|
2081
2170
|
def _gini_mean_difference_risk(
|
2082
|
-
self,
|
2171
|
+
self,
|
2172
|
+
return_distribution: ReturnDistribution,
|
2173
|
+
w: cp.Variable,
|
2174
|
+
factor: skt.Factor,
|
2083
2175
|
) -> skt.RiskResult:
|
2084
2176
|
"""Expression and Constraints of the Gini Mean Difference risk measure.
|
2085
2177
|
|
@@ -2095,8 +2187,8 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
2095
2187
|
|
2096
2188
|
Parameters
|
2097
2189
|
----------
|
2098
|
-
|
2099
|
-
|
2190
|
+
return_distribution : ReturnDistribution
|
2191
|
+
asset returns distribution DataModel.
|
2100
2192
|
|
2101
2193
|
w : cvxpy Variable
|
2102
2194
|
The CVXPY Variable representing assets weights.
|
@@ -2110,12 +2202,14 @@ class ConvexOptimization(BaseOptimization, ABC):
|
|
2110
2202
|
expression : tuple[cvxpy Expression , list[cvxpy Expression]]
|
2111
2203
|
CVXPY Expression and Constraints the Ulcer Index risk measure.
|
2112
2204
|
"""
|
2113
|
-
ptf_returns = self._cvx_returns(
|
2205
|
+
ptf_returns = self._cvx_returns(return_distribution=return_distribution, w=w)
|
2114
2206
|
ptf_transaction_cost = self._cvx_transaction_cost(
|
2115
|
-
|
2207
|
+
return_distribution=return_distribution, w=w, factor=factor
|
2208
|
+
)
|
2209
|
+
ptf_management_fee = self._cvx_management_fee(
|
2210
|
+
return_distribution=return_distribution, w=w
|
2116
2211
|
)
|
2117
|
-
|
2118
|
-
observation_nb = prior_model.returns.shape[0]
|
2212
|
+
observation_nb = return_distribution.returns.shape[0]
|
2119
2213
|
x = cp.Variable((observation_nb, 1))
|
2120
2214
|
y = cp.Variable((observation_nb, 1))
|
2121
2215
|
z = cp.Variable((observation_nb, 1))
|