skfolio 0.1.2__tar.gz → 0.1.3__tar.gz

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 (87) hide show
  1. {skfolio-0.1.2/src/skfolio.egg-info → skfolio-0.1.3}/PKG-INFO +6 -7
  2. {skfolio-0.1.2 → skfolio-0.1.3}/README.rst +5 -5
  3. {skfolio-0.1.2 → skfolio-0.1.3}/pyproject.toml +10 -13
  4. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/datasets/_base.py +4 -1
  5. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/distance/_distance.py +0 -1
  6. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/measures/_enums.py +3 -1
  7. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/measures/_measures.py +0 -1
  8. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/model_selection/_combinatorial.py +14 -12
  9. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/model_selection/_validation.py +8 -6
  10. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/_base.py +11 -9
  11. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/cluster/hierarchical/_hrp.py +0 -1
  12. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/ensemble/_base.py +1 -3
  13. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/ensemble/_stacking.py +6 -4
  14. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/population/_population.py +25 -18
  15. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/portfolio/_base.py +0 -1
  16. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/portfolio/_portfolio.py +13 -12
  17. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/prior/_factor_model.py +6 -4
  18. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/utils/fixes/_dendrogram.py +9 -7
  19. {skfolio-0.1.2 → skfolio-0.1.3/src/skfolio.egg-info}/PKG-INFO +6 -7
  20. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio.egg-info/requires.txt +0 -1
  21. {skfolio-0.1.2 → skfolio-0.1.3}/LICENSE +0 -0
  22. {skfolio-0.1.2 → skfolio-0.1.3}/MANIFEST.in +0 -0
  23. {skfolio-0.1.2 → skfolio-0.1.3}/setup.cfg +0 -0
  24. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/__init__.py +0 -0
  25. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/cluster/__init__.py +0 -0
  26. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/cluster/_hierarchical.py +0 -0
  27. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/datasets/__init__.py +0 -0
  28. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/datasets/data/__init__.py +0 -0
  29. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/datasets/data/factors_dataset.csv.gz +0 -0
  30. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/datasets/data/sp500_dataset.csv.gz +0 -0
  31. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/datasets/data/sp500_index.csv.gz +0 -0
  32. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/distance/__init__.py +0 -0
  33. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/distance/_base.py +0 -0
  34. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/exceptions.py +0 -0
  35. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/measures/__init__.py +0 -0
  36. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/metrics/__init__.py +0 -0
  37. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/metrics/_scorer.py +0 -0
  38. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/model_selection/__init__.py +0 -0
  39. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/model_selection/_walk_forward.py +0 -0
  40. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/moments/__init__.py +0 -0
  41. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/moments/covariance/__init__.py +0 -0
  42. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/moments/covariance/_base.py +0 -0
  43. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/moments/covariance/_covariance.py +0 -0
  44. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/moments/expected_returns/__init__.py +0 -0
  45. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/moments/expected_returns/_base.py +0 -0
  46. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/moments/expected_returns/_expected_returns.py +0 -0
  47. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/__init__.py +0 -0
  48. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/cluster/__init__.py +0 -0
  49. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/cluster/_nco.py +0 -0
  50. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/cluster/hierarchical/__init__.py +0 -0
  51. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/cluster/hierarchical/_base.py +0 -0
  52. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/cluster/hierarchical/_herc.py +0 -0
  53. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/convex/__init__.py +0 -0
  54. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/convex/_base.py +0 -0
  55. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/convex/_distributionally_robust.py +0 -0
  56. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/convex/_maximum_diversification.py +0 -0
  57. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/convex/_mean_risk.py +0 -0
  58. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/convex/_risk_budgeting.py +0 -0
  59. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/ensemble/__init__.py +0 -0
  60. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/naive/__init__.py +0 -0
  61. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/optimization/naive/_naive.py +0 -0
  62. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/population/__init__.py +0 -0
  63. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/portfolio/__init__.py +0 -0
  64. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/portfolio/_multi_period_portfolio.py +0 -0
  65. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/pre_selection/__init__.py +0 -0
  66. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/pre_selection/_pre_selection.py +0 -0
  67. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/preprocessing/__init__.py +0 -0
  68. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/preprocessing/_returns.py +0 -0
  69. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/prior/__init__.py +0 -0
  70. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/prior/_base.py +0 -0
  71. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/prior/_black_litterman.py +0 -0
  72. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/prior/_empirical.py +0 -0
  73. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/typing.py +0 -0
  74. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/uncertainty_set/__init__.py +0 -0
  75. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/uncertainty_set/_base.py +0 -0
  76. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/uncertainty_set/_bootstrap.py +0 -0
  77. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/uncertainty_set/_empirical.py +0 -0
  78. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/utils/__init__.py +0 -0
  79. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/utils/bootstrap.py +0 -0
  80. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/utils/equations.py +0 -0
  81. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/utils/fixes/__init__.py +0 -0
  82. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/utils/sorting.py +0 -0
  83. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/utils/stats.py +0 -0
  84. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio/utils/tools.py +0 -0
  85. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio.egg-info/SOURCES.txt +0 -0
  86. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio.egg-info/dependency_links.txt +0 -0
  87. {skfolio-0.1.2 → skfolio-0.1.3}/src/skfolio.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: skfolio
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Portfolio optimization built on top of scikit-learn
5
5
  Author-email: Hugo Delatte <delatte.hugo@gmail.com>
