openseries 1.9.6__py3-none-any.whl → 2.0.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.
- openseries/__init__.py +1 -8
- openseries/_common_model.py +375 -224
- openseries/_risk.py +3 -10
- openseries/datefixer.py +9 -16
- openseries/frame.py +100 -117
- openseries/load_plotly.py +3 -10
- openseries/owntypes.py +3 -10
- openseries/portfoliotools.py +19 -41
- openseries/py.typed +0 -0
- openseries/report.py +6 -12
- openseries/series.py +36 -54
- openseries/simulation.py +104 -39
- openseries-2.0.0.dist-info/METADATA +126 -0
- openseries-2.0.0.dist-info/RECORD +18 -0
- {openseries-1.9.6.dist-info → openseries-2.0.0.dist-info}/WHEEL +1 -1
- openseries-1.9.6.dist-info/METADATA +0 -369
- openseries-1.9.6.dist-info/RECORD +0 -17
- {openseries-1.9.6.dist-info → openseries-2.0.0.dist-info}/licenses/LICENSE.md +0 -0
openseries/simulation.py
CHANGED
@@ -1,15 +1,14 @@
|
|
1
|
-
"""
|
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
|
|
12
|
-
from
|
5
|
+
from functools import cached_property
|
6
|
+
from typing import TYPE_CHECKING, TypedDict, cast
|
7
|
+
|
8
|
+
try:
|
9
|
+
from typing import Unpack
|
10
|
+
except ImportError: # pragma: no cover
|
11
|
+
from typing_extensions import Unpack
|
13
12
|
|
14
13
|
if TYPE_CHECKING:
|
15
14
|
import datetime as dt # pragma: no cover
|
@@ -41,6 +40,14 @@ from .owntypes import (
|
|
41
40
|
__all__ = ["ReturnSimulation"]
|
42
41
|
|
43
42
|
|
43
|
+
class _JumpParams(TypedDict, total=False):
|
44
|
+
"""TypedDict for jump diffusion parameters."""
|
45
|
+
|
46
|
+
jumps_lamda: NonNegativeFloat
|
47
|
+
jumps_sigma: NonNegativeFloat
|
48
|
+
jumps_mu: float
|
49
|
+
|
50
|
+
|
44
51
|
def _random_generator(seed: int | None) -> Generator:
|
45
52
|
"""Make a Numpy Random Generator object.
|
46
53
|
|
@@ -50,7 +57,7 @@ def _random_generator(seed: int | None) -> Generator:
|
|
50
57
|
Random seed
|
51
58
|
|
52
59
|
Returns:
|
53
|
-
|
60
|
+
--------
|
54
61
|
numpy.random.Generator
|
55
62
|
Numpy random process generator
|
56
63
|
|
@@ -60,6 +67,58 @@ def _random_generator(seed: int | None) -> Generator:
|
|
60
67
|
return Generator(bit_generator=bg)
|
61
68
|
|
62
69
|
|
70
|
+
def _create_base_simulation(
|
71
|
+
cls: type[ReturnSimulation],
|
72
|
+
returns: DataFrame,
|
73
|
+
number_of_sims: PositiveInt,
|
74
|
+
trading_days: PositiveInt,
|
75
|
+
trading_days_in_year: DaysInYearType,
|
76
|
+
mean_annual_return: float,
|
77
|
+
mean_annual_vol: PositiveFloat,
|
78
|
+
seed: int | None = None,
|
79
|
+
**kwargs: Unpack[_JumpParams],
|
80
|
+
) -> ReturnSimulation:
|
81
|
+
"""Common logic for creating simulations.
|
82
|
+
|
83
|
+
Parameters
|
84
|
+
----------
|
85
|
+
cls: type[ReturnSimulation]
|
86
|
+
The ReturnSimulation class
|
87
|
+
returns: pandas.DataFrame
|
88
|
+
The calculated returns data
|
89
|
+
number_of_sims: PositiveInt
|
90
|
+
Number of simulations to generate
|
91
|
+
trading_days: PositiveInt
|
92
|
+
Number of trading days to simulate
|
93
|
+
trading_days_in_year: DaysInYearType
|
94
|
+
Number of trading days used to annualize
|
95
|
+
mean_annual_return: float
|
96
|
+
Mean annual return
|
97
|
+
mean_annual_vol: PositiveFloat
|
98
|
+
Mean annual volatility
|
99
|
+
seed: int, optional
|
100
|
+
Seed for random process initiation
|
101
|
+
**kwargs
|
102
|
+
Additional keyword arguments for jump parameters
|
103
|
+
|
104
|
+
Returns:
|
105
|
+
--------
|
106
|
+
ReturnSimulation
|
107
|
+
A ReturnSimulation instance
|
108
|
+
|
109
|
+
"""
|
110
|
+
return cls(
|
111
|
+
number_of_sims=number_of_sims,
|
112
|
+
trading_days=trading_days,
|
113
|
+
trading_days_in_year=trading_days_in_year,
|
114
|
+
mean_annual_return=mean_annual_return,
|
115
|
+
mean_annual_vol=mean_annual_vol,
|
116
|
+
dframe=returns,
|
117
|
+
seed=seed,
|
118
|
+
**kwargs,
|
119
|
+
)
|
120
|
+
|
121
|
+
|
63
122
|
class ReturnSimulation(BaseModel):
|
64
123
|
"""The class ReturnSimulation allows for simulating financial timeseries.
|
65
124
|
|
@@ -105,12 +164,12 @@ class ReturnSimulation(BaseModel):
|
|
105
164
|
revalidate_instances="always",
|
106
165
|
)
|
107
166
|
|
108
|
-
@
|
167
|
+
@cached_property
|
109
168
|
def results(self: Self) -> DataFrame:
|
110
169
|
"""Simulation data.
|
111
170
|
|
112
171
|
Returns:
|
113
|
-
|
172
|
+
--------
|
114
173
|
pandas.DataFrame
|
115
174
|
Simulation data
|
116
175
|
|
@@ -122,7 +181,7 @@ class ReturnSimulation(BaseModel):
|
|
122
181
|
"""Annualized arithmetic mean of returns.
|
123
182
|
|
124
183
|
Returns:
|
125
|
-
|
184
|
+
--------
|
126
185
|
float
|
127
186
|
Annualized arithmetic mean of returns
|
128
187
|
|
@@ -139,7 +198,7 @@ class ReturnSimulation(BaseModel):
|
|
139
198
|
"""Annualized volatility.
|
140
199
|
|
141
200
|
Returns:
|
142
|
-
|
201
|
+
--------
|
143
202
|
float
|
144
203
|
Annualized volatility
|
145
204
|
|
@@ -183,7 +242,7 @@ class ReturnSimulation(BaseModel):
|
|
183
242
|
Random process generator
|
184
243
|
|
185
244
|
Returns:
|
186
|
-
|
245
|
+
--------
|
187
246
|
ReturnSimulation
|
188
247
|
Normal distribution simulation
|
189
248
|
|
@@ -197,13 +256,14 @@ class ReturnSimulation(BaseModel):
|
|
197
256
|
size=(number_of_sims, trading_days),
|
198
257
|
)
|
199
258
|
|
200
|
-
return
|
259
|
+
return _create_base_simulation(
|
260
|
+
cls=cls,
|
261
|
+
returns=DataFrame(data=returns, dtype="float64"),
|
201
262
|
number_of_sims=number_of_sims,
|
202
263
|
trading_days=trading_days,
|
203
264
|
trading_days_in_year=trading_days_in_year,
|
204
265
|
mean_annual_return=mean_annual_return,
|
205
266
|
mean_annual_vol=mean_annual_vol,
|
206
|
-
dframe=DataFrame(data=returns, dtype="float64"),
|
207
267
|
seed=seed,
|
208
268
|
)
|
209
269
|
|
@@ -238,7 +298,7 @@ class ReturnSimulation(BaseModel):
|
|
238
298
|
Random process generator
|
239
299
|
|
240
300
|
Returns:
|
241
|
-
|
301
|
+
--------
|
242
302
|
ReturnSimulation
|
243
303
|
Lognormal distribution simulation
|
244
304
|
|
@@ -255,13 +315,14 @@ class ReturnSimulation(BaseModel):
|
|
255
315
|
- 1
|
256
316
|
)
|
257
317
|
|
258
|
-
return
|
318
|
+
return _create_base_simulation(
|
319
|
+
cls=cls,
|
320
|
+
returns=DataFrame(data=returns, dtype="float64"),
|
259
321
|
number_of_sims=number_of_sims,
|
260
322
|
trading_days=trading_days,
|
261
323
|
trading_days_in_year=trading_days_in_year,
|
262
324
|
mean_annual_return=mean_annual_return,
|
263
325
|
mean_annual_vol=mean_annual_vol,
|
264
|
-
dframe=DataFrame(data=returns, dtype="float64"),
|
265
326
|
seed=seed,
|
266
327
|
)
|
267
328
|
|
@@ -296,7 +357,7 @@ class ReturnSimulation(BaseModel):
|
|
296
357
|
Random process generator
|
297
358
|
|
298
359
|
Returns:
|
299
|
-
|
360
|
+
--------
|
300
361
|
ReturnSimulation
|
301
362
|
Geometric Brownian Motion simulation
|
302
363
|
|
@@ -317,13 +378,14 @@ class ReturnSimulation(BaseModel):
|
|
317
378
|
|
318
379
|
returns = drift + wiener
|
319
380
|
|
320
|
-
return
|
381
|
+
return _create_base_simulation(
|
382
|
+
cls=cls,
|
383
|
+
returns=DataFrame(data=returns, dtype="float64"),
|
321
384
|
number_of_sims=number_of_sims,
|
322
385
|
trading_days=trading_days,
|
323
386
|
trading_days_in_year=trading_days_in_year,
|
324
387
|
mean_annual_return=mean_annual_return,
|
325
388
|
mean_annual_vol=mean_annual_vol,
|
326
|
-
dframe=DataFrame(data=returns, dtype="float64"),
|
327
389
|
seed=seed,
|
328
390
|
)
|
329
391
|
|
@@ -367,7 +429,7 @@ class ReturnSimulation(BaseModel):
|
|
367
429
|
Random process generator
|
368
430
|
|
369
431
|
Returns:
|
370
|
-
|
432
|
+
--------
|
371
433
|
ReturnSimulation
|
372
434
|
Merton Jump-Diffusion model simulation
|
373
435
|
|
@@ -404,17 +466,18 @@ class ReturnSimulation(BaseModel):
|
|
404
466
|
|
405
467
|
returns[:, 0] = 0.0
|
406
468
|
|
407
|
-
return
|
469
|
+
return _create_base_simulation(
|
470
|
+
cls=cls,
|
471
|
+
returns=DataFrame(data=returns, dtype="float64"),
|
408
472
|
number_of_sims=number_of_sims,
|
409
473
|
trading_days=trading_days,
|
410
474
|
trading_days_in_year=trading_days_in_year,
|
411
475
|
mean_annual_return=mean_annual_return,
|
412
476
|
mean_annual_vol=mean_annual_vol,
|
477
|
+
seed=seed,
|
413
478
|
jumps_lamda=jumps_lamda,
|
414
479
|
jumps_sigma=jumps_sigma,
|
415
480
|
jumps_mu=jumps_mu,
|
416
|
-
dframe=DataFrame(data=returns, dtype="float64"),
|
417
|
-
seed=seed,
|
418
481
|
)
|
419
482
|
|
420
483
|
def to_dataframe(
|
@@ -441,7 +504,7 @@ class ReturnSimulation(BaseModel):
|
|
441
504
|
(List of) markets code(s) according to pandas-market-calendars
|
442
505
|
|
443
506
|
Returns:
|
444
|
-
|
507
|
+
--------
|
445
508
|
pandas.DataFrame
|
446
509
|
The simulation(s) data
|
447
510
|
|
@@ -465,15 +528,17 @@ class ReturnSimulation(BaseModel):
|
|
465
528
|
)
|
466
529
|
return sdf
|
467
530
|
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
531
|
+
df_list = [
|
532
|
+
DataFrame(
|
533
|
+
data=self.dframe.iloc[item].values,
|
534
|
+
index=Index(d_range),
|
535
|
+
columns=MultiIndex.from_arrays(
|
536
|
+
[
|
537
|
+
[f"{name}_{item}"],
|
538
|
+
[ValueType.RTRN],
|
539
|
+
],
|
540
|
+
),
|
477
541
|
)
|
478
|
-
|
479
|
-
|
542
|
+
for item in range(self.number_of_sims)
|
543
|
+
]
|
544
|
+
return concat(df_list, axis="columns", sort=True)
|
@@ -0,0 +1,126 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: openseries
|
3
|
+
Version: 2.0.0
|
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.14
|
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: License :: OSI Approved :: BSD License
|
44
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
45
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
46
|
+
Classifier: Natural Language :: English
|
47
|
+
Classifier: Development Status :: 5 - Production/Stable
|
48
|
+
Classifier: Operating System :: OS Independent
|
49
|
+
Classifier: Framework :: Pydantic
|
50
|
+
Requires-Dist: exchange-calendars (>=4.8,<6.0)
|
51
|
+
Requires-Dist: holidays (>=0.30,<1.0)
|
52
|
+
Requires-Dist: numpy (>=1.23.2,!=2.3.0,<3.0.0)
|
53
|
+
Requires-Dist: openpyxl (>=3.1.2,<5.0.0)
|
54
|
+
Requires-Dist: pandas (>=2.1.2,<3.0.0)
|
55
|
+
Requires-Dist: plotly (>=5.18.0,<7.0.0)
|
56
|
+
Requires-Dist: pydantic (>=2.5.2,<3.0.0)
|
57
|
+
Requires-Dist: python-dateutil (>=2.8.2,<4.0.0)
|
58
|
+
Requires-Dist: requests (>=2.20.0,<3.0.0)
|
59
|
+
Requires-Dist: scikit-learn (>=1.4.0,<2.0.0)
|
60
|
+
Requires-Dist: scipy (>=1.11.4,<2.0.0)
|
61
|
+
Project-URL: Documentation, https://openseries.readthedocs.io/
|
62
|
+
Project-URL: Homepage, https://github.com/CaptorAB/openseries
|
63
|
+
Project-URL: Issue Tracker, https://github.com/CaptorAB/openseries/issues
|
64
|
+
Project-URL: Release Notes, https://github.com/CaptorAB/openseries/releases
|
65
|
+
Project-URL: Source, https://github.com/CaptorAB/openseries
|
66
|
+
Description-Content-Type: text/markdown
|
67
|
+
|
68
|
+
<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/>
|
69
|
+
|
70
|
+
<br><br>
|
71
|
+
|
72
|
+
# openseries
|
73
|
+
|
74
|
+
[](https://pypi.org/project/openseries/)
|
75
|
+
[](https://anaconda.org/conda-forge/openseries)
|
76
|
+

|
77
|
+
[](https://www.python.org/)
|
78
|
+
[](https://github.com/CaptorAB/openseries/actions/workflows/test.yml)
|
79
|
+
[](https://codecov.io/gh/CaptorAB/openseries/branch/master)
|
80
|
+
[](https://python-poetry.org/)
|
81
|
+
[](https://beta.ruff.rs/docs/)
|
82
|
+
[](https://github.com/CaptorAB/openseries/blob/master/LICENSE.md)
|
83
|
+
[](https://nbviewer.org/github/karrmagadgeteer2/NoteBook/blob/master/openseriesnotebook.ipynb)
|
84
|
+
|
85
|
+
Tools for analyzing financial timeseries of a single asset or a group of assets. Designed for daily or less frequent data.
|
86
|
+
|
87
|
+
## Documentation
|
88
|
+
|
89
|
+
Complete documentation is available at: [https://openseries.readthedocs.io](https://openseries.readthedocs.io/)
|
90
|
+
|
91
|
+
The documentation includes:
|
92
|
+
|
93
|
+
- Quick start guide
|
94
|
+
- API reference
|
95
|
+
- Tutorials and examples
|
96
|
+
- Installation instructions
|
97
|
+
|
98
|
+
## Installation
|
99
|
+
|
100
|
+
```bash
|
101
|
+
pip install openseries
|
102
|
+
```
|
103
|
+
|
104
|
+
or:
|
105
|
+
|
106
|
+
```bash
|
107
|
+
conda install -c conda-forge openseries
|
108
|
+
```
|
109
|
+
|
110
|
+
## Quick Start
|
111
|
+
|
112
|
+
```python
|
113
|
+
from openseries import OpenTimeSeries
|
114
|
+
import yfinance as yf
|
115
|
+
|
116
|
+
move=yf.Ticker(ticker="^MOVE")
|
117
|
+
history=move.history(period="max")
|
118
|
+
series=OpenTimeSeries.from_df(dframe=history.loc[:, "Close"])
|
119
|
+
_=series.set_new_label(lvl_zero="ICE BofAML MOVE Index")
|
120
|
+
_,_=series.plot_series()
|
121
|
+
```
|
122
|
+
|
123
|
+
### Sample output using the report_html() function
|
124
|
+
|
125
|
+
<img src="https://raw.githubusercontent.com/CaptorAB/openseries/master/openseries_plot.png" alt="Two Assets Compared" width="1000" />
|
126
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
openseries/__init__.py,sha256=WVAO2vtZUZHp7wlXCXV_OKaLkPHfGUjfxTGgBsMdORc,1104
|
2
|
+
openseries/_common_model.py,sha256=vXVsSuD6ULTDT6A_sg58uS_yfoazQQvwtjo_jxKMQHA,89131
|
3
|
+
openseries/_risk.py,sha256=YisMnI8DQT0w9n9SQbrvq0ZZqmZHrz7-jhZtngObJRk,2094
|
4
|
+
openseries/datefixer.py,sha256=U1Kc6QdW3UEzAp61NIUALOllyLWb-mJemiL7KLfSAto,15512
|
5
|
+
openseries/frame.py,sha256=OCx4soNy_PzjOwpEzxhmdBUIbXjM2WzXv-JaW5GJ4U8,57343
|
6
|
+
openseries/load_plotly.py,sha256=sVssTMzJ2tPPHceCa9OCavI4Mv5BFgSKR6wnTltnqQQ,1997
|
7
|
+
openseries/owntypes.py,sha256=I709YjKqN9W9bJNNezhCQbnmTZgTIZZnoxzoUkbHF8w,9436
|
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.0.dist-info/METADATA,sha256=8L-PeC1b2pv8VfrC5upsvunrh1WNSiaOMvWg2BfxXZs,6085
|
16
|
+
openseries-2.0.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
17
|
+
openseries-2.0.0.dist-info/licenses/LICENSE.md,sha256=wNupG-KLsG0aTncb_SMNDh1ExtrKXlpxSJ6RC-g-SWs,1516
|
18
|
+
openseries-2.0.0.dist-info/RECORD,,
|