openseries 1.9.7__py3-none-any.whl → 2.0.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.
openseries/owntypes.py CHANGED
@@ -1,11 +1,4 @@
1
- """Declaring types used throughout the project.
2
-
3
- Copyright (c) Captor Fund Management AB. This file is part of the openseries project.
4
-
5
- Licensed under the BSD 3-Clause License. You may obtain a copy of the License at:
6
- https://github.com/CaptorAB/openseries/blob/master/LICENSE.md
7
- SPDX-License-Identifier: BSD-3-Clause
8
- """
1
+ """Declaring types used throughout the project."""
9
2
 
10
3
  from __future__ import annotations
11
4
 
@@ -142,7 +135,9 @@ LiteralPlotlyHistogramHistNorm = Literal[
142
135
  "density",
143
136
  "probability density",
144
137
  ]
145
- LiteralPortfolioWeightings = Literal["eq_weights", "inv_vol"]
138
+ LiteralPortfolioWeightings = Literal[
139
+ "eq_weights", "inv_vol", "max_div", "min_vol_overweight"
140
+ ]
146
141
  LiteralMinimizeMethods = Literal[
147
142
  "SLSQP",
148
143
  "Nelder-Mead",
@@ -381,3 +376,23 @@ class PropertiesInputValidationError(Exception):
381
376
 
382
377
  class ResampleDataLossError(Exception):
383
378
  """Raised when user attempts to run resample_to_business_period_ends on returns."""
379
+
380
+
381
+ class WeightsNotProvidedError(Exception):
382
+ """Raised when weights are not provided."""
383
+
384
+
385
+ class MultipleCurrenciesError(Exception):
386
+ """Raised when multiple currencies are provided."""
387
+
388
+
389
+ class PortfolioItemsNotWithinFrameError(Exception):
390
+ """Raised when portfolio items are not within frame."""
391
+
392
+
393
+ class MaxDiversificationNaNError(Exception):
394
+ """Raised when max_div weight strategy produces NaN values."""
395
+
396
+
397
+ class MaxDiversificationNegativeWeightsError(Exception):
398
+ """Raised when max_div weight strategy produces negative weights."""
@@ -1,11 +1,4 @@
1
- """Defining the portfolio tools for the OpenFrame class.
2
-
3
- Copyright (c) Captor Fund Management AB. This file is part of the openseries project.
4
-
5
- Licensed under the BSD 3-Clause License. You may obtain a copy of the License at:
6
- https://github.com/CaptorAB/openseries/blob/master/LICENSE.md
7
- SPDX-License-Identifier: BSD-3-Clause
8
- """
1
+ """Defining the portfolio tools for the OpenFrame class."""
9
2
 
10
3
  from __future__ import annotations
11
4
 
@@ -84,7 +77,7 @@ def simulate_portfolios(
84
77
  The seed for the random process
85
78
 
86
79
  Returns:
87
- -------
80
+ --------
88
81
  pandas.DataFrame
89
82
  The resulting data
90
83
 
@@ -155,7 +148,7 @@ def efficient_frontier(
155
148
  cutting the frontier to exclude multiple points with almost the same risk
156
149
 
157
150
  Returns:
158
- -------
151
+ --------
159
152
  tuple[DataFrame, DataFrame, NDArray[float]]
160
153
  The efficient frontier data, simulation data and optimal portfolio
161
154
 
@@ -342,7 +335,7 @@ def constrain_optimized_portfolios(
342
335
  The method passed into the scipy.minimize function
343
336
 
344
337
  Returns:
345
- -------
338
+ --------
346
339
  tuple[OpenFrame, OpenTimeSeries, OpenFrame, OpenTimeSeries]
347
340
  The constrained optimal portfolio data
348
341
 
@@ -404,7 +397,7 @@ def prepare_plot_data(
404
397
  Data optimized with the efficient_frontier method
405
398
 
406
399
  Returns:
407
- -------
400
+ --------
408
401
  DataFrame
409
402
  The data prepared with mean returns, volatility and weights
410
403
 
@@ -488,7 +481,7 @@ def sharpeplot(
488
481
  Determines whether to open a browser window with the plot
489
482
 
490
483
  Returns:
491
- -------
484
+ --------
492
485
  Figure
493
486
  The scatter plot with simulated and optimized results
494
487
 
openseries/report.py CHANGED
@@ -1,11 +1,4 @@
1
- """Functions related to HTML reports.
2
-
3
- Copyright (c) Captor Fund Management AB. This file is part of the openseries project.
4
-
5
- Licensed under the BSD 3-Clause License. You may obtain a copy of the License at:
6
- https://github.com/CaptorAB/openseries/blob/master/LICENSE.md
7
- SPDX-License-Identifier: BSD-3-Clause
8
- """
1
+ """Functions related to HTML reports."""
9
2
 
10
3
  from __future__ import annotations
11
4
 
@@ -61,7 +54,7 @@ def calendar_period_returns(
61
54
  Whether to set new appropriate labels
62
55
 
63
56
  Returns:
64
- -------
57
+ --------
65
58
  pandas.DataFrame
66
59
  The resulting data
67
60
 
@@ -122,7 +115,7 @@ def report_html(
122
115
  Determines whether to vertically align the legend's labels
123
116
 
124
117
  Returns:
125
- -------
118
+ --------
126
119
  tuple[plotly.go.Figure, str]
127
120
  Plotly Figure and a div section or a html filename with location
128
121
 
openseries/series.py CHANGED
@@ -1,11 +1,4 @@
1
- """Defining the OpenTimeSeries class.
2
-
3
- Copyright (c) Captor Fund Management AB. This file is part of the openseries project.
4
-
5
- Licensed under the BSD 3-Clause License. You may obtain a copy of the License at:
6
- https://github.com/CaptorAB/openseries/blob/master/LICENSE.md
7
- SPDX-License-Identifier: BSD-3-Clause
8
- """
1
+ """The OpenTimeSeries class."""
9
2
 
10
3
  from __future__ import annotations
11
4
 
@@ -215,7 +208,7 @@ class OpenTimeSeries(_CommonModel[float]):
215
208
  Boolean flag indicating if timeseries is in local currency
216
209
 
217
210
  Returns:
218
- -------
211
+ --------
219
212
  OpenTimeSeries
220
213
  An OpenTimeSeries object
221
214
 
@@ -265,7 +258,7 @@ class OpenTimeSeries(_CommonModel[float]):
265
258
  Boolean flag indicating if timeseries is in local currency
266
259
 
267
260
  Returns:
268
- -------
261
+ --------
269
262
  OpenTimeSeries
270
263
  An OpenTimeSeries object
271
264
 
@@ -364,7 +357,7 @@ class OpenTimeSeries(_CommonModel[float]):
364
357
  Boolean flag indicating if timeseries is in local currency
365
358
 
366
359
  Returns:
367
- -------
360
+ --------
368
361
  OpenTimeSeries
369
362
  An OpenTimeSeries object
370
363
 
@@ -403,7 +396,7 @@ class OpenTimeSeries(_CommonModel[float]):
403
396
  """Create copy of OpenTimeSeries object.
404
397
 
405
398
  Returns:
406
- -------
399
+ --------
407
400
  OpenTimeSeries
408
401
  An OpenTimeSeries object
409
402
 
@@ -414,7 +407,7 @@ class OpenTimeSeries(_CommonModel[float]):
414
407
  """Populate .tsdf Pandas DataFrame from the .dates and .values lists.
415
408
 
416
409
  Returns:
417
- -------
410
+ --------
418
411
  OpenTimeSeries
419
412
  An OpenTimeSeries object
420
413
 
@@ -441,7 +434,7 @@ class OpenTimeSeries(_CommonModel[float]):
441
434
  The properties to calculate. Defaults to calculating all available.
442
435
 
443
436
  Returns:
444
- -------
437
+ --------
445
438
  pandas.DataFrame
446
439
  Properties of the OpenTimeSeries
447
440
 
@@ -461,7 +454,7 @@ class OpenTimeSeries(_CommonModel[float]):
461
454
  """Convert series of values into series of returns.
462
455
 
463
456
  Returns:
464
- -------
457
+ --------
465
458
  OpenTimeSeries
466
459
  The returns of the values in the series
467
460
 
@@ -486,7 +479,7 @@ class OpenTimeSeries(_CommonModel[float]):
486
479
  is calculated
487
480
 
488
481
  Returns:
489
- -------
482
+ --------
490
483
  OpenTimeSeries
491
484
  An OpenTimeSeries object
492
485
 
@@ -506,7 +499,7 @@ class OpenTimeSeries(_CommonModel[float]):
506
499
  """Convert series of returns into cumulative series of values.
507
500
 
508
501
  Returns:
509
- -------
502
+ --------
510
503
  OpenTimeSeries
511
504
  An OpenTimeSeries object
512
505
 
@@ -541,7 +534,7 @@ class OpenTimeSeries(_CommonModel[float]):
541
534
  Convenience divider for when the 1-day rate is not scaled correctly
542
535
 
543
536
  Returns:
544
- -------
537
+ --------
545
538
  OpenTimeSeries
546
539
  An OpenTimeSeries object
547
540
 
@@ -582,7 +575,7 @@ class OpenTimeSeries(_CommonModel[float]):
582
575
  The date offset string that sets the resampled frequency
583
576
 
584
577
  Returns:
585
- -------
578
+ --------
586
579
  OpenTimeSeries
587
580
  An OpenTimeSeries object
588
581
 
@@ -612,7 +605,7 @@ class OpenTimeSeries(_CommonModel[float]):
612
605
  Controls the method used to align values across columns
613
606
 
614
607
  Returns:
615
- -------
608
+ --------
616
609
  OpenTimeSeries
617
610
  An OpenTimeSeries object
618
611
 
@@ -667,7 +660,7 @@ class OpenTimeSeries(_CommonModel[float]):
667
660
  Allows locking the periods-in-a-year to simplify test cases and comparisons
668
661
 
669
662
  Returns:
670
- -------
663
+ --------
671
664
  Pandas.Series[float]
672
665
  Series EWMA volatility
673
666
 
@@ -732,7 +725,7 @@ class OpenTimeSeries(_CommonModel[float]):
732
725
  assumed number of days in a calendar year
733
726
 
734
727
  Returns:
735
- -------
728
+ --------
736
729
  OpenTimeSeries
737
730
  An OpenTimeSeries object
738
731
 
@@ -793,7 +786,7 @@ class OpenTimeSeries(_CommonModel[float]):
793
786
  If True the level one label is deleted
794
787
 
795
788
  Returns:
796
- -------
789
+ --------
797
790
  OpenTimeSeries
798
791
  An OpenTimeSeries object
799
792
 
@@ -835,7 +828,7 @@ def timeseries_chain(
835
828
  Fee to apply to earlier series
836
829
 
837
830
  Returns:
838
- -------
831
+ --------
839
832
  TypeOpenTimeSeries
840
833
  An OpenTimeSeries object or a subclass thereof
841
834
 
@@ -896,7 +889,7 @@ def _check_if_none(item: Any) -> bool: # noqa: ANN401
896
889
  variable to be checked
897
890
 
898
891
  Returns:
899
- -------
892
+ --------
900
893
  bool
901
894
  Answer to whether the variable is None or equivalent
902
895
 
openseries/simulation.py CHANGED
@@ -1,11 +1,4 @@
1
- """Defining the ReturnSimulation class.
2
-
3
- Copyright (c) Captor Fund Management AB. This file is part of the openseries project.
4
-
5
- Licensed under the BSD 3-Clause License. You may obtain a copy of the License at:
6
- https://github.com/CaptorAB/openseries/blob/master/LICENSE.md
7
- SPDX-License-Identifier: BSD-3-Clause
8
- """
1
+ """The ReturnSimulation class."""
9
2
 
10
3
  from __future__ import annotations
11
4
 
@@ -14,7 +7,7 @@ from typing import TYPE_CHECKING, TypedDict, cast
14
7
 
15
8
  try:
16
9
  from typing import Unpack
17
- except ImportError:
10
+ except ImportError: # pragma: no cover
18
11
  from typing_extensions import Unpack
19
12
 
20
13
  if TYPE_CHECKING:
@@ -64,7 +57,7 @@ def _random_generator(seed: int | None) -> Generator:
64
57
  Random seed
65
58
 
66
59
  Returns:
67
- -------
60
+ --------
68
61
  numpy.random.Generator
69
62
  Numpy random process generator
70
63
 
@@ -109,7 +102,7 @@ def _create_base_simulation(
109
102
  Additional keyword arguments for jump parameters
110
103
 
111
104
  Returns:
112
- -------
105
+ --------
113
106
  ReturnSimulation
114
107
  A ReturnSimulation instance
115
108
 
@@ -176,7 +169,7 @@ class ReturnSimulation(BaseModel):
176
169
  """Simulation data.
177
170
 
178
171
  Returns:
179
- -------
172
+ --------
180
173
  pandas.DataFrame
181
174
  Simulation data
182
175
 
@@ -188,7 +181,7 @@ class ReturnSimulation(BaseModel):
188
181
  """Annualized arithmetic mean of returns.
189
182
 
190
183
  Returns:
191
- -------
184
+ --------
192
185
  float
193
186
  Annualized arithmetic mean of returns
194
187
 
@@ -205,7 +198,7 @@ class ReturnSimulation(BaseModel):
205
198
  """Annualized volatility.
206
199
 
207
200
  Returns:
208
- -------
201
+ --------
209
202
  float
210
203
  Annualized volatility
211
204
 
@@ -249,7 +242,7 @@ class ReturnSimulation(BaseModel):
249
242
  Random process generator
250
243
 
251
244
  Returns:
252
- -------
245
+ --------
253
246
  ReturnSimulation
254
247
  Normal distribution simulation
255
248
 
@@ -305,7 +298,7 @@ class ReturnSimulation(BaseModel):
305
298
  Random process generator
306
299
 
307
300
  Returns:
308
- -------
301
+ --------
309
302
  ReturnSimulation
310
303
  Lognormal distribution simulation
311
304
 
@@ -364,7 +357,7 @@ class ReturnSimulation(BaseModel):
364
357
  Random process generator
365
358
 
366
359
  Returns:
367
- -------
360
+ --------
368
361
  ReturnSimulation
369
362
  Geometric Brownian Motion simulation
370
363
 
@@ -436,7 +429,7 @@ class ReturnSimulation(BaseModel):
436
429
  Random process generator
437
430
 
438
431
  Returns:
439
- -------
432
+ --------
440
433
  ReturnSimulation
441
434
  Merton Jump-Diffusion model simulation
442
435
 
@@ -511,7 +504,7 @@ class ReturnSimulation(BaseModel):
511
504
  (List of) markets code(s) according to pandas-market-calendars
512
505
 
513
506
  Returns:
514
- -------
507
+ --------
515
508
  pandas.DataFrame
516
509
  The simulation(s) data
517
510
 
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.4
2
+ Name: openseries
3
+ Version: 2.0.1
4
+ Summary: Tools for analyzing financial timeseries.
5
+ License: # BSD 3-Clause License
6
+
7
+ ## Copyright (c) Captor Fund Management AB
8
+
9
+ Redistribution and use in source and binary forms, with or without modification, are
10
+ permitted provided that the following conditions are met:
11
+
12
+ 1. Redistributions of source code must retain the above copyright notice, this list of
13
+ conditions and the following disclaimer.
14
+
15
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
16
+ of conditions and the following disclaimer in the documentation and/or other
17
+ materials provided with the distribution.
18
+
19
+ 3. Neither the name of the copyright holder nor the names of its contributors may be
20
+ used to endorse or promote products derived from this software without specific prior
21
+ written permission.
22
+
23
+ This software is provided by the copyright holders and contributors “as is” and any
24
+ express or implied warranties, including, but not limited to, the implied warranties of
25
+ merchantability and fitness for a particular purpose, are disclaimed. In no event shall
26
+ the copyright holder or contributors be liable for any direct, indirect, incidental,
27
+ special, exemplary, or consequential damages (including, but not limited to, procurement
28
+ of substitute goods or services; loss of use, data, or profits; or business interruption)
29
+ however caused and on any theory of liability, whether in contract, strict liability,
30
+ or tort (including negligence or otherwise) arising in any way out of the use of this
31
+ software, even if advised of the possibility of such damage.
32
+ License-File: LICENSE.md
33
+ Keywords: python,finance,fintech,data-science,timeseries,timeseries-data,timeseries-analysis,investment,investment-analysis,investing
34
+ Author: Martin Karrin
35
+ Author-email: martin.karrin@captor.se
36
+ Maintainer: Martin Karrin
37
+ Maintainer-email: martin.karrin@captor.se
38
+ Requires-Python: >=3.10,<3.15
39
+ Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
41
+ Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Programming Language :: Python :: 3.13
43
+ Classifier: Programming Language :: Python :: 3.14
44
+ Classifier: License :: OSI Approved :: BSD License
45
+ Classifier: Intended Audience :: Financial and Insurance Industry
46
+ Classifier: Topic :: Office/Business :: Financial :: Investment
47
+ Classifier: Natural Language :: English
48
+ Classifier: Development Status :: 5 - Production/Stable
49
+ Classifier: Operating System :: OS Independent
50
+ Classifier: Framework :: Pydantic
51
+ Requires-Dist: exchange-calendars (>=4.8,<6.0)
52
+ Requires-Dist: holidays (>=0.30,<1.0)
53
+ Requires-Dist: numpy (>=1.23.2,!=2.3.0,<3.0.0)
54
+ Requires-Dist: openpyxl (>=3.1.2,<5.0.0)
55
+ Requires-Dist: pandas (>=2.1.2,<3.0.0)
56
+ Requires-Dist: plotly (>=5.18.0,<7.0.0)
57
+ Requires-Dist: pydantic (>=2.5.2,<3.0.0)
58
+ Requires-Dist: python-dateutil (>=2.8.2,<4.0.0)
59
+ Requires-Dist: requests (>=2.20.0,<3.0.0)
60
+ Requires-Dist: scikit-learn (>=1.4.0,<2.0.0)
61
+ Requires-Dist: scipy (>=1.11.4,<2.0.0)
62
+ Project-URL: Documentation, https://openseries.readthedocs.io/
63
+ Project-URL: Homepage, https://github.com/CaptorAB/openseries
64
+ Project-URL: Issue Tracker, https://github.com/CaptorAB/openseries/issues
65
+ Project-URL: Release Notes, https://github.com/CaptorAB/openseries/releases
66
+ Project-URL: Source, https://github.com/CaptorAB/openseries
67
+ Description-Content-Type: text/markdown
68
+
69
+ <a href="https://captor.se/"><img src="https://sales.captor.se/captor_logo_sv_1600_icketransparent.png" alt="Captor Fund Management AB" width="81" height="100" align="left" float="right"/></a><br/>
70
+
71
+ <br><br>
72
+
73
+ # openseries
74
+
75
+ [![PyPI version](https://img.shields.io/pypi/v/openseries.svg)](https://pypi.org/project/openseries/)
76
+ [![Conda Version](https://img.shields.io/conda/vn/conda-forge/openseries.svg)](https://anaconda.org/conda-forge/openseries)
77
+ ![Platform](https://img.shields.io/badge/platforms-Windows%20%7C%20macOS%20%7C%20Linux-blue)
78
+ [![Python version](https://img.shields.io/pypi/pyversions/openseries.svg)](https://www.python.org/)
79
+ [![GitHub Action Test Suite](https://github.com/CaptorAB/openseries/actions/workflows/test.yml/badge.svg)](https://github.com/CaptorAB/openseries/actions/workflows/test.yml)
80
+ [![codecov](https://img.shields.io/codecov/c/gh/CaptorAB/openseries?logo=codecov)](https://codecov.io/gh/CaptorAB/openseries/branch/master)
81
+ [![Documentation](https://readthedocs.org/projects/openseries/badge/?version=latest)](https://openseries.readthedocs.io/en/latest/?badge=latest)
82
+ [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
83
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://beta.ruff.rs/docs/)
84
+ [![GitHub License](https://img.shields.io/github/license/CaptorAB/openseries)](https://github.com/CaptorAB/openseries/blob/master/LICENSE.md)
85
+ [![Code Sample](https://img.shields.io/badge/-Code%20Sample-blue)](https://nbviewer.org/github/karrmagadgeteer2/NoteBook/blob/master/openseriesnotebook.ipynb)
86
+
87
+ Tools for analyzing financial timeseries of a single asset or a group of assets. Designed for daily or less frequent data.
88
+
89
+ ## Documentation
90
+
91
+ Complete documentation is available at: [https://openseries.readthedocs.io](https://openseries.readthedocs.io/)
92
+
93
+ The documentation includes:
94
+
95
+ - Quick start guide
96
+ - API reference
97
+ - Tutorials and examples
98
+ - Installation instructions
99
+
100
+ ## Installation
101
+
102
+ ```bash
103
+ pip install openseries
104
+ ```
105
+
106
+ or:
107
+
108
+ ```bash
109
+ conda install -c conda-forge openseries
110
+ ```
111
+
112
+ ## Quick Start
113
+
114
+ ```python
115
+ from openseries import OpenTimeSeries
116
+ import yfinance as yf
117
+
118
+ move=yf.Ticker(ticker="^MOVE")
119
+ history=move.history(period="max")
120
+ series=OpenTimeSeries.from_df(dframe=history.loc[:, "Close"])
121
+ _=series.set_new_label(lvl_zero="ICE BofAML MOVE Index")
122
+ _,_=series.plot_series()
123
+ ```
124
+
125
+ ### Sample output using the report_html() function
126
+
127
+ <img src="https://raw.githubusercontent.com/CaptorAB/openseries/master/openseries_plot.png" alt="Two Assets Compared" width="1000" />
128
+
@@ -0,0 +1,18 @@
1
+ openseries/__init__.py,sha256=vkJZmQaReCry7g6f8plQU5RaP1LBwVKe3DoD9ekF3Sc,1127
2
+ openseries/_common_model.py,sha256=y-udTW6LI0Q5er-Egzd4IrFoGHfRGSnsjHJuCu_YTIU,91628
3
+ openseries/_risk.py,sha256=YisMnI8DQT0w9n9SQbrvq0ZZqmZHrz7-jhZtngObJRk,2094
4
+ openseries/datefixer.py,sha256=U1Kc6QdW3UEzAp61NIUALOllyLWb-mJemiL7KLfSAto,15512
5
+ openseries/frame.py,sha256=g3X3eVkUptawmj7fb-86i21odIFTX_QvwJEcMU_mtO0,69376
6
+ openseries/load_plotly.py,sha256=sVssTMzJ2tPPHceCa9OCavI4Mv5BFgSKR6wnTltnqQQ,1997
7
+ openseries/owntypes.py,sha256=wxyU4d08YrxfEGL_bSI9M6ZVLjipqMLEsq376gVV9lk,10001
8
+ openseries/plotly_captor_logo.json,sha256=F5nhMzEyxKywtjvQqMTKgKRCJQYMDIiBgDSxdte8Clo,178
9
+ openseries/plotly_layouts.json,sha256=MvDEQuiqIhMBXBelXb1sedTOlTPheizv6NZRLeE9YS4,1431
10
+ openseries/portfoliotools.py,sha256=v7s9-AgJFlvPIbPuPf6J7d0VjP-dDT-rsm086EoqSAE,19073
11
+ openseries/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ openseries/report.py,sha256=FYN79MroQfY8DrDSSdsSDBcy6S9PwIS0FyujnqPEQV0,14106
13
+ openseries/series.py,sha256=Wp5G3EmzsBqABtkIPvFQ0Y4T77RhXM9uzvtJBPFWMrQ,28354
14
+ openseries/simulation.py,sha256=J58uHuakeIbZ2Pabha-RtsaO-k-MVsRfXSdZexrMAkI,16071
15
+ openseries-2.0.1.dist-info/METADATA,sha256=_YFEzFjSM-xzkD9ayOMVf41bJ2NGk8dLw15E2k9yu9c,6281
16
+ openseries-2.0.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
17
+ openseries-2.0.1.dist-info/licenses/LICENSE.md,sha256=wNupG-KLsG0aTncb_SMNDh1ExtrKXlpxSJ6RC-g-SWs,1516
18
+ openseries-2.0.1.dist-info/RECORD,,