openseries 1.8.0__py3-none-any.whl → 1.8.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.
@@ -3,7 +3,6 @@
3
3
  # mypy: disable-error-code="index,assignment"
4
4
  from __future__ import annotations
5
5
 
6
- from collections.abc import Callable
7
6
  from inspect import stack
8
7
  from pathlib import Path
9
8
  from typing import TYPE_CHECKING, cast
@@ -22,7 +21,6 @@ from numpy import (
22
21
  from numpy import (
23
22
  sum as npsum,
24
23
  )
25
- from numpy.typing import NDArray
26
24
  from pandas import (
27
25
  DataFrame,
28
26
  Series,
@@ -35,10 +33,12 @@ from scipy.optimize import minimize # type: ignore[import-untyped,unused-ignore
35
33
 
36
34
  from .load_plotly import load_plotly_dict
37
35
  from .owntypes import (
36
+ AtLeastOneFrameError,
38
37
  LiteralLinePlotMode,
39
38
  LiteralMinimizeMethods,
40
39
  LiteralPlotlyJSlib,
41
40
  LiteralPlotlyOutput,
41
+ MixedValuetypesError,
42
42
  ValueType,
43
43
  )
44
44
  from .series import OpenTimeSeries
@@ -47,6 +47,9 @@ from .series import OpenTimeSeries
47
47
  from .simulation import _random_generator
48
48
 
49
49
  if TYPE_CHECKING: # pragma: no cover
50
+ from collections.abc import Callable
51
+
52
+ from numpy.typing import NDArray
50
53
  from pydantic import DirectoryPath
51
54
 
52
55
  from .frame import OpenFrame
@@ -92,7 +95,7 @@ def simulate_portfolios(
92
95
  log_ret = copi.tsdf.copy()
93
96
  else:
94
97
  msg = "Mix of series types will give inconsistent results"
95
- raise ValueError(msg)
98
+ raise MixedValuetypesError(msg)
96
99
 
97
100
  log_ret.columns = log_ret.columns.droplevel(level=1)
98
101
 
@@ -128,7 +131,7 @@ def simulate_portfolios(
128
131
 
129
132
 
130
133
  # noinspection PyUnusedLocal
131
- def efficient_frontier( # noqa: C901
134
+ def efficient_frontier(
132
135
  eframe: OpenFrame,
133
136
  num_ports: int = 5000,
134
137
  seed: int = 71,
@@ -176,7 +179,7 @@ def efficient_frontier( # noqa: C901
176
179
  log_ret = copi.tsdf.copy()
177
180
  else:
178
181
  msg = "Mix of series types will give inconsistent results"
179
- raise ValueError(msg)
182
+ raise MixedValuetypesError(msg)
180
183
 
181
184
  log_ret.columns = log_ret.columns.droplevel(level=1)
182
185
 
@@ -200,7 +203,7 @@ def efficient_frontier( # noqa: C901
200
203
  ret = npsum(lg_ret.mean() * weights) * per_in_yr
201
204
  volatility = sqrt(weights.T @ (lg_ret.cov() * per_in_yr @ weights))
202
205
  sr = ret / volatility
203
- return cast(NDArray[float64], array([ret, volatility, sr]))
206
+ return cast("NDArray[float64]", array([ret, volatility, sr]))
204
207
 
205
208
  def _diff_return(
206
209
  lg_ret: DataFrame,
@@ -209,14 +212,14 @@ def efficient_frontier( # noqa: C901
209
212
  poss_return: float,
210
213
  ) -> float64:
211
214
  return cast(
212
- float64,
215
+ "float64",
213
216
  _get_ret_vol_sr(lg_ret=lg_ret, weights=weights, per_in_yr=per_in_yr)[0]
214
217
  - poss_return,
215
218
  )
216
219
 
217
220
  def _neg_sharpe(weights: NDArray[float64]) -> float64:
218
221
  return cast(
219
- float64,
222
+ "float64",
220
223
  _get_ret_vol_sr(
221
224
  lg_ret=log_ret,
222
225
  weights=weights,
@@ -229,7 +232,7 @@ def efficient_frontier( # noqa: C901
229
232
  weights: NDArray[float64],
230
233
  ) -> float64:
231
234
  return cast(
232
- float64,
235
+ "float64",
233
236
  _get_ret_vol_sr(
234
237
  lg_ret=log_ret,
235
238
  weights=weights,
@@ -262,7 +265,7 @@ def efficient_frontier( # noqa: C901
262
265
 
263
266
  for possible_return in frontier_y:
264
267
  cons = cast(
265
- dict[str, str | Callable[[float, NDArray[float64]], float64]],
268
+ "dict[str, str | Callable[[float, NDArray[float64]], float64]]",
266
269
  (
267
270
  {"type": "eq", "fun": _check_sum},
268
271
  {
@@ -414,7 +417,7 @@ def prepare_plot_data(
414
417
  [
415
418
  f"{wgt:.1%} {nm}"
416
419
  for wgt, nm in zip(
417
- cast(list[float], assets.weights),
420
+ cast("list[float]", assets.weights),
418
421
  assets.columns_lvl_zero,
419
422
  strict=True,
420
423
  )
@@ -445,7 +448,7 @@ def prepare_plot_data(
445
448
  return plotframe
446
449
 
447
450
 
448
- def sharpeplot( # noqa: C901
451
+ def sharpeplot(
449
452
  sim_frame: DataFrame | None = None,
450
453
  line_frame: DataFrame | None = None,
451
454
  point_frame: DataFrame | None = None,
@@ -514,7 +517,7 @@ def sharpeplot( # noqa: C901
514
517
 
515
518
  if sim_frame is None and line_frame is None and point_frame is None:
516
519
  msg = "One of sim_frame, line_frame or point_frame must be provided."
517
- raise ValueError(msg)
520
+ raise AtLeastOneFrameError(msg)
518
521
 
519
522
  if sim_frame is not None:
520
523
  returns.extend(list(sim_frame.loc[:, "ret"]))
@@ -552,7 +555,7 @@ def sharpeplot( # noqa: C901
552
555
 
553
556
  if point_frame is not None:
554
557
  colorway = cast(
555
- dict[str, str | int | float | bool | list[str]],
558
+ "dict[str, str | int | float | bool | list[str]]",
556
559
  fig["layout"],
557
560
  ).get("colorway")[: len(point_frame.columns)]
558
561
  for col, clr in zip(point_frame.columns, colorway, strict=True):
@@ -600,7 +603,7 @@ def sharpeplot( # noqa: C901
600
603
  auto_open=auto_open,
601
604
  auto_play=False,
602
605
  link_text="",
603
- include_plotlyjs=cast(bool, include_plotlyjs),
606
+ include_plotlyjs=cast("bool", include_plotlyjs),
604
607
  config=fig["config"],
605
608
  output_type=output_type,
606
609
  )
@@ -611,7 +614,7 @@ def sharpeplot( # noqa: C901
611
614
  fig=figure,
612
615
  config=fig["config"],
613
616
  auto_play=False,
614
- include_plotlyjs=cast(bool, include_plotlyjs),
617
+ include_plotlyjs=cast("bool", include_plotlyjs),
615
618
  full_html=False,
616
619
  div_id=div_id,
617
620
  )
openseries/series.py CHANGED
@@ -1,12 +1,15 @@
1
1
  """Defining the OpenTimeSeries class."""
2
2
 
3
+ # mypy: disable-error-code="no-any-return"
3
4
  from __future__ import annotations
4
5
 
5
- import datetime as dt
6
6
  from collections.abc import Iterable
7
7
  from copy import deepcopy
8
- from logging import warning
9
- from typing import Any, TypeVar, cast
8
+ from logging import getLogger
9
+ from typing import TYPE_CHECKING, Any, TypeVar, cast
10
+
11
+ if TYPE_CHECKING: # pragma: no cover
12
+ import datetime as dt
10
13
 
11
14
  from numpy import (
12
15
  append,
@@ -27,7 +30,6 @@ from pandas import (
27
30
  date_range,
28
31
  )
29
32
  from pydantic import field_validator, model_validator
30
- from typing_extensions import Self
31
33
 
32
34
  from ._common_model import _CommonModel
33
35
  from .datefixer import _do_resample_to_business_period_ends, date_fix
@@ -36,22 +38,27 @@ from .owntypes import (
36
38
  CountriesType,
37
39
  Currency,
38
40
  CurrencyStringType,
41
+ DateAlignmentError,
39
42
  DateListType,
40
43
  DaysInYearType,
44
+ IncorrectArgumentComboError,
41
45
  LiteralBizDayFreq,
42
46
  LiteralPandasReindexMethod,
43
47
  LiteralSeriesProps,
44
48
  OpenTimeSeriesPropertiesList,
49
+ Self,
45
50
  ValueListType,
46
51
  ValueType,
47
52
  )
48
53
 
54
+ logger = getLogger(__name__)
55
+
49
56
  __all__ = ["OpenTimeSeries", "timeseries_chain"]
50
57
 
51
58
  TypeOpenTimeSeries = TypeVar("TypeOpenTimeSeries", bound="OpenTimeSeries")
52
59
 
53
60
 
54
- # noinspection PyUnresolvedReferences
61
+ # noinspection PyUnresolvedReferences,PyNestedDecorators
55
62
  class OpenTimeSeries(_CommonModel):
56
63
  """OpenTimeSeries objects are at the core of the openseries package.
57
64
 
@@ -142,7 +149,7 @@ class OpenTimeSeries(_CommonModel):
142
149
 
143
150
  @classmethod
144
151
  def from_arrays(
145
- cls: type[OpenTimeSeries],
152
+ cls,
146
153
  name: str,
147
154
  dates: DateListType,
148
155
  values: ValueListType,
@@ -153,7 +160,7 @@ class OpenTimeSeries(_CommonModel):
153
160
  baseccy: CurrencyStringType = "SEK",
154
161
  *,
155
162
  local_ccy: bool = True,
156
- ) -> OpenTimeSeries:
163
+ ) -> Self:
157
164
  """Create series from a Pandas DataFrame or Series.
158
165
 
159
166
  Parameters
@@ -204,14 +211,14 @@ class OpenTimeSeries(_CommonModel):
204
211
 
205
212
  @classmethod
206
213
  def from_df(
207
- cls: type[OpenTimeSeries],
214
+ cls,
208
215
  dframe: Series[float] | DataFrame,
209
216
  column_nmbr: int = 0,
210
217
  valuetype: ValueType = ValueType.PRICE,
211
218
  baseccy: CurrencyStringType = "SEK",
212
219
  *,
213
220
  local_ccy: bool = True,
214
- ) -> OpenTimeSeries:
221
+ ) -> Self:
215
222
  """Create series from a Pandas DataFrame or Series.
216
223
 
217
224
  Parameters
@@ -240,7 +247,7 @@ class OpenTimeSeries(_CommonModel):
240
247
  label, _ = dframe.name
241
248
  else:
242
249
  label = dframe.name
243
- values = cast(list[float], dframe.to_numpy().tolist())
250
+ values = cast("list[float]", dframe.to_numpy().tolist())
244
251
  elif isinstance(dframe, DataFrame):
245
252
  values = dframe.iloc[:, column_nmbr].to_list()
246
253
  if isinstance(dframe.columns, MultiIndex):
@@ -249,7 +256,7 @@ class OpenTimeSeries(_CommonModel):
249
256
  ):
250
257
  label = "Series"
251
258
  msg = f"Label missing. Adding: {label}"
252
- warning(msg=msg)
259
+ logger.warning(msg=msg)
253
260
  else:
254
261
  label = dframe.columns.get_level_values(0).to_numpy()[column_nmbr]
255
262
  if _check_if_none(
@@ -257,13 +264,13 @@ class OpenTimeSeries(_CommonModel):
257
264
  ):
258
265
  valuetype = ValueType.PRICE
259
266
  msg = f"valuetype missing. Adding: {valuetype.value}"
260
- warning(msg=msg)
267
+ logger.warning(msg=msg)
261
268
  else:
262
269
  valuetype = dframe.columns.get_level_values(1).to_numpy()[
263
270
  column_nmbr
264
271
  ]
265
272
  else:
266
- label = cast(MultiIndex, dframe.columns).to_numpy()[column_nmbr]
273
+ label = cast("MultiIndex", dframe.columns).to_numpy()[column_nmbr]
267
274
  else:
268
275
  raise TypeError(msg)
269
276
 
@@ -289,7 +296,7 @@ class OpenTimeSeries(_CommonModel):
289
296
 
290
297
  @classmethod
291
298
  def from_fixed_rate(
292
- cls: type[OpenTimeSeries],
299
+ cls,
293
300
  rate: float,
294
301
  d_range: DatetimeIndex | None = None,
295
302
  days: int | None = None,
@@ -299,7 +306,7 @@ class OpenTimeSeries(_CommonModel):
299
306
  baseccy: CurrencyStringType = "SEK",
300
307
  *,
301
308
  local_ccy: bool = True,
302
- ) -> OpenTimeSeries:
309
+ ) -> Self:
303
310
  """Create series from values accruing with a given fixed rate return.
304
311
 
305
312
  Providing a date_range of type Pandas DatetimeIndex takes priority over
@@ -338,7 +345,7 @@ class OpenTimeSeries(_CommonModel):
338
345
  )
339
346
  elif not isinstance(d_range, Iterable) and not all([days, end_dt]):
340
347
  msg = "If d_range is not provided both days and end_dt must be."
341
- raise ValueError(msg)
348
+ raise IncorrectArgumentComboError(msg)
342
349
 
343
350
  deltas = array(
344
351
  [i.days for i in DatetimeIndex(d_range)[1:] - DatetimeIndex(d_range)[:-1]], # type: ignore[arg-type]
@@ -413,7 +420,7 @@ class OpenTimeSeries(_CommonModel):
413
420
  """
414
421
  if not properties:
415
422
  properties = cast(
416
- list[LiteralSeriesProps],
423
+ "list[LiteralSeriesProps]",
417
424
  OpenTimeSeriesPropertiesList.allowed_strings,
418
425
  )
419
426
 
@@ -435,7 +442,9 @@ class OpenTimeSeries(_CommonModel):
435
442
  returns.iloc[0] = 0
436
443
  self.valuetype = ValueType.RTRN
437
444
  arrays = [[self.label], [self.valuetype]]
438
- returns.columns = MultiIndex.from_arrays(arrays=arrays)
445
+ returns.columns = MultiIndex.from_arrays(
446
+ arrays=arrays # type: ignore[arg-type,unused-ignore]
447
+ )
439
448
  self.tsdf = returns.copy()
440
449
  return self
441
450
 
@@ -624,26 +633,26 @@ class OpenTimeSeries(_CommonModel):
624
633
  time_factor = float(periods_in_a_year_fixed)
625
634
  else:
626
635
  how_many = self.tsdf.loc[
627
- cast(int, earlier) : cast(int, later),
636
+ cast("int", earlier) : cast("int", later),
628
637
  self.tsdf.columns.to_numpy()[0],
629
638
  ].count()
630
639
  fraction = (later - earlier).days / 365.25
631
640
  time_factor = how_many / fraction
632
641
 
633
- data = self.tsdf.loc[cast(int, earlier) : cast(int, later)].copy()
642
+ data = self.tsdf.loc[cast("int", earlier) : cast("int", later)].copy()
634
643
 
635
644
  data[self.label, ValueType.RTRN] = (
636
645
  data.loc[:, self.tsdf.columns.to_numpy()[0]].apply(log).diff()
637
646
  )
638
647
 
639
648
  rawdata = [
640
- data.loc[:, cast(int, (self.label, ValueType.RTRN))]
649
+ data.loc[:, cast("int", (self.label, ValueType.RTRN))]
641
650
  .iloc[1:day_chunk]
642
651
  .std(ddof=dlta_degr_freedms)
643
652
  * sqrt(time_factor),
644
653
  ]
645
654
 
646
- for item in data.loc[:, cast(int, (self.label, ValueType.RTRN))].iloc[1:]:
655
+ for item in data.loc[:, cast("int", (self.label, ValueType.RTRN))].iloc[1:]:
647
656
  prev = rawdata[-1]
648
657
  rawdata.append(
649
658
  sqrt(
@@ -684,7 +693,7 @@ class OpenTimeSeries(_CommonModel):
684
693
  values = [1.0]
685
694
  returns_input = True
686
695
  else:
687
- values = [cast(float, self.tsdf.iloc[0, 0])]
696
+ values = [cast("float", self.tsdf.iloc[0, 0])]
688
697
  ra_df = self.tsdf.ffill().pct_change()
689
698
  returns_input = False
690
699
  ra_df = ra_df.dropna()
@@ -693,16 +702,16 @@ class OpenTimeSeries(_CommonModel):
693
702
  dates: list[dt.date] = [prev]
694
703
 
695
704
  for idx, row in ra_df.iterrows():
696
- dates.append(cast(dt.date, idx))
705
+ dates.append(cast("dt.date", idx))
697
706
  values.append(
698
707
  values[-1]
699
708
  * (
700
709
  1
701
710
  + row.iloc[0]
702
- + adjustment * (cast(dt.date, idx) - prev).days / days_in_year
711
+ + adjustment * (cast("dt.date", idx) - prev).days / days_in_year
703
712
  ),
704
713
  )
705
- prev = cast(dt.date, idx)
714
+ prev = cast("dt.date", idx)
706
715
  self.tsdf = DataFrame(data=values, index=dates)
707
716
  self.valuetype = ValueType.PRICE
708
717
  self.tsdf.columns = MultiIndex.from_arrays(
@@ -752,7 +761,7 @@ class OpenTimeSeries(_CommonModel):
752
761
  self.valuetype = lvl_one
753
762
  else:
754
763
  self.tsdf.columns = MultiIndex.from_arrays([[lvl_zero], [lvl_one]])
755
- self.label, self.valuetype = lvl_zero, cast(ValueType, lvl_one)
764
+ self.label, self.valuetype = lvl_zero, cast("ValueType", lvl_one)
756
765
  if delete_lvl_one:
757
766
  self.tsdf.columns = self.tsdf.columns.droplevel(level=1)
758
767
  return self
@@ -762,7 +771,7 @@ def timeseries_chain(
762
771
  front: TypeOpenTimeSeries,
763
772
  back: TypeOpenTimeSeries,
764
773
  old_fee: float = 0.0,
765
- ) -> TypeOpenTimeSeries | OpenTimeSeries:
774
+ ) -> TypeOpenTimeSeries:
766
775
  """Chain two timeseries together.
767
776
 
768
777
  The function assumes that the two series have at least one date in common.
@@ -778,7 +787,7 @@ def timeseries_chain(
778
787
 
779
788
  Returns
780
789
  -------
781
- TypeOpenTimeSeries | OpenTimeSeries
790
+ TypeOpenTimeSeries
782
791
  An OpenTimeSeries object or a subclass thereof
783
792
 
784
793
  """
@@ -790,14 +799,14 @@ def timeseries_chain(
790
799
 
791
800
  if old.last_idx < first:
792
801
  msg = "Timeseries dates must overlap to allow them to be chained."
793
- raise ValueError(msg)
802
+ raise DateAlignmentError(msg)
794
803
 
795
804
  while first not in old.tsdf.index:
796
805
  idx += 1
797
806
  first = new.tsdf.index[idx]
798
807
  if first > old.tsdf.index[-1]:
799
808
  msg = "Failed to find a matching date between series"
800
- raise ValueError(msg)
809
+ raise DateAlignmentError(msg)
801
810
 
802
811
  dates: list[str] = [x.strftime("%Y-%m-%d") for x in old.tsdf.index if x < first]
803
812
 
@@ -809,27 +818,6 @@ def timeseries_chain(
809
818
 
810
819
  dates.extend([x.strftime("%Y-%m-%d") for x in new.tsdf.index])
811
820
 
812
- # noinspection PyUnresolvedReferences
813
- if back.__class__.__subclasscheck__(
814
- OpenTimeSeries,
815
- ):
816
- return OpenTimeSeries(
817
- timeseries_id=new.timeseries_id,
818
- instrument_id=new.instrument_id,
819
- currency=new.currency,
820
- dates=dates,
821
- name=new.name,
822
- label=new.name,
823
- valuetype=new.valuetype,
824
- values=list(values),
825
- local_ccy=new.local_ccy,
826
- tsdf=DataFrame(
827
- data=values,
828
- index=[d.date() for d in DatetimeIndex(dates)],
829
- columns=[[new.label], [new.valuetype]],
830
- dtype="float64",
831
- ),
832
- )
833
821
  return back.__class__(
834
822
  timeseries_id=new.timeseries_id,
835
823
  instrument_id=new.instrument_id,
@@ -864,7 +852,7 @@ def _check_if_none(item: Any) -> bool: # noqa: ANN401
864
852
 
865
853
  """
866
854
  try:
867
- return cast(bool, isnan(item))
855
+ return cast("bool", isnan(item))
868
856
  except TypeError:
869
857
  if item is None:
870
858
  return True
openseries/simulation.py CHANGED
@@ -1,5 +1,6 @@
1
1
  """Defining the ReturnSimulation class."""
2
2
 
3
+ # mypy: disable-error-code="no-any-return"
3
4
  from __future__ import annotations
4
5
 
5
6
  from typing import TYPE_CHECKING, cast
@@ -22,12 +23,12 @@ from pydantic import (
22
23
  PositiveFloat,
23
24
  PositiveInt,
24
25
  )
25
- from typing_extensions import Self
26
26
 
27
27
  from .datefixer import generate_calendar_date_range
28
28
  from .owntypes import (
29
29
  CountriesType,
30
30
  DaysInYearType,
31
+ Self,
31
32
  ValueType,
32
33
  )
33
34
 
@@ -49,7 +50,7 @@ def _random_generator(seed: int | None) -> Generator:
49
50
 
50
51
  """
51
52
  ss = SeedSequence(entropy=seed)
52
- bg = PCG64(seed=cast(int | None, ss))
53
+ bg = PCG64(seed=cast("int | None", ss))
53
54
  return Generator(bit_generator=bg)
54
55
 
55
56
 
@@ -121,7 +122,7 @@ class ReturnSimulation(BaseModel):
121
122
 
122
123
  """
123
124
  return cast(
124
- float,
125
+ "float",
125
126
  (
126
127
  self.results.ffill().pct_change().mean() * self.trading_days_in_year
127
128
  ).iloc[0],
@@ -138,7 +139,7 @@ class ReturnSimulation(BaseModel):
138
139
 
139
140
  """
140
141
  return cast(
141
- float,
142
+ "float",
142
143
  (
143
144
  self.results.ffill().pct_change().std()
144
145
  * sqrt(self.trading_days_in_year)
@@ -0,0 +1,27 @@
1
+ # BSD 3-Clause License
2
+
3
+ ## Copyright (c) Captor Fund Management AB
4
+
5
+ Redistribution and use in source and binary forms, with or without modification, are
6
+ permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this list of
9
+ conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
12
+ of conditions and the following disclaimer in the documentation and/or other
13
+ materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its contributors may be
16
+ used to endorse or promote products derived from this software without specific prior
17
+ written permission.
18
+
19
+ This software is provided by the copyright holders and contributors “as is” and any
20
+ express or implied warranties, including, but not limited to, the implied warranties of
21
+ merchantability and fitness for a particular purpose, are disclaimed. In no event shall
22
+ the copyright holder or contributors be liable for any direct, indirect, incidental,
23
+ special, exemplary, or consequential damages (including, but not limited to, procurement
24
+ of substitute goods or services; loss of use, data, or profits; or business interruption)
25
+ however caused and on any theory of liability, whether in contract, strict liability,
26
+ or tort (including negligence or otherwise) arising in any way out of the use of this
27
+ software, even if advised of the possibility of such damage.
@@ -1,8 +1,34 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openseries
3
- Version: 1.8.0
3
+ Version: 1.8.1
4
4
  Summary: Tools for analyzing financial timeseries.
5
- License: BSD-3-Clause
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.
6
32
  Keywords: python,finance,fintech,data-science,timeseries,timeseries-data,timeseries-analysis,investment,investment-analysis,investing
7
33
  Author: Martin Karrin
8
34
  Author-email: martin.karrin@captor.se
@@ -22,18 +48,19 @@ Classifier: Operating System :: OS Independent
22
48
  Classifier: Framework :: Pydantic
23
49
  Requires-Dist: holidays (>=0.30,<1.0)
24
50
  Requires-Dist: numpy (>=1.23.2,<3.0.0)
25
- Requires-Dist: openpyxl (>=3.1.2,<4.0.0)
51
+ Requires-Dist: openpyxl (>=3.1.2,<5.0.0)
26
52
  Requires-Dist: pandas (>=2.1.2,<3.0.0)
27
- Requires-Dist: plotly (>=5.18.0,<6.0.0)
28
- Requires-Dist: pyarrow (>=14.0.2,<20.0.0)
53
+ Requires-Dist: plotly (>=5.18.0,<7.0.0)
54
+ Requires-Dist: pyarrow (>=14.0.2,<21.0.0)
29
55
  Requires-Dist: pydantic (>=2.5.2,<3.0.0)
30
- Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
56
+ Requires-Dist: python-dateutil (>=2.8.2,<4.0.0)
31
57
  Requires-Dist: requests (>=2.20.0,<3.0.0)
32
58
  Requires-Dist: scipy (>=1.11.4,<2.0.0)
33
59
  Requires-Dist: statsmodels (>=0.14.0,!=0.14.2,<1.0.0)
34
- Project-URL: Documentation, https://github.com/CaptorAB/openseries
35
60
  Project-URL: Homepage, https://github.com/CaptorAB/openseries
36
- Project-URL: Repository, https://github.com/CaptorAB/openseries
61
+ Project-URL: Issue Tracker, https://github.com/CaptorAB/openseries/issues
62
+ Project-URL: Release Notes, https://github.com/CaptorAB/openseries/releases
63
+ Project-URL: Source, https://github.com/CaptorAB/openseries
37
64
  Description-Content-Type: text/markdown
38
65
 
39
66
  <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/>
@@ -194,11 +221,12 @@ make lint
194
221
 
195
222
  ### On some files in the project
196
223
 
197
- | File | Description |
198
- |:-----------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
199
- | [series.py](https://github.com/CaptorAB/openseries/blob/master/openseries/series.py) | Defines the class _OpenTimeSeries_ for managing and analyzing a single timeseries. The module also defines a function `timeseries_chain` that can be used to chain two timeseries objects together. |
200
- | [frame.py](https://github.com/CaptorAB/openseries/blob/master/openseries/frame.py) | Defines the class _OpenFrame_ for managing a group of timeseries, and e.g. calculate a portfolio timeseries from a rebalancing strategy between timeseries. The module also defines functions to simulate, optimize, and plot portfolios. |
201
- | [simulation.py](https://github.com/CaptorAB/openseries/blob/master/openseries/simulation.py) | Defines the class _ReturnSimulation_ to create simulated financial timeseries. Used in the project's test suite |
224
+ | File | Description |
225
+ |:-----------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
226
+ | [series.py](https://github.com/CaptorAB/openseries/blob/master/openseries/series.py) | Defines the class _OpenTimeSeries_ for managing and analyzing a single timeseries. The module also defines a function `timeseries_chain` that can be used to chain two timeseries objects together. |
227
+ | [frame.py](https://github.com/CaptorAB/openseries/blob/master/openseries/frame.py) | Defines the class _OpenFrame_ for managing a group of timeseries, and e.g. calculate a portfolio timeseries from a rebalancing strategy between timeseries. |
228
+ | [portfoliotools.py](https://github.com/CaptorAB/openseries/blob/master/openseries/portfoliotools.py) | Defines functions to simulate, optimize, and plot portfolios. |
229
+ | [simulation.py](https://github.com/CaptorAB/openseries/blob/master/openseries/simulation.py) | Defines the class _ReturnSimulation_ to create simulated financial timeseries. Used in the project's test suite |
202
230
 
203
231
  ### Class methods used to construct objects.
204
232
 
@@ -0,0 +1,16 @@
1
+ openseries/__init__.py,sha256=dKw_wEfgrCwwV1IRljesrtxjE9AVFwTyhE8k4CFIck8,1053
2
+ openseries/_common_model.py,sha256=x1CqaMjWo-nG-sRYxhKaIT_UBPGhfsNTGFF2x4tf3Gk,74451
3
+ openseries/_risk.py,sha256=5Lu4vK2oQlDdtv5WKD2ZTGrMIlsa0TiPxk6opgtnVlA,2084
4
+ openseries/datefixer.py,sha256=w_3lH9cmAm-Xl8t8-X3FdW22AA3zb5OqS0A4FrgS9vc,12479
5
+ openseries/frame.py,sha256=j5kD6s6kXLDjlSQEpKaFzT1bDN9Pmb2PbAF-hSf-NGc,55894
6
+ openseries/load_plotly.py,sha256=CzD-ZJNk6WGzIkzIHso4aULDpoWXsjH3xL7p7MP0lqY,1998
7
+ openseries/owntypes.py,sha256=aqidJ09w3autlgLD6fVEtANbgzh28K53gWDB6j_P4T4,9047
8
+ openseries/plotly_captor_logo.json,sha256=F5nhMzEyxKywtjvQqMTKgKRCJQYMDIiBgDSxdte8Clo,178
9
+ openseries/plotly_layouts.json,sha256=im8QZPRB--zV_rOu1OiSbvJPA52oJ6QZRFzkwB1C708,1430
10
+ openseries/portfoliotools.py,sha256=8XTjPMPHuazh20LeYj-y4hTZnGX8hrArLwS9Ot_MufM,19261
11
+ openseries/series.py,sha256=rwd-J_cD1lElC7W65kt2xGLPHFRfmWAwxe_KEJvi3Pc,27099
12
+ openseries/simulation.py,sha256=TLEsIZq8SzQ5BRQqjQMIeCY8ibPX5tkftnx4R-zLspQ,13905
13
+ openseries-1.8.1.dist-info/LICENSE.md,sha256=wNupG-KLsG0aTncb_SMNDh1ExtrKXlpxSJ6RC-g-SWs,1516
14
+ openseries-1.8.1.dist-info/METADATA,sha256=JcL-WQlrWAvJu2cfcxNwqDKsIrSgFrK6Uad2jqC-Xzs,45658
15
+ openseries-1.8.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
16
+ openseries-1.8.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.0.1
2
+ Generator: poetry-core 2.1.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,27 +0,0 @@
1
- # BSD 3-Clause License
2
-
3
- ## Copyright (c) Captor Fund Management AB
4
-
5
- Redistribution and use in source and binary forms, with or without modification, are
6
- permitted provided that the following conditions are met:
7
-
8
- 1. Redistributions of source code must retain the above copyright notice, this list of
9
- conditions and the following disclaimer.
10
-
11
- 2. Redistributions in binary form must reproduce the above copyright notice, this list
12
- of conditions and the following disclaimer in the documentation and/or other
13
- materials provided with the distribution.
14
-
15
- 3. Neither the name of the copyright holder nor the names of its contributors may be
16
- used to endorse or promote products derived from this software without specific prior
17
- written permission.
18
-
19
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY
20
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22
- THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24
- OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.