6
6
  Maintainer-email: Hugo Delatte <delatte.hugo@gmail.com>
@@ -66,7 +66,6 @@ Requires-Dist: plotly>=5.15.0
66
66
  Provides-Extra: tests
67
67
  Requires-Dist: pytest; extra == "tests"
68
68
  Requires-Dist: pytest-cov; extra == "tests"
69
- Requires-Dist: black; extra == "tests"
70
69
  Requires-Dist: ruff; extra == "tests"
71
70
  Provides-Extra: docs
72
71
  Requires-Dist: Sphinx; extra == "docs"
@@ -646,9 +645,9 @@ If you use `skfolio` in a scientific publication, we would appreciate citations:
646
645
  Bibtex entry::
647
646
 
648
647
  @misc{skfolio,
649
- author = {Hugo Delatte, Carlo Nicolini},
650
- title = {skfolio},
651
- year = {2023},
652
- url = {https://github.com/skfolio/skfolio}
653
-
648
+ author = {Delatte, Hugo and Nicolini, Carlo},
649
+ title = {skfolio},
650
+ year = {2023},
651
+ url = {https://github.com/skfolio/skfolio}
652
+ }
654
653
 
@@ -560,9 +560,9 @@ If you use `skfolio` in a scientific publication, we would appreciate citations:
560
560
  Bibtex entry::
561
561
 
562
562
  @misc{skfolio,
563
- author = {Hugo Delatte, Carlo Nicolini},
564
- title = {skfolio},
565
- year = {2023},
566
- url = {https://github.com/skfolio/skfolio}
567
-
563
+ author = {Delatte, Hugo and Nicolini, Carlo},
564
+ title = {skfolio},
565
+ year = {2023},
566
+ url = {https://github.com/skfolio/skfolio}
567
+ }
568
568
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "skfolio"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  maintainers = [
9
9
  { name = "Hugo Delatte", email = "delatte.hugo@gmail.com" },
10
10
  ]
@@ -62,7 +62,6 @@ classifiers = [
62
62
  tests = [
63
63
  "pytest",
64
64
  "pytest-cov",
65
- "black",
66
65
  "ruff"
67
66
  ]
68
67
  docs = [
@@ -106,33 +105,31 @@ commit_message = "v{version} [skip ci]\n\nAutomatically generated by python-sema
106
105
  [tool.semantic_release.remote]
107
106
  token = { env = "GH_TOKEN" }
108
107
 
109
- [tool.black]
110
- line-length = 88
111
- target_version = ["py310", "py311"]
112
- preview = true
113
-
114
108
  [tool.ruff]
115
109
  include = ["pyproject.toml", "src/**/*.py"]
110
+ line-length = 88
111
+ src = ["src"]
112
+ target-version = "py310"
113
+
114
+ [tool.ruff.lint]
116
115
  select = [
117
116
  "E", # pycodestyle
118
117
  "F", # pyflakes
119
118
  "I", # isort
120
119
  "A", # prevent using keywords that clobber python builtins
121
120
  "B", # bugbear: security warnings
122
- "E", # pycodestyle
123
121
  "F", # pyflakes
124
122
  "ISC", # implicit string concatenation
125
123
  "UP", # alert you when better syntax is available in your python version
126
124
  "RUF", # the ruff developer's own rules
127
125
  ]
128
- ignore = ["E203", "E501"]
129
- # Same as Black.
130
- line-length = 88
131
- target-version = "py310"
126
+ ignore = ["E203", "ISC001", "ISC002", "E111", "E114", "E117"] # rules redundant with the formatter.
132
127
 
133
- [tool.ruff.isort]
128
+ [tool.ruff.lint.isort]
134
129
  case-sensitive = true
135
130
 
131
+ [tool.ruff.lint.pycodestyle]
132
+ max-line-length = 320
136
133
 
137
134
  [tool.pytest.ini_options]
138
135
  addopts = [
@@ -140,7 +140,10 @@ def download_dataset(
140
140
  DataFrame with each row representing one observation and each column
141
141
  representing the asset price of a given observation.
142
142
  """
143
- url = f"https://github.com/skfolio/skfolio/raw/main/datasets/{data_filename}.csv.gz"
143
+ url = (
144
+ f"https://github.com/skfolio/skfolio-datasets/raw/main/"
145
+ f"datasets/{data_filename}.csv.gz"
146
+ )
144
147
 
145
148
  data_home = get_data_home(data_home=data_home)
146
149
  filepath = os.path.join(data_home, f"{data_filename}.pkz")
@@ -4,7 +4,6 @@
4
4
  # Author: Hugo Delatte <delatte.hugo@gmail.com>
5
5
  # License: BSD 3 clause
6
6
 
7
-
8
7
  import numpy as np
9
8
  import numpy.typing as npt
10
9
  import pandas as pd
@@ -19,7 +19,9 @@ class BaseMeasure(AutoEnum):
19
19
  (
20
20
  word.capitalize()
21
21
  if len(word) > 3
22
- else word.upper() if len(word) != 2 else word.lower()
22
+ else word.upper()
23
+ if len(word) != 2
24
+ else word.lower()
23
25
  )
24
26
  for word in self.value.split("_")
25
27
  ]
@@ -6,7 +6,6 @@
6
6
  # Gini mean difference and OWA GMD weights features are derived
7
7
  # from Riskfolio-Lib, Copyright (c) 2020-2023, Dany Cajas, Licensed under BSD 3 clause.
8
8
 
9
-
10
9
  import numpy as np
11
10
  import scipy.optimize as sco
12
11
 
@@ -321,18 +321,20 @@ class CombinatorialPurgedCV(BaseCombinatorialCV):
321
321
 
322
322
  def summary(self, X) -> pd.Series:
323
323
  n_samples = X.shape[0]
324
- return pd.Series({
325
- "Number of Observations": n_samples,
326
- "Total Number of Folds": self.n_folds,
327
- "Number of Test Folds": self.n_test_folds,
328
- "Purge Size": self.purged_size,
329
- "Embargo Size": self.embargo_size,
330
- "Average Training Size": int(
331
- n_samples / self.n_folds * (self.n_folds - self.n_test_folds)
332
- ),
333
- "Number of Test Paths": self.n_test_paths,
334
- "Number of Training Combinations": self.n_splits,
335
- })
324
+ return pd.Series(
325
+ {
326
+ "Number of Observations": n_samples,
327
+ "Total Number of Folds": self.n_folds,
328
+ "Number of Test Folds": self.n_test_folds,
329
+ "Purge Size": self.purged_size,
330
+ "Embargo Size": self.embargo_size,
331
+ "Average Training Size": int(
332
+ n_samples / self.n_folds * (self.n_folds - self.n_test_folds)
333
+ ),
334
+ "Number of Test Paths": self.n_test_paths,
335
+ "Number of Training Combinations": self.n_splits,
336
+ }
337
+ )
336
338
 
337
339
  def plot_train_test_folds(self) -> skt.Figure:
338
340
  """Plot the train/test fold locations"""
@@ -170,12 +170,14 @@ def cross_val_predict(
170
170
  path_id = path_ids[i, j]
171
171
  portfolios[path_id].append(p)
172
172
  name = portfolio_params.pop("name", "path")
173
- pred = Population([
174
- MultiPeriodPortfolio(
175
- name=f"{name}_{i}", portfolios=portfolios[i], **portfolio_params
176
- )
177
- for i in range(path_nb)
178
- ])
173
+ pred = Population(
174
+ [
175
+ MultiPeriodPortfolio(
176
+ name=f"{name}_{i}", portfolios=portfolios[i], **portfolio_params
177
+ )
178
+ for i in range(path_nb)
179
+ ]
180
+ )
179
181
  else:
180
182
  # We need to re-order the test folds in case they were un-ordered by the
181
183
  # CV generator.
@@ -97,15 +97,17 @@ class BaseOptimization(skb.BaseEstimator, ABC):
97
97
  # For a 2D array we return a population of portfolios.
98
98
  if self.weights_.ndim == 2:
99
99
  n_portfolios = self.weights_.shape[0]
100
- return Population([
101
- Portfolio(
102
- X=X,
103
- weights=self.weights_[i],
104
- name=f"ptf{i} - {name}",
105
- **ptf_kwargs,
106
- )
107
- for i in range(n_portfolios)
108
- ])
100
+ return Population(
101
+ [
102
+ Portfolio(
103
+ X=X,
104
+ weights=self.weights_[i],
105
+ name=f"ptf{i} - {name}",
106
+ **ptf_kwargs,
107
+ )
108
+ for i in range(n_portfolios)
109
+ ]
110
+ )
109
111
  return Portfolio(X=X, weights=self.weights_, name=name, **ptf_kwargs)
110
112
 
111
113
  def score(self, X: npt.ArrayLike, y: npt.ArrayLike = None) -> float:
@@ -6,7 +6,6 @@
6
6
  # The risk measure generalization and constraint features are derived
7
7
  # from Riskfolio-Lib, Copyright (c) 2020-2023, Dany Cajas, Licensed under BSD 3 clause.
8
8
 
9
-
10
9
  import numpy as np
11
10
  import numpy.typing as npt
12
11
  import pandas as pd
@@ -80,9 +80,7 @@ class BaseComposition(skb.BaseEstimator, ABC):
80
80
  invalid_names = set(names).intersection(self.get_params(deep=False))
81
81
  if invalid_names:
82
82
  raise ValueError(
83
- "Estimator names conflict with constructor arguments: {!r}".format(
84
- sorted(invalid_names)
85
- )
83
+ f"Estimator names conflict with constructor arguments: {sorted(invalid_names)!r}"
86
84
  )
87
85
  invalid_names = [name for name in names if "__" in name]
88
86
  if invalid_names:
@@ -312,10 +312,12 @@ class StackingOptimization(BaseOptimization, BaseComposition):
312
312
  _ = self._validate_data(X)
313
313
 
314
314
  if isinstance(self.cv, BaseCombinatorialCV):
315
- X_pred = np.array([
316
- pred.quantile(measure=self.quantile_measure, q=self.quantile)
317
- for pred in cv_predictions
318
- ]).T
315
+ X_pred = np.array(
316
+ [
317
+ pred.quantile(measure=self.quantile_measure, q=self.quantile)
318
+ for pred in cv_predictions
319
+ ]
320
+ ).T
319
321
  else:
320
322
  X_pred = np.array(cv_predictions).T
321
323
  if y is not None:
@@ -1,4 +1,4 @@
1
- """ Population module.
1
+ """Population module.
2
2
  A population is a collection of portfolios.
3
3
  """
4
4
 
@@ -140,9 +140,12 @@ class Population(list):
140
140
  non-dominated portfolios.
141
141
  """
142
142
  n = len(self)
143
- if n > 0 and np.any([
144
- portfolio.fitness_measures != self[0].fitness_measures for portfolio in self
145
- ]):
143
+ if n > 0 and np.any(
144
+ [
145
+ portfolio.fitness_measures != self[0].fitness_measures
146
+ for portfolio in self
147
+ ]
148
+ ):
146
149
  raise ValueError(
147
150
  "Cannot compute non denominated sorting with Portfolios "
148
151
  "containing mixed `fitness_measures`"
@@ -187,11 +190,13 @@ class Population(list):
187
190
  return self.__class__(
188
191
  [portfolio for portfolio in self if portfolio.tag in tags]
189
192
  )
190
- return self.__class__([
191
- portfolio
192
- for portfolio in self
193
- if portfolio.name in names and portfolio.tag in tags
194
- ])
193
+ return self.__class__(
194
+ [
195
+ portfolio
196
+ for portfolio in self
197
+ if portfolio.name in names and portfolio.tag in tags
198
+ ]
199
+ )
195
200
 
196
201
  def measures(
197
202
  self,
@@ -784,15 +789,17 @@ class Population(list):
784
789
  x=xi,
785
790
  y=yi,
786
791
  z=Z,
787
- hovertemplate="<br>".join([
788
- str(e)
789
- + ": %{"
790
- + v
791
- + ":"
792
- + (",.3%" if not e.is_ratio else None)
793
- + "}"
794
- for e, v in [(x, "x"), (y, "y"), (z, "z")]
795
- ])
792
+ hovertemplate="<br>".join(
793
+ [
794
+ str(e)
795
+ + ": %{"
796
+ + v
797
+ + ":"
798
+ + (",.3%" if not e.is_ratio else None)
799
+ + "}"
800
+ for e, v in [(x, "x"), (y, "y"), (z, "z")]
801
+ ]
802
+ )
796
803
  + "<extra></extra>",
797
804
  colorbar=dict(
798
805
  title=str(z),
@@ -37,7 +37,6 @@
37
37
  # the class attributes with the argument name preceded by the measure name and
38
38
  # separated by '_'.
39
39
 
40
-
41
40
  import warnings
42
41
  from abc import abstractmethod
43
42
  from typing import ClassVar
@@ -8,7 +8,6 @@ is the dot product of the assets weights with the assets returns.
8
8
  # Author: Hugo Delatte <delatte.hugo@gmail.com>
9
9
  # License: BSD 3 clause
10
10
 
11
-
12
11
  import numbers
13
12
  from typing import ClassVar
14
13
 
@@ -402,17 +401,19 @@ class Portfolio(BasePortfolio):
402
401
  """
403
402
 
404
403
  _read_only_attrs: ClassVar[set] = BasePortfolio._read_only_attrs.copy()
405
- _read_only_attrs.update({
406
- "X",
407
- "assets",
408
- "weights",
409
- "previous_weights",
410
- "transaction_costs",
411
- "management_fees",
412
- "n_assets",
413
- "total_cost",
414
- "total_fee",
415
- })
404
+ _read_only_attrs.update(
405
+ {
406
+ "X",
407
+ "assets",
408
+ "weights",
409
+ "previous_weights",
410
+ "transaction_costs",
411
+ "management_fees",
412
+ "n_assets",
413
+ "total_cost",
414
+ "total_fee",
415
+ }
416
+ )
416
417
 
417
418
  __slots__ = {
418
419
  # read-only
@@ -114,10 +114,12 @@ class LoadingMatrixRegression(BaseLoadingMatrix):
114
114
  self.loading_matrix_ = np.array(
115
115
  [self.multi_output_regressor_.estimators_[i].coef_ for i in range(n_assets)]
116
116
  )
117
- self.intercepts_ = np.array([
118
- self.multi_output_regressor_.estimators_[i].intercept_
119
- for i in range(n_assets)
120
- ])
117
+ self.intercepts_ = np.array(
118
+ [
119
+ self.multi_output_regressor_.estimators_[i].intercept_
120
+ for i in range(n_assets)
121
+ ]
122
+ )
121
123
 
122
124
 
123
125
  class FactorModel(BasePrior):
@@ -290,13 +290,15 @@ class _Dendrogram:
290
290
  Sets and returns default layout object for dendrogram figure.
291
291
 
292
292
  """
293
- self.layout.update({
294
- "showlegend": False,
295
- "autosize": False,
296
- "hovermode": "closest",
297
- "width": width,
298
- "height": height,
299
- })
293
+ self.layout.update(
294
+ {
295
+ "showlegend": False,
296
+ "autosize": False,
297
+ "hovermode": "closest",
298
+ "width": width,
299
+ "height": height,
300
+ }
301
+ )
300
302
 
301
303
  self.set_axis_layout(self.xaxis)
302
304
  self.set_axis_layout(self.yaxis)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: skfolio
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Portfolio optimization built on top of scikit-learn
5
5
  Author-email: Hugo Delatte <delatte.hugo@gmail.com>
6
6
  Maintainer-email: Hugo Delatte <delatte.hugo@gmail.com>
@@ -66,7 +66,6 @@ Requires-Dist: plotly>=5.15.0
66
66
  Provides-Extra: tests
67
67
  Requires-Dist: pytest; extra == "tests"
68
68
  Requires-Dist: pytest-cov; extra == "tests"
69
- Requires-Dist: black; extra == "tests"
70
69
  Requires-Dist: ruff; extra == "tests"
71
70
  Provides-Extra: docs
72
71
  Requires-Dist: Sphinx; extra == "docs"
@@ -646,9 +645,9 @@ If you use `skfolio` in a scientific publication, we would appreciate citations:
646
645
  Bibtex entry::
647
646
 
648
647
  @misc{skfolio,
649
- author = {Hugo Delatte, Carlo Nicolini},
650
- title = {skfolio},
651
- year = {2023},
652
- url = {https://github.com/skfolio/skfolio}
653
-
648
+ author = {Delatte, Hugo and Nicolini, Carlo},
649
+ title = {skfolio},
650
+ year = {2023},
651
+ url = {https://github.com/skfolio/skfolio}
652
+ }
654
653
 
@@ -24,5 +24,4 @@ sphinx-sitemap
24
24
  [tests]
25
25
  pytest
26
26
  pytest-cov
27
- black
28
27
  ruff
File without changes
File without changes
File without changes
File without changes
File without changes