skfolio 0.9.1__py3-none-any.whl → 0.10.0__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.
Files changed (41) hide show
  1. skfolio/distribution/multivariate/_vine_copula.py +35 -34
  2. skfolio/distribution/univariate/_base.py +20 -15
  3. skfolio/exceptions.py +5 -0
  4. skfolio/measures/__init__.py +2 -0
  5. skfolio/measures/_measures.py +390 -155
  6. skfolio/optimization/_base.py +21 -4
  7. skfolio/optimization/cluster/hierarchical/_base.py +16 -13
  8. skfolio/optimization/cluster/hierarchical/_herc.py +6 -6
  9. skfolio/optimization/cluster/hierarchical/_hrp.py +8 -6
  10. skfolio/optimization/convex/_base.py +238 -144
  11. skfolio/optimization/convex/_distributionally_robust.py +32 -20
  12. skfolio/optimization/convex/_maximum_diversification.py +15 -15
  13. skfolio/optimization/convex/_mean_risk.py +26 -24
  14. skfolio/optimization/convex/_risk_budgeting.py +23 -21
  15. skfolio/optimization/ensemble/__init__.py +2 -4
  16. skfolio/optimization/ensemble/_stacking.py +1 -1
  17. skfolio/optimization/naive/_naive.py +2 -2
  18. skfolio/population/_population.py +30 -9
  19. skfolio/portfolio/_base.py +68 -26
  20. skfolio/portfolio/_multi_period_portfolio.py +5 -0
  21. skfolio/portfolio/_portfolio.py +5 -0
  22. skfolio/prior/__init__.py +6 -2
  23. skfolio/prior/_base.py +7 -3
  24. skfolio/prior/_black_litterman.py +14 -12
  25. skfolio/prior/_empirical.py +8 -7
  26. skfolio/prior/_entropy_pooling.py +1493 -0
  27. skfolio/prior/_factor_model.py +39 -22
  28. skfolio/prior/_opinion_pooling.py +475 -0
  29. skfolio/prior/_synthetic_data.py +10 -8
  30. skfolio/uncertainty_set/_bootstrap.py +4 -4
  31. skfolio/uncertainty_set/_empirical.py +6 -6
  32. skfolio/utils/equations.py +10 -4
  33. skfolio/utils/figure.py +185 -0
  34. skfolio/utils/tools.py +4 -2
  35. {skfolio-0.9.1.dist-info → skfolio-0.10.0.dist-info}/METADATA +94 -5
  36. {skfolio-0.9.1.dist-info → skfolio-0.10.0.dist-info}/RECORD +40 -38
  37. {skfolio-0.9.1.dist-info → skfolio-0.10.0.dist-info}/WHEEL +1 -1
  38. skfolio/synthetic_returns/__init__.py +0 -1
  39. /skfolio/{optimization/ensemble/_base.py → utils/composition.py} +0 -0
  40. {skfolio-0.9.1.dist-info → skfolio-0.10.0.dist-info}/licenses/LICENSE +0 -0
  41. {skfolio-0.9.1.dist-info → skfolio-0.10.0.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, PriorModel
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.PriorModel`
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:`sphx_glr_auto_examples_1_mean_risk_plot_6_transaction_costs.py`)
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
- * "2.5 * ref1 + 0.10 * ref2 + 0.0013 <= 2.5 * ref3"
323
- * "ref1 >= 2.9 * ref2"
324
- * "ref1 == ref2"
325
- * "ref1 >= ref1"
322
+ * `"ref1 >= a"`
323
+ * `"ref1 == b"`
324
+ * `"ref1 >= ref1"`
325
+ * `"a * ref1 + b * ref2 + c <= d * ref3"`
326
326
 
327
- With "ref1", "ref2" ... the assets names or the groups names provided
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, prior_model: PriorModel, w: cp.Variable
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 = prior_model.mu @ w
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, prior_model: PriorModel, w: cp.Variable, factor: skt.Factor
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
- prior_model : PriorModel
1245
- The prior model of the assets distributions.
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 = prior_model.returns.shape[1]
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, prior_model: PriorModel, w: cp.Variable
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
- prior_model : PriorModel
1295
- The prior model of the assets distributions.
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 = prior_model.returns.shape[1]
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(self, prior_model: PriorModel, w: cp.Variable) -> cp.Expression:
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
- prior_model : PriorModel
1327
- The prior model of the assets distributions.
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 = prior_model.returns @ w
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
- prior_model: PriorModel,
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
- prior_model : PriorModel
1391
- The prior model of the assets distributions..
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 = prior_model.mu
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 = (prior_model.returns - min_acceptable_return) @ w
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, prior_model: PriorModel, w: cp.Variable, factor: skt.Factor
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
- prior_model : PriorModel
1424
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
1439
- ptf_returns = self._cvx_returns(prior_model=prior_model, w=w)
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
- prior_model=prior_model, w=w, factor=factor
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, prior_model: PriorModel, w: cp.Variable, factor: skt.Factor
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
- prior_model : PriorModel
1466
- The prior model of the assets distributions.
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(prior_model=prior_model, w=w, factor=factor)
1494
+ v, _ = self.__cvx_drawdown(
1495
+ return_distribution=return_distribution, w=w, factor=factor
1496
+ )
1482
1497
  return v, []
1483
- return self.__cvx_drawdown(prior_model=prior_model, w=w, factor=factor)
1498
+ return self.__cvx_drawdown(
1499
+ return_distribution=return_distribution, w=w, factor=factor
1500
+ )
1484
1501
 
1485
1502
  def _tracking_error(
1486
- self, prior_model: PriorModel, w: cp.Variable, y: np.ndarray, factor: skt.Factor
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
- prior_model : PriorModel
1493
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
1511
- ptf_returns = self._cvx_returns(prior_model=prior_model, w=w)
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, prior_model: PriorModel, w: cp.Variable, min_acceptable_return: skt.Target
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
- prior_model : PriorModel
1528
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
1567
+ n_observations = return_distribution.returns.shape[0]
1544
1568
  ptf_min_acceptable_return = self._cvx_min_acceptable_return(
1545
- prior_model=prior_model, w=w, min_acceptable_return=min_acceptable_return
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
- risk = 2 * cp.sum(v) / n_observations
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
- prior_model: PriorModel,
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
- prior_model : PriorModel
1567
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
1617
+ n_observations = return_distribution.returns.shape[0]
1587
1618
  ptf_min_acceptable_return = self._cvx_min_acceptable_return(
1588
- prior_model=prior_model, w=w, min_acceptable_return=min_acceptable_return
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
- risk = cp.sum(v) / n_observations
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, prior_model: PriorModel, w: cp.Variable
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
- prior_model : PriorModel
1607
- The prior model of the assets distributions.
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 prior_model.cholesky is not None:
1621
- z = prior_model.cholesky
1658
+ if return_distribution.cholesky is not None:
1659
+ z = return_distribution.cholesky
1622
1660
  else:
1623
- z = np.linalg.cholesky(prior_model.covariance)
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(self, prior_model: PriorModel, w: cp.Variable) -> skt.RiskResult:
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
- prior_model : PriorModel
1636
- The prior model of the assets distributions.
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(prior_model=prior_model, w=w)
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
- prior_model: PriorModel,
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
- prior_model : PriorModel
1662
- The prior model of the assets distributions.
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 = prior_model.returns.shape[1]
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(prior_model.covariance @ (x + y))
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
- prior_model: PriorModel,
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
- prior_model : PriorModel
1711
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
1766
+ n_observations = return_distribution.returns.shape[0]
1726
1767
  ptf_min_acceptable_return = self._cvx_min_acceptable_return(
1727
- prior_model=prior_model, w=w, min_acceptable_return=min_acceptable_return
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
- risk = cp.sum_squares(v) / (n_observations - 1)
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
- prior_model: PriorModel,
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
- prior_model : PriorModel
1748
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
1812
+ n_observations = return_distribution.returns.shape[0]
1763
1813
  ptf_min_acceptable_return = self._cvx_min_acceptable_return(
1764
- prior_model=prior_model, w=w, min_acceptable_return=min_acceptable_return
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
- risk = cp.norm(v, 2) / np.sqrt(n_observations - 1)
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, prior_model: PriorModel, w: cp.Variable, factor: skt.Factor
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
- prior_model : PriorModel
1788
- The prior model of the assets distributions.
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(prior_model=prior_model, w=w)
1864
+ ptf_returns = self._cvx_returns(return_distribution=return_distribution, w=w)
1803
1865
  ptf_transaction_cost = self._cvx_transaction_cost(
1804
- prior_model=prior_model, w=w, factor=factor
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
- prior_model: PriorModel,
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
- prior_model : PriorModel
1828
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
1843
- ptf_returns = self._cvx_returns(prior_model=prior_model, w=w)
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
- prior_model=prior_model, w=w, factor=factor
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
- risk = alpha + 1.0 / (n_observations * (1 - self.cvar_beta)) * cp.sum(v)
1851
- # noinspection PyTypeChecker
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
- prior_model: PriorModel,
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
- prior_model : PriorModel
1873
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
1888
- ptf_returns = self._cvx_returns(prior_model=prior_model, w=w)
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
- prior_model=prior_model, w=w, factor=factor
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, prior_model: PriorModel, w: cp.Variable, factor: skt.Factor
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
- prior_model : PriorModel
1927
- The prior model of the assets distributions.
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(prior_model=prior_model, w=w, factor=factor)
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, prior_model: PriorModel, w: cp.Variable, factor: skt.Factor
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
- prior_model : PriorModel
1955
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
1970
- v, constraints = self._cvx_drawdown(prior_model=prior_model, w=w, factor=factor)
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
- prior_model: PriorModel,
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
- prior_model : PriorModel
1985
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
2000
- v, constraints = self._cvx_drawdown(prior_model=prior_model, w=w, factor=factor)
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
- prior_model: PriorModel,
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
- prior_model : PriorModel
2021
- The prior model of the assets distributions.
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 = prior_model.returns.shape[0]
2036
- v, constraints = self._cvx_drawdown(prior_model=prior_model, w=w, factor=factor)
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
- prior_model: PriorModel,
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
- prior_model : PriorModel
2062
- The prior model of the assets distributions.
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(prior_model=prior_model, w=w, factor=factor)
2077
- n_observations = prior_model.returns.shape[0]
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, prior_model: PriorModel, w: cp.Variable, factor: skt.Factor
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
- prior_model : PriorModel
2099
- The prior model of the assets distributions.
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(prior_model=prior_model, w=w)
2205
+ ptf_returns = self._cvx_returns(return_distribution=return_distribution, w=w)
2114
2206
  ptf_transaction_cost = self._cvx_transaction_cost(
2115
- prior_model=prior_model, w=w, factor=factor
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
- ptf_management_fee = self._cvx_management_fee(prior_model=prior_model, w=w)
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))