openseries 1.8.2__py3-none-any.whl → 1.8.4__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/_common_model.py +220 -4
- openseries/datefixer.py +120 -32
- openseries/frame.py +2 -6
- openseries/owntypes.py +13 -10
- openseries/plotly_layouts.json +1 -1
- openseries/series.py +24 -0
- openseries/simulation.py +4 -0
- {openseries-1.8.2.dist-info → openseries-1.8.4.dist-info}/METADATA +34 -33
- openseries-1.8.4.dist-info/RECORD +16 -0
- {openseries-1.8.2.dist-info → openseries-1.8.4.dist-info}/WHEEL +1 -1
- openseries-1.8.2.dist-info/RECORD +0 -16
- {openseries-1.8.2.dist-info → openseries-1.8.4.dist-info}/LICENSE.md +0 -0
openseries/_common_model.py
CHANGED
@@ -33,6 +33,10 @@ if TYPE_CHECKING: # pragma: no cover
|
|
33
33
|
LiteralLinePlotMode,
|
34
34
|
LiteralNanMethod,
|
35
35
|
LiteralPandasReindexMethod,
|
36
|
+
LiteralPlotlyHistogramBarMode,
|
37
|
+
LiteralPlotlyHistogramCurveType,
|
38
|
+
LiteralPlotlyHistogramHistNorm,
|
39
|
+
LiteralPlotlyHistogramPlotType,
|
36
40
|
LiteralPlotlyJSlib,
|
37
41
|
LiteralPlotlyOutput,
|
38
42
|
LiteralQuantileInterp,
|
@@ -50,10 +54,11 @@ from pandas import (
|
|
50
54
|
to_datetime,
|
51
55
|
)
|
52
56
|
from pandas.tseries.offsets import CustomBusinessDay
|
57
|
+
from plotly.figure_factory import create_distplot # type: ignore[import-untyped]
|
53
58
|
from plotly.graph_objs import Figure # type: ignore[import-untyped]
|
54
59
|
from plotly.io import to_html # type: ignore[import-untyped]
|
55
60
|
from plotly.offline import plot # type: ignore[import-untyped]
|
56
|
-
from pydantic import BaseModel, ConfigDict, DirectoryPath
|
61
|
+
from pydantic import BaseModel, ConfigDict, DirectoryPath, ValidationError
|
57
62
|
from scipy.stats import ( # type: ignore[import-untyped]
|
58
63
|
kurtosis,
|
59
64
|
norm,
|
@@ -372,13 +377,23 @@ class _CommonModel(BaseModel): # type: ignore[misc]
|
|
372
377
|
|
373
378
|
"""
|
374
379
|
method: LiteralPandasReindexMethod = "nearest"
|
375
|
-
|
380
|
+
|
381
|
+
try:
|
382
|
+
countries = self.countries
|
383
|
+
markets = self.markets
|
384
|
+
except AttributeError:
|
385
|
+
countries = self.constituents[0].countries
|
386
|
+
markets = self.constituents[0].markets
|
387
|
+
|
376
388
|
wmdf = self.tsdf.copy()
|
389
|
+
|
377
390
|
dates = _do_resample_to_business_period_ends(
|
378
391
|
data=wmdf,
|
379
392
|
freq="BME",
|
380
393
|
countries=countries,
|
394
|
+
markets=markets,
|
381
395
|
)
|
396
|
+
|
382
397
|
wmdf = wmdf.reindex(index=[deyt.date() for deyt in dates], method=method)
|
383
398
|
wmdf.index = DatetimeIndex(wmdf.index)
|
384
399
|
result = wmdf.ffill().pct_change().min()
|
@@ -534,14 +549,20 @@ class _CommonModel(BaseModel): # type: ignore[misc]
|
|
534
549
|
|
535
550
|
def align_index_to_local_cdays(
|
536
551
|
self: Self,
|
537
|
-
countries: CountriesType =
|
552
|
+
countries: CountriesType | None = None,
|
553
|
+
markets: list[str] | str | None = None,
|
554
|
+
custom_holidays: list[str] | str | None = None,
|
538
555
|
) -> Self:
|
539
556
|
"""Align the index of .tsdf with local calendar business days.
|
540
557
|
|
541
558
|
Parameters
|
542
559
|
----------
|
543
|
-
countries: CountriesType,
|
560
|
+
countries: CountriesType, optional
|
544
561
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
562
|
+
markets: list[str] | str, optional
|
563
|
+
(List of) markets code(s) according to pandas-market-calendars
|
564
|
+
custom_holidays: list[str] | str, optional
|
565
|
+
Argument where missing holidays can be added
|
545
566
|
|
546
567
|
Returns:
|
547
568
|
-------
|
@@ -551,10 +572,37 @@ class _CommonModel(BaseModel): # type: ignore[misc]
|
|
551
572
|
"""
|
552
573
|
startyear = cast("int", to_datetime(self.tsdf.index[0]).year)
|
553
574
|
endyear = cast("int", to_datetime(self.tsdf.index[-1]).year)
|
575
|
+
|
576
|
+
if countries:
|
577
|
+
try:
|
578
|
+
self.countries = countries
|
579
|
+
except ValidationError:
|
580
|
+
for serie in self.constituents:
|
581
|
+
serie.countries = countries
|
582
|
+
else:
|
583
|
+
try:
|
584
|
+
countries = self.countries
|
585
|
+
except AttributeError:
|
586
|
+
countries = self.constituents[0].countries
|
587
|
+
|
588
|
+
if markets:
|
589
|
+
try:
|
590
|
+
self.markets = markets
|
591
|
+
except ValidationError:
|
592
|
+
for serie in self.constituents:
|
593
|
+
serie.markets = markets
|
594
|
+
else:
|
595
|
+
try:
|
596
|
+
markets = self.markets
|
597
|
+
except AttributeError:
|
598
|
+
markets = self.constituents[0].markets
|
599
|
+
|
554
600
|
calendar = holiday_calendar(
|
555
601
|
startyear=startyear,
|
556
602
|
endyear=endyear,
|
557
603
|
countries=countries,
|
604
|
+
markets=markets,
|
605
|
+
custom_holidays=custom_holidays,
|
558
606
|
)
|
559
607
|
|
560
608
|
d_range = [
|
@@ -1005,6 +1053,174 @@ class _CommonModel(BaseModel): # type: ignore[misc]
|
|
1005
1053
|
|
1006
1054
|
return figure, string_output
|
1007
1055
|
|
1056
|
+
def plot_histogram(
|
1057
|
+
self: Self,
|
1058
|
+
plot_type: LiteralPlotlyHistogramPlotType = "bars",
|
1059
|
+
histnorm: LiteralPlotlyHistogramHistNorm = "percent",
|
1060
|
+
barmode: LiteralPlotlyHistogramBarMode = "overlay",
|
1061
|
+
xbins_size: float | None = None,
|
1062
|
+
opacity: float = 0.75,
|
1063
|
+
bargap: float = 0.0,
|
1064
|
+
bargroupgap: float = 0.0,
|
1065
|
+
curve_type: LiteralPlotlyHistogramCurveType = "kde",
|
1066
|
+
x_fmt: str | None = None,
|
1067
|
+
y_fmt: str | None = None,
|
1068
|
+
filename: str | None = None,
|
1069
|
+
directory: DirectoryPath | None = None,
|
1070
|
+
labels: list[str] | None = None,
|
1071
|
+
output_type: LiteralPlotlyOutput = "file",
|
1072
|
+
include_plotlyjs: LiteralPlotlyJSlib = "cdn",
|
1073
|
+
*,
|
1074
|
+
cumulative: bool = False,
|
1075
|
+
show_rug: bool = False,
|
1076
|
+
auto_open: bool = True,
|
1077
|
+
add_logo: bool = True,
|
1078
|
+
) -> tuple[Figure, str]:
|
1079
|
+
"""Create a Plotly Histogram Figure.
|
1080
|
+
|
1081
|
+
Parameters
|
1082
|
+
----------
|
1083
|
+
plot_type: LiteralPlotlyHistogramPlotType, default: bars
|
1084
|
+
Type of plot
|
1085
|
+
histnorm: LiteralPlotlyHistogramHistNorm, default: percent
|
1086
|
+
Sets the normalization mode
|
1087
|
+
barmode: LiteralPlotlyHistogramBarMode, default: overlay
|
1088
|
+
Specifies how bar traces are displayed relative to one another
|
1089
|
+
xbins_size: float, optional
|
1090
|
+
Explicitly sets the width of each bin along the x-axis in data units
|
1091
|
+
opacity: float, default: 0.75
|
1092
|
+
Sets the trace opacity, must be between 0 (fully transparent) and 1
|
1093
|
+
bargap: float, default: 0.0
|
1094
|
+
Sets the gap between bars of adjacent location coordinates
|
1095
|
+
bargroupgap: float, default: 0.0
|
1096
|
+
Sets the gap between bar “groups” at the same location coordinate
|
1097
|
+
curve_type: LiteralPlotlyHistogramCurveType, default: kde
|
1098
|
+
Specifies the type of distribution curve to overlay on the histogram
|
1099
|
+
y_fmt: str, optional
|
1100
|
+
None, '%', '.1%' depending on number of decimals to show on the y-axis
|
1101
|
+
x_fmt: str, optional
|
1102
|
+
None, '%', '.1%' depending on number of decimals to show on the x-axis
|
1103
|
+
filename: str, optional
|
1104
|
+
Name of the Plotly html file
|
1105
|
+
directory: DirectoryPath, optional
|
1106
|
+
Directory where Plotly html file is saved
|
1107
|
+
labels: list[str], optional
|
1108
|
+
A list of labels to manually override using the names of
|
1109
|
+
the input self.tsdf
|
1110
|
+
output_type: LiteralPlotlyOutput, default: "file"
|
1111
|
+
Determines output type
|
1112
|
+
include_plotlyjs: LiteralPlotlyJSlib, default: "cdn"
|
1113
|
+
Determines how the plotly.js library is included in the output
|
1114
|
+
cumulative: bool, default: False
|
1115
|
+
Determines whether to compute a cumulative histogram
|
1116
|
+
show_rug: bool, default: False
|
1117
|
+
Determines whether to draw a rug plot alongside the distribution
|
1118
|
+
auto_open: bool, default: True
|
1119
|
+
Determines whether to open a browser window with the plot
|
1120
|
+
add_logo: bool, default: True
|
1121
|
+
If True a Captor logo is added to the plot
|
1122
|
+
|
1123
|
+
Returns:
|
1124
|
+
-------
|
1125
|
+
tuple[plotly.go.Figure, str]
|
1126
|
+
Plotly Figure and a div section or a html filename with location
|
1127
|
+
|
1128
|
+
"""
|
1129
|
+
if labels:
|
1130
|
+
if len(labels) != self.tsdf.shape[1]:
|
1131
|
+
msg = "Must provide same number of labels as items in frame."
|
1132
|
+
raise NumberOfItemsAndLabelsNotSameError(msg)
|
1133
|
+
else:
|
1134
|
+
labels = list(self.tsdf.columns.get_level_values(0))
|
1135
|
+
|
1136
|
+
if directory:
|
1137
|
+
dirpath = Path(directory).resolve()
|
1138
|
+
elif Path.home().joinpath("Documents").exists():
|
1139
|
+
dirpath = Path.home().joinpath("Documents")
|
1140
|
+
else:
|
1141
|
+
dirpath = Path(stack()[1].filename).parent
|
1142
|
+
|
1143
|
+
if not filename:
|
1144
|
+
filename = "".join(choice(ascii_letters) for _ in range(6)) + ".html"
|
1145
|
+
plotfile = dirpath.joinpath(filename)
|
1146
|
+
|
1147
|
+
fig_dict, logo = load_plotly_dict()
|
1148
|
+
|
1149
|
+
hovertemplate = f"Count: %{{y:{y_fmt}}}" if y_fmt else "Count: %{y}"
|
1150
|
+
|
1151
|
+
if x_fmt:
|
1152
|
+
hovertemplate += f"<br>%{{x:{x_fmt}}}"
|
1153
|
+
else:
|
1154
|
+
hovertemplate += "<br>%{x}"
|
1155
|
+
|
1156
|
+
msg = "plot_type must be 'bars' or 'lines'."
|
1157
|
+
if plot_type == "bars":
|
1158
|
+
figure = Figure(fig_dict)
|
1159
|
+
for item in range(self.tsdf.shape[1]):
|
1160
|
+
figure.add_histogram(
|
1161
|
+
x=self.tsdf.iloc[:, item],
|
1162
|
+
cumulative={"enabled": cumulative},
|
1163
|
+
histnorm=histnorm,
|
1164
|
+
name=labels[item],
|
1165
|
+
xbins={"size": xbins_size},
|
1166
|
+
opacity=opacity,
|
1167
|
+
hovertemplate=hovertemplate,
|
1168
|
+
)
|
1169
|
+
figure.update_layout(
|
1170
|
+
barmode=barmode,
|
1171
|
+
bargap=bargap,
|
1172
|
+
bargroupgap=bargroupgap,
|
1173
|
+
)
|
1174
|
+
elif plot_type == "lines":
|
1175
|
+
hist_data = [
|
1176
|
+
cast("Series[float]", self.tsdf.loc[:, ds]).dropna().tolist()
|
1177
|
+
for ds in self.tsdf
|
1178
|
+
]
|
1179
|
+
figure = create_distplot(
|
1180
|
+
hist_data=hist_data,
|
1181
|
+
curve_type=curve_type,
|
1182
|
+
group_labels=labels,
|
1183
|
+
show_hist=False,
|
1184
|
+
show_rug=show_rug,
|
1185
|
+
histnorm=histnorm,
|
1186
|
+
)
|
1187
|
+
figure.update_layout(dict1=fig_dict["layout"])
|
1188
|
+
else:
|
1189
|
+
raise TypeError(msg)
|
1190
|
+
|
1191
|
+
figure.update_layout(xaxis={"tickformat": x_fmt}, yaxis={"tickformat": y_fmt})
|
1192
|
+
|
1193
|
+
figure.update_xaxes(zeroline=True, zerolinewidth=2, zerolinecolor="lightgrey")
|
1194
|
+
figure.update_yaxes(zeroline=True, zerolinewidth=2, zerolinecolor="lightgrey")
|
1195
|
+
|
1196
|
+
if add_logo:
|
1197
|
+
figure.add_layout_image(logo)
|
1198
|
+
|
1199
|
+
if output_type == "file":
|
1200
|
+
plot(
|
1201
|
+
figure_or_data=figure,
|
1202
|
+
filename=str(plotfile),
|
1203
|
+
auto_open=auto_open,
|
1204
|
+
auto_play=False,
|
1205
|
+
link_text="",
|
1206
|
+
include_plotlyjs=cast("bool", include_plotlyjs),
|
1207
|
+
config=fig_dict["config"],
|
1208
|
+
output_type=output_type,
|
1209
|
+
)
|
1210
|
+
string_output = str(plotfile)
|
1211
|
+
else:
|
1212
|
+
div_id = filename.rsplit(".", 1)[0]
|
1213
|
+
string_output = to_html(
|
1214
|
+
fig=figure,
|
1215
|
+
config=fig_dict["config"],
|
1216
|
+
auto_play=False,
|
1217
|
+
include_plotlyjs=cast("bool", include_plotlyjs),
|
1218
|
+
full_html=False,
|
1219
|
+
div_id=div_id,
|
1220
|
+
)
|
1221
|
+
|
1222
|
+
return figure, string_output
|
1223
|
+
|
1008
1224
|
def arithmetic_ret_func(
|
1009
1225
|
self: Self,
|
1010
1226
|
months_from_last: int | None = None,
|
openseries/datefixer.py
CHANGED
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
5
5
|
import datetime as dt
|
6
6
|
from typing import TYPE_CHECKING, cast
|
7
7
|
|
8
|
+
import pandas_market_calendars as mcal
|
8
9
|
from dateutil.relativedelta import relativedelta
|
9
10
|
from holidays import (
|
10
11
|
country_holidays,
|
@@ -24,6 +25,7 @@ from pandas.tseries.offsets import CustomBusinessDay
|
|
24
25
|
from .owntypes import (
|
25
26
|
BothStartAndEndError,
|
26
27
|
CountriesNotStringNorListStrError,
|
28
|
+
MarketsNotStringNorListStrError,
|
27
29
|
TradingDaysNotAboveZeroError,
|
28
30
|
)
|
29
31
|
|
@@ -31,7 +33,6 @@ if TYPE_CHECKING:
|
|
31
33
|
from .owntypes import ( # pragma: no cover
|
32
34
|
CountriesType,
|
33
35
|
DateType,
|
34
|
-
HolidayType,
|
35
36
|
LiteralBizDayFreq,
|
36
37
|
)
|
37
38
|
|
@@ -45,11 +46,59 @@ __all__ = [
|
|
45
46
|
]
|
46
47
|
|
47
48
|
|
49
|
+
def market_holidays(
|
50
|
+
startyear: int,
|
51
|
+
endyear: int,
|
52
|
+
markets: str | list[str],
|
53
|
+
) -> list[str]:
|
54
|
+
"""Return a dict of holiday dates mapping to list of markets closed.
|
55
|
+
|
56
|
+
Parameters
|
57
|
+
----------
|
58
|
+
startyear: int
|
59
|
+
First year (inclusive) to consider.
|
60
|
+
endyear: int
|
61
|
+
Last year (inclusive) to consider.
|
62
|
+
markets: str | list[str]
|
63
|
+
String or list of market codes supported by pandas_market_calendars.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
-------
|
67
|
+
list[str]
|
68
|
+
list of holiday dates.
|
69
|
+
"""
|
70
|
+
market_list = [markets] if isinstance(markets, str) else list(markets)
|
71
|
+
|
72
|
+
supported = mcal.get_calendar_names()
|
73
|
+
|
74
|
+
if not all(m in supported for m in market_list):
|
75
|
+
msg = (
|
76
|
+
"Argument markets must be a string market code or a list of market "
|
77
|
+
"codes supported by pandas_market_calendars."
|
78
|
+
)
|
79
|
+
raise MarketsNotStringNorListStrError(msg)
|
80
|
+
|
81
|
+
holidays: list[str] = []
|
82
|
+
for m in market_list:
|
83
|
+
cal = mcal.get_calendar(m)
|
84
|
+
# noinspection PyUnresolvedReferences
|
85
|
+
cal_hols = cal.holidays().calendar.holidays
|
86
|
+
my_hols: list[str] = [
|
87
|
+
str(date)
|
88
|
+
for date in cal_hols
|
89
|
+
if (startyear <= int(str(date)[:4]) <= endyear)
|
90
|
+
]
|
91
|
+
holidays.extend(my_hols)
|
92
|
+
|
93
|
+
return list(set(holidays))
|
94
|
+
|
95
|
+
|
48
96
|
def holiday_calendar(
|
49
97
|
startyear: int,
|
50
98
|
endyear: int,
|
51
99
|
countries: CountriesType = "SE",
|
52
|
-
|
100
|
+
markets: list[str] | str | None = None,
|
101
|
+
custom_holidays: list[str] | str | None = None,
|
53
102
|
) -> busdaycalendar:
|
54
103
|
"""Generate a business calendar.
|
55
104
|
|
@@ -61,9 +110,10 @@ def holiday_calendar(
|
|
61
110
|
Last year in date range generated
|
62
111
|
countries: CountriesType, default: "SE"
|
63
112
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
64
|
-
|
65
|
-
|
66
|
-
|
113
|
+
markets: list[str] | str, optional
|
114
|
+
(List of) markets code(s) according to pandas-market-calendars
|
115
|
+
custom_holidays: list[str] | str, optional
|
116
|
+
Argument where missing holidays can be added
|
67
117
|
|
68
118
|
Returns:
|
69
119
|
-------
|
@@ -79,20 +129,16 @@ def holiday_calendar(
|
|
79
129
|
|
80
130
|
if isinstance(countries, str) and countries in list_supported_countries():
|
81
131
|
staging = country_holidays(country=countries, years=years)
|
82
|
-
|
83
|
-
|
84
|
-
hols = array(sorted(staging.keys()), dtype="datetime64[D]")
|
85
|
-
elif isinstance(countries, list) and all(
|
132
|
+
hols = list(staging.keys())
|
133
|
+
elif isinstance(countries, (list, set)) and all(
|
86
134
|
country in list_supported_countries() for country in countries
|
87
135
|
):
|
88
136
|
country: str
|
89
137
|
countryholidays: list[dt.date | str] = []
|
90
|
-
for
|
138
|
+
for country in countries:
|
91
139
|
staging = country_holidays(country=country, years=years)
|
92
|
-
if i == 0 and custom_holidays is not None:
|
93
|
-
staging.update(custom_holidays)
|
94
140
|
countryholidays += list(staging)
|
95
|
-
hols =
|
141
|
+
hols = list(countryholidays)
|
96
142
|
else:
|
97
143
|
msg = (
|
98
144
|
"Argument countries must be a string country code or "
|
@@ -100,7 +146,22 @@ def holiday_calendar(
|
|
100
146
|
)
|
101
147
|
raise CountriesNotStringNorListStrError(msg)
|
102
148
|
|
103
|
-
|
149
|
+
if markets:
|
150
|
+
market_hols = market_holidays(
|
151
|
+
startyear=startyear, endyear=endyear, markets=markets
|
152
|
+
)
|
153
|
+
dt_mkt_hols = [date_fix(fixerdate=ddate) for ddate in market_hols]
|
154
|
+
hols.extend(dt_mkt_hols)
|
155
|
+
|
156
|
+
if custom_holidays:
|
157
|
+
custom_list = (
|
158
|
+
[custom_holidays]
|
159
|
+
if isinstance(custom_holidays, str)
|
160
|
+
else list(custom_holidays) # type: ignore[arg-type]
|
161
|
+
)
|
162
|
+
hols.extend([date_fix(fixerdate=ddate) for ddate in custom_list])
|
163
|
+
|
164
|
+
return busdaycalendar(holidays=array(sorted(set(hols)), dtype="datetime64[D]"))
|
104
165
|
|
105
166
|
|
106
167
|
def date_fix(
|
@@ -137,7 +198,8 @@ def date_offset_foll(
|
|
137
198
|
raw_date: DateType,
|
138
199
|
months_offset: int = 12,
|
139
200
|
countries: CountriesType = "SE",
|
140
|
-
|
201
|
+
markets: list[str] | str | None = None,
|
202
|
+
custom_holidays: list[str] | str | None = None,
|
141
203
|
*,
|
142
204
|
adjust: bool = False,
|
143
205
|
following: bool = True,
|
@@ -152,9 +214,10 @@ def date_offset_foll(
|
|
152
214
|
Number of months as integer
|
153
215
|
countries: CountriesType, default: "SE"
|
154
216
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
155
|
-
|
156
|
-
|
157
|
-
|
217
|
+
markets: list[str] | str, optional
|
218
|
+
(List of) markets code(s) according to pandas-market-calendars
|
219
|
+
custom_holidays: list[str] | str, optional
|
220
|
+
Argument where missing holidays can be added
|
158
221
|
adjust: bool, default: False
|
159
222
|
Determines if offset should adjust for business days
|
160
223
|
following: bool, default: True
|
@@ -180,6 +243,7 @@ def date_offset_foll(
|
|
180
243
|
startyear=startyear,
|
181
244
|
endyear=endyear,
|
182
245
|
countries=countries,
|
246
|
+
markets=markets,
|
183
247
|
custom_holidays=custom_holidays,
|
184
248
|
)
|
185
249
|
while not is_busday(dates=new_date, busdaycal=calendar):
|
@@ -191,7 +255,8 @@ def date_offset_foll(
|
|
191
255
|
def get_previous_business_day_before_today(
|
192
256
|
today: dt.date | None = None,
|
193
257
|
countries: CountriesType = "SE",
|
194
|
-
|
258
|
+
markets: list[str] | str | None = None,
|
259
|
+
custom_holidays: list[str] | str | None = None,
|
195
260
|
) -> dt.date:
|
196
261
|
"""Bump date backwards to find the previous business day.
|
197
262
|
|
@@ -201,9 +266,10 @@ def get_previous_business_day_before_today(
|
|
201
266
|
Manual input of the day from where the previous business day is found
|
202
267
|
countries: CountriesType, default: "SE"
|
203
268
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
204
|
-
|
205
|
-
|
206
|
-
|
269
|
+
markets: list[str] | str, optional
|
270
|
+
(List of) markets code(s) according to pandas-market-calendars
|
271
|
+
custom_holidays: list[str] | str, optional
|
272
|
+
Argument where missing holidays can be added
|
207
273
|
|
208
274
|
Returns:
|
209
275
|
-------
|
@@ -215,10 +281,11 @@ def get_previous_business_day_before_today(
|
|
215
281
|
today = dt.datetime.now().astimezone().date()
|
216
282
|
|
217
283
|
return date_offset_foll(
|
218
|
-
today - dt.timedelta(days=1),
|
284
|
+
raw_date=today - dt.timedelta(days=1),
|
285
|
+
months_offset=0,
|
219
286
|
countries=countries,
|
287
|
+
markets=markets,
|
220
288
|
custom_holidays=custom_holidays,
|
221
|
-
months_offset=0,
|
222
289
|
adjust=True,
|
223
290
|
following=False,
|
224
291
|
)
|
@@ -228,7 +295,8 @@ def offset_business_days(
|
|
228
295
|
ddate: dt.date,
|
229
296
|
days: int,
|
230
297
|
countries: CountriesType = "SE",
|
231
|
-
|
298
|
+
markets: list[str] | str | None = None,
|
299
|
+
custom_holidays: list[str] | str | None = None,
|
232
300
|
) -> dt.date:
|
233
301
|
"""Bump date by business days.
|
234
302
|
|
@@ -244,9 +312,10 @@ def offset_business_days(
|
|
244
312
|
If days is set as anything other than an integer its value is set to zero
|
245
313
|
countries: CountriesType, default: "SE"
|
246
314
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
247
|
-
|
248
|
-
|
249
|
-
|
315
|
+
markets: list[str] | str, optional
|
316
|
+
(List of) markets code(s) according to pandas-market-calendars
|
317
|
+
custom_holidays: list[str] | str, optional
|
318
|
+
Argument where missing holidays can be added
|
250
319
|
|
251
320
|
Returns:
|
252
321
|
-------
|
@@ -266,6 +335,7 @@ def offset_business_days(
|
|
266
335
|
startyear=ndate.year,
|
267
336
|
endyear=ddate.year,
|
268
337
|
countries=countries,
|
338
|
+
markets=markets,
|
269
339
|
custom_holidays=custom_holidays,
|
270
340
|
)
|
271
341
|
local_bdays: list[dt.date] = [
|
@@ -283,6 +353,7 @@ def offset_business_days(
|
|
283
353
|
startyear=ddate.year,
|
284
354
|
endyear=ndate.year,
|
285
355
|
countries=countries,
|
356
|
+
markets=markets,
|
286
357
|
custom_holidays=custom_holidays,
|
287
358
|
)
|
288
359
|
local_bdays = [
|
@@ -310,6 +381,8 @@ def generate_calendar_date_range(
|
|
310
381
|
start: dt.date | None = None,
|
311
382
|
end: dt.date | None = None,
|
312
383
|
countries: CountriesType = "SE",
|
384
|
+
markets: list[str] | str | None = None,
|
385
|
+
custom_holidays: list[str] | str | None = None,
|
313
386
|
) -> list[dt.date]:
|
314
387
|
"""Generate a list of business day calendar dates.
|
315
388
|
|
@@ -323,6 +396,10 @@ def generate_calendar_date_range(
|
|
323
396
|
Date when the range ends
|
324
397
|
countries: CountriesType, default: "SE"
|
325
398
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
399
|
+
markets: list[str] | str, optional
|
400
|
+
(List of) markets code(s) according to pandas-market-calendars
|
401
|
+
custom_holidays: list[str] | str, optional
|
402
|
+
Argument where missing holidays can be added
|
326
403
|
|
327
404
|
Returns:
|
328
405
|
-------
|
@@ -344,6 +421,8 @@ def generate_calendar_date_range(
|
|
344
421
|
startyear=start.year,
|
345
422
|
endyear=date_fix(tmp_range.tolist()[-1]).year,
|
346
423
|
countries=countries,
|
424
|
+
markets=markets,
|
425
|
+
custom_holidays=custom_holidays,
|
347
426
|
)
|
348
427
|
return [
|
349
428
|
d.date()
|
@@ -360,6 +439,8 @@ def generate_calendar_date_range(
|
|
360
439
|
startyear=date_fix(tmp_range.tolist()[0]).year,
|
361
440
|
endyear=end.year,
|
362
441
|
countries=countries,
|
442
|
+
markets=markets,
|
443
|
+
custom_holidays=custom_holidays,
|
363
444
|
)
|
364
445
|
return [
|
365
446
|
d.date()
|
@@ -381,6 +462,8 @@ def _do_resample_to_business_period_ends(
|
|
381
462
|
data: DataFrame,
|
382
463
|
freq: LiteralBizDayFreq,
|
383
464
|
countries: CountriesType,
|
465
|
+
markets: list[str] | str | None = None,
|
466
|
+
custom_holidays: list[str] | str | None = None,
|
384
467
|
) -> DatetimeIndex:
|
385
468
|
"""Resample timeseries frequency to business calendar month end dates.
|
386
469
|
|
@@ -394,7 +477,10 @@ def _do_resample_to_business_period_ends(
|
|
394
477
|
The date offset string that sets the resampled frequency
|
395
478
|
countries: CountriesType
|
396
479
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
397
|
-
|
480
|
+
markets: list[str] | str, optional
|
481
|
+
(List of) markets code(s) according to pandas-market-calendars
|
482
|
+
custom_holidays: list[str] | str, optional
|
483
|
+
Argument where missing holidays can be added
|
398
484
|
|
399
485
|
Returns:
|
400
486
|
-------
|
@@ -413,12 +499,14 @@ def _do_resample_to_business_period_ends(
|
|
413
499
|
dates = DatetimeIndex(
|
414
500
|
[copydata.index[0]]
|
415
501
|
+ [
|
416
|
-
date_offset_foll(
|
417
|
-
dt.date(d.year, d.month, 1)
|
502
|
+
date_offset_foll( # type: ignore[misc]
|
503
|
+
raw_date=dt.date(d.year, d.month, 1)
|
418
504
|
+ relativedelta(months=1)
|
419
505
|
- dt.timedelta(days=1),
|
420
|
-
countries=countries,
|
421
506
|
months_offset=0,
|
507
|
+
countries=countries,
|
508
|
+
markets=markets,
|
509
|
+
custom_holidays=custom_holidays,
|
422
510
|
adjust=True,
|
423
511
|
following=False,
|
424
512
|
)
|
openseries/frame.py
CHANGED
@@ -41,7 +41,6 @@ from pydantic import field_validator
|
|
41
41
|
from ._common_model import _CommonModel
|
42
42
|
from .datefixer import _do_resample_to_business_period_ends
|
43
43
|
from .owntypes import (
|
44
|
-
CountriesType,
|
45
44
|
DaysInYearType,
|
46
45
|
LabelsNotUniqueError,
|
47
46
|
LiteralBizDayFreq,
|
@@ -429,7 +428,6 @@ class OpenFrame(_CommonModel):
|
|
429
428
|
def resample_to_business_period_ends(
|
430
429
|
self: Self,
|
431
430
|
freq: LiteralBizDayFreq = "BME",
|
432
|
-
countries: CountriesType = "SE",
|
433
431
|
method: LiteralPandasReindexMethod = "nearest",
|
434
432
|
) -> Self:
|
435
433
|
"""Resamples timeseries frequency to the business calendar month end dates.
|
@@ -440,9 +438,6 @@ class OpenFrame(_CommonModel):
|
|
440
438
|
----------
|
441
439
|
freq: LiteralBizDayFreq, default "BME"
|
442
440
|
The date offset string that sets the resampled frequency
|
443
|
-
countries: CountriesType, default: "SE"
|
444
|
-
(List of) country code(s) according to ISO 3166-1 alpha-2
|
445
|
-
to create a business day calendar used for date adjustments
|
446
441
|
method: LiteralPandasReindexMethod, default: nearest
|
447
442
|
Controls the method used to align values across columns
|
448
443
|
|
@@ -456,7 +451,8 @@ class OpenFrame(_CommonModel):
|
|
456
451
|
dates = _do_resample_to_business_period_ends(
|
457
452
|
data=xerie.tsdf,
|
458
453
|
freq=freq,
|
459
|
-
countries=countries,
|
454
|
+
countries=xerie.countries,
|
455
|
+
markets=xerie.markets,
|
460
456
|
)
|
461
457
|
xerie.tsdf = xerie.tsdf.reindex(
|
462
458
|
[deyt.date() for deyt in dates],
|
openseries/owntypes.py
CHANGED
@@ -86,16 +86,6 @@ DaysInYearType = Annotated[int, Field(strict=True, ge=1, le=366)]
|
|
86
86
|
|
87
87
|
DateType = str | dt.date | dt.datetime | datetime64 | Timestamp
|
88
88
|
|
89
|
-
HolidayType = (
|
90
|
-
dict[dt.date | dt.datetime | str | float | int, str]
|
91
|
-
| list[dt.date | dt.datetime | str | float | int]
|
92
|
-
| dt.date
|
93
|
-
| dt.datetime
|
94
|
-
| str
|
95
|
-
| float
|
96
|
-
| int
|
97
|
-
)
|
98
|
-
|
99
89
|
PlotlyLayoutType = dict[
|
100
90
|
str,
|
101
91
|
str
|
@@ -135,6 +125,15 @@ LiteralCaptureRatio = Literal["up", "down", "both"]
|
|
135
125
|
LiteralBarPlotMode = Literal["stack", "group", "overlay", "relative"]
|
136
126
|
LiteralPlotlyOutput = Literal["file", "div"]
|
137
127
|
LiteralPlotlyJSlib = Literal[True, False, "cdn"]
|
128
|
+
LiteralPlotlyHistogramPlotType = Literal["bars", "lines"]
|
129
|
+
LiteralPlotlyHistogramBarMode = Literal["stack", "group", "overlay", "relative"]
|
130
|
+
LiteralPlotlyHistogramCurveType = Literal["normal", "kde"]
|
131
|
+
LiteralPlotlyHistogramHistNorm = Literal[
|
132
|
+
"percent",
|
133
|
+
"probability",
|
134
|
+
"density",
|
135
|
+
"probability density",
|
136
|
+
]
|
138
137
|
LiteralOlsFitMethod = Literal["pinv", "qr"]
|
139
138
|
LiteralPortfolioWeightings = Literal["eq_weights", "inv_vol"]
|
140
139
|
LiteralOlsFitCovType = Literal[
|
@@ -347,6 +346,10 @@ class CountriesNotStringNorListStrError(Exception):
|
|
347
346
|
"""Raised when countries argument is not provided in correct format."""
|
348
347
|
|
349
348
|
|
349
|
+
class MarketsNotStringNorListStrError(Exception):
|
350
|
+
"""Raised when markets argument is not provided in correct format."""
|
351
|
+
|
352
|
+
|
350
353
|
class TradingDaysNotAboveZeroError(Exception):
|
351
354
|
"""Raised when trading days argument is not above zero."""
|
352
355
|
|
openseries/plotly_layouts.json
CHANGED
openseries/series.py
CHANGED
@@ -45,6 +45,7 @@ from .owntypes import (
|
|
45
45
|
LiteralBizDayFreq,
|
46
46
|
LiteralPandasReindexMethod,
|
47
47
|
LiteralSeriesProps,
|
48
|
+
MarketsNotStringNorListStrError,
|
48
49
|
OpenTimeSeriesPropertiesList,
|
49
50
|
Self,
|
50
51
|
ValueListType,
|
@@ -91,6 +92,8 @@ class OpenTimeSeries(_CommonModel):
|
|
91
92
|
ISO 4217 currency code of the user's home currency
|
92
93
|
countries: CountriesType, default: "SE"
|
93
94
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
95
|
+
markets: list[str] | str, optional
|
96
|
+
(List of) markets code(s) according to pandas-market-calendars
|
94
97
|
isin : str, optional
|
95
98
|
ISO 6166 identifier code of the associated instrument
|
96
99
|
label : str, optional
|
@@ -109,6 +112,7 @@ class OpenTimeSeries(_CommonModel):
|
|
109
112
|
currency: CurrencyStringType
|
110
113
|
domestic: CurrencyStringType = "SEK"
|
111
114
|
countries: CountriesType = "SE"
|
115
|
+
markets: list[str] | str | None = None # type: ignore[assignment]
|
112
116
|
isin: str | None = None
|
113
117
|
label: str | None = None
|
114
118
|
|
@@ -126,6 +130,25 @@ class OpenTimeSeries(_CommonModel):
|
|
126
130
|
_ = Countries(countryinput=value)
|
127
131
|
return value
|
128
132
|
|
133
|
+
@field_validator("markets", mode="before") # type: ignore[misc]
|
134
|
+
@classmethod
|
135
|
+
def _validate_markets(
|
136
|
+
cls, value: list[str] | str | None
|
137
|
+
) -> list[str] | str | None:
|
138
|
+
"""Pydantic validator to ensure markets field is validated."""
|
139
|
+
msg = (
|
140
|
+
"'markets' must be a string or list of strings, "
|
141
|
+
f"got {type(value).__name__!r}"
|
142
|
+
)
|
143
|
+
if value is None or isinstance(value, str):
|
144
|
+
return value
|
145
|
+
if isinstance(value, list):
|
146
|
+
if all(isinstance(item, str) for item in value) and len(value) != 0:
|
147
|
+
return value
|
148
|
+
item_msg = "All items in 'markets' must be strings."
|
149
|
+
raise MarketsNotStringNorListStrError(item_msg)
|
150
|
+
raise MarketsNotStringNorListStrError(msg)
|
151
|
+
|
129
152
|
@model_validator(mode="after") # type: ignore[misc,unused-ignore]
|
130
153
|
def _dates_and_values_validate(self: Self) -> Self:
|
131
154
|
"""Pydantic validator to ensure dates and values are validated."""
|
@@ -587,6 +610,7 @@ class OpenTimeSeries(_CommonModel):
|
|
587
610
|
data=self.tsdf,
|
588
611
|
freq=freq,
|
589
612
|
countries=self.countries,
|
613
|
+
markets=self.markets,
|
590
614
|
)
|
591
615
|
self.tsdf = self.tsdf.reindex([deyt.date() for deyt in dates], method=method)
|
592
616
|
return self
|
openseries/simulation.py
CHANGED
@@ -417,6 +417,7 @@ class ReturnSimulation(BaseModel): # type: ignore[misc]
|
|
417
417
|
start: dt.date | None = None,
|
418
418
|
end: dt.date | None = None,
|
419
419
|
countries: CountriesType = "SE",
|
420
|
+
markets: list[str] | str | None = None,
|
420
421
|
) -> DataFrame:
|
421
422
|
"""Create a pandas.DataFrame from simulation(s).
|
422
423
|
|
@@ -430,6 +431,8 @@ class ReturnSimulation(BaseModel): # type: ignore[misc]
|
|
430
431
|
Date when the simulation ends
|
431
432
|
countries: CountriesType, default: "SE"
|
432
433
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
434
|
+
markets: list[str] | str, optional
|
435
|
+
(List of) markets code(s) according to pandas-market-calendars
|
433
436
|
|
434
437
|
Returns:
|
435
438
|
-------
|
@@ -442,6 +445,7 @@ class ReturnSimulation(BaseModel): # type: ignore[misc]
|
|
442
445
|
start=start,
|
443
446
|
end=end,
|
444
447
|
countries=countries,
|
448
|
+
markets=markets,
|
445
449
|
)
|
446
450
|
|
447
451
|
if self.number_of_sims == 1:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: openseries
|
3
|
-
Version: 1.8.
|
3
|
+
Version: 1.8.4
|
4
4
|
Summary: Tools for analyzing financial timeseries.
|
5
5
|
License: # BSD 3-Clause License
|
6
6
|
|
@@ -50,6 +50,7 @@ Requires-Dist: holidays (>=0.30,<1.0)
|
|
50
50
|
Requires-Dist: numpy (>=1.23.2,<3.0.0)
|
51
51
|
Requires-Dist: openpyxl (>=3.1.2,<5.0.0)
|
52
52
|
Requires-Dist: pandas (>=2.1.2,<3.0.0)
|
53
|
+
Requires-Dist: pandas-market-calendars (>=5.1.0,<7.0.0)
|
53
54
|
Requires-Dist: plotly (>=5.18.0,<7.0.0)
|
54
55
|
Requires-Dist: pyarrow (>=14.0.2,<21.0.0)
|
55
56
|
Requires-Dist: pydantic (>=2.5.2,<3.0.0)
|
@@ -83,7 +84,6 @@ Description-Content-Type: text/markdown
|
|
83
84
|
This is a project with tools to analyze financial timeseries of a single
|
84
85
|
asset or a group of assets. It is solely made for daily or less frequent data.
|
85
86
|
|
86
|
-
|
87
87
|
## Basic Usage
|
88
88
|
|
89
89
|
To install:
|
@@ -119,6 +119,7 @@ _,_=series.plot_series()
|
|
119
119
|
```
|
120
120
|
|
121
121
|
### Sample output using the OpenFrame.all_properties() method:
|
122
|
+
|
122
123
|
```
|
123
124
|
Scilla Global Equity C (simulation+fund) Global Low Volatility index, SEK
|
124
125
|
ValueType.PRICE ValueType.PRICE
|
@@ -156,7 +157,6 @@ The OpenTimeSeries and OpenFrame classes are both subclasses of
|
|
156
157
|
the [Pydantic BaseModel](https://docs.pydantic.dev/usage/models/). Please refer to its documentation for information
|
157
158
|
on any attributes or methods inherited from this model.
|
158
159
|
|
159
|
-
|
160
160
|
### Windows Powershell
|
161
161
|
|
162
162
|
```powershell
|
@@ -202,7 +202,6 @@ make lint
|
|
202
202
|
|
203
203
|
```
|
204
204
|
|
205
|
-
|
206
205
|
## Table of Contents
|
207
206
|
|
208
207
|
- [Basic Usage](#basic-usage)
|
@@ -239,34 +238,35 @@ make lint
|
|
239
238
|
|
240
239
|
### Non-numerical or "helper" properties that apply only to the [OpenTimeSeries](https://github.com/CaptorAB/openseries/blob/master/openseries/series.py) class.
|
241
240
|
|
242
|
-
| Property | type
|
243
|
-
|
244
|
-
| `timeseries_id` | `str`
|
245
|
-
| `instrument_id` | `str`
|
246
|
-
| `dates` | `list[str]`
|
247
|
-
| `values` | `list[float]`
|
248
|
-
| `currency` | `str`
|
249
|
-
| `domestic` | `str`
|
250
|
-
| `local_ccy` | `bool`
|
251
|
-
| `name` | `str`
|
252
|
-
| `isin` | `str`
|
253
|
-
| `label` | `str`
|
254
|
-
| `countries` | `list` or `str` | `OpenTimeSeries` | (List of) country code(s) according to ISO 3166-1 alpha-2 used to generate business days.
|
255
|
-
| `
|
241
|
+
| Property | type | Applies to | Description |
|
242
|
+
|:----------------|:---------------------|:-----------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
243
|
+
| `timeseries_id` | `str` | `OpenTimeSeries` | Placeholder for database identifier for the timeseries. Can be left as empty string. |
|
244
|
+
| `instrument_id` | `str` | `OpenTimeSeries` | Placeholder for database identifier for the instrument associated with the timeseries. Can be left as empty string. |
|
245
|
+
| `dates` | `list[str]` | `OpenTimeSeries` | Dates of the timeseries. Not edited by any method to allow reversion to original. |
|
246
|
+
| `values` | `list[float]` | `OpenTimeSeries` | Values of the timeseries. Not edited by any method to allow reversion to original. |
|
247
|
+
| `currency` | `str` | `OpenTimeSeries` | Currency of the timeseries. Only used if conversion/hedging methods are added. |
|
248
|
+
| `domestic` | `str` | `OpenTimeSeries` | Domestic currency of the user / investor. Only used if conversion/hedging methods are added. |
|
249
|
+
| `local_ccy` | `bool` | `OpenTimeSeries` | Indicates if series should be in its local currency or the domestic currency of the user. Only used if conversion/hedging methods are added. |
|
250
|
+
| `name` | `str` | `OpenTimeSeries` | An identifier field. |
|
251
|
+
| `isin` | `str` | `OpenTimeSeries` | ISIN code of the associated instrument. If any. |
|
252
|
+
| `label` | `str` | `OpenTimeSeries` | Field used in outputs. Derived from name as default. |
|
253
|
+
| `countries` | `list[str]` or `str` | `OpenTimeSeries` | (List of) country code(s) according to ISO 3166-1 alpha-2 used in the [holidays](https://github.com/vacanza/holidays/) package to generate business days. |
|
254
|
+
| `markets` | `list[str]` or `str` | `OpenTimeSeries` | (List of) markets code(s) according to market code(s) input for the [pandas-market-calendars](https://pandas-market-calendars.readthedocs.io/en/latest/) package. |
|
255
|
+
| `valuetype` | `ValueType` | `OpenTimeSeries` | Field identifies the type of values in the series. ValueType is an Enum. |
|
256
256
|
|
257
257
|
### Non-numerical or "helper" properties that apply only to the [OpenFrame](https://github.com/CaptorAB/openseries/blob/master/openseries/frame.py) class.
|
258
258
|
|
259
|
-
| Property | type
|
260
|
-
|
261
|
-
| `constituents` | `list[OpenTimeSeries]`
|
262
|
-
| `columns_lvl_zero` | `list`
|
263
|
-
| `columns_lvl_one` | `list`
|
264
|
-
| `item_count` | `int`
|
265
|
-
| `weights` | `list[float]`
|
266
|
-
| `first_indices` | `pandas.Series`
|
267
|
-
| `last_indices` | `pandas.Series`
|
268
|
-
| `lengths_of_items` | `pandas.Series`
|
269
|
-
| `span_of_days_all` | `pandas.Series`
|
259
|
+
| Property | type | Applies to | Description |
|
260
|
+
|:-------------------|:---------------------------------|:------------|:-------------------------------------------------------------------------|
|
261
|
+
| `constituents` | `list[OpenTimeSeries]` | `OpenFrame` | A list of the OpenTimeSeries that make up an OpenFrame. |
|
262
|
+
| `columns_lvl_zero` | `list[str]` | `OpenFrame` | A list of the level zero column names in the OpenFrame pandas.DataFrame. |
|
263
|
+
| `columns_lvl_one` | `list[ValueType]` or `list[str]` | `OpenFrame` | A list of the level one column names in the OpenFrame pandas.DataFrame. |
|
264
|
+
| `item_count` | `int` | `OpenFrame` | Number of columns in the OpenFrame pandas.DataFrame. |
|
265
|
+
| `weights` | `list[float]` | `OpenFrame` | Weights used in the method `make_portfolio`. |
|
266
|
+
| `first_indices` | `pandas.Series[dt.date]` | `OpenFrame` | First dates of all the series in the OpenFrame. |
|
267
|
+
| `last_indices` | `pandas.Series[dt.date]` | `OpenFrame` | Last dates of all the series in the OpenFrame. |
|
268
|
+
| `lengths_of_items` | `pandas.Series[int]` | `OpenFrame` | Number of items in each of the series in the OpenFrame. |
|
269
|
+
| `span_of_days_all` | `pandas.Series[int]` | `OpenFrame` | Number of days from the first to the last in each of the series. |
|
270
270
|
|
271
271
|
### Non-numerical or "helper" properties that apply to both the [OpenTimeSeries](https://github.com/CaptorAB/openseries/blob/master/openseries/series.py) and the [OpenFrame](https://github.com/CaptorAB/openseries/blob/master/openseries/frame.py) class.
|
272
272
|
|
@@ -290,7 +290,7 @@ make lint
|
|
290
290
|
| `running_adjustment` | `OpenTimeSeries` | Adjusts the series performance with a `float` factor. |
|
291
291
|
| `ewma_vol_func` | `OpenTimeSeries` | Returns a `pandas.Series` with volatility based on [Exponentially Weighted Moving Average](https://www.investopedia.com/articles/07/ewma.asp). |
|
292
292
|
| `from_1d_rate_to_cumret` | `OpenTimeSeries` | Converts a series of 1-day rates into a cumulative valueseries. |
|
293
|
-
|
293
|
+
|
|
294
294
|
|
295
295
|
### Methods that apply only to the [OpenFrame](https://github.com/CaptorAB/openseries/blob/master/openseries/frame.py) class.
|
296
296
|
|
@@ -328,10 +328,11 @@ make lint
|
|
328
328
|
| `to_xlsx` | `OpenTimeSeries`, `OpenFrame` | Method to save the data in the .tsdf DataFrame to an Excel file. |
|
329
329
|
| `value_to_ret` | `OpenTimeSeries`, `OpenFrame` | Converts a value series into a percentage return series. |
|
330
330
|
| `value_to_diff` | `OpenTimeSeries`, `OpenFrame` | Converts a value series into a series of differences. |
|
331
|
-
| `value_to_log` | `OpenTimeSeries`, `OpenFrame` | Converts a value series into a
|
331
|
+
| `value_to_log` | `OpenTimeSeries`, `OpenFrame` | Converts a value series into a cumulative log return series, useful for plotting growth relative to the starting point. |
|
332
332
|
| `value_ret_calendar_period` | `OpenTimeSeries`, `OpenFrame` | Returns the series simple return for a specific calendar period. |
|
333
|
-
| `plot_series` | `OpenTimeSeries`, `OpenFrame` | Opens a HTML [Plotly Scatter](https://plotly.com/python/line-and-scatter/) plot of the
|
334
|
-
| `plot_bars` | `OpenTimeSeries`, `OpenFrame` | Opens a HTML [Plotly Bar](https://plotly.com/python/bar-charts/) plot of the
|
333
|
+
| `plot_series` | `OpenTimeSeries`, `OpenFrame` | Opens a HTML [Plotly Scatter](https://plotly.com/python/line-and-scatter/) plot of the serie(s) in a browser window. |
|
334
|
+
| `plot_bars` | `OpenTimeSeries`, `OpenFrame` | Opens a HTML [Plotly Bar](https://plotly.com/python/bar-charts/) plot of the serie(s) in a browser window. |
|
335
|
+
| `plot_histogram` | `OpenTimeSeries`, `OpenFrame` | Opens a HTML [Plotly Histogram](https://plotly.com/python/histograms/) plot of the serie(s) in a browser window. |
|
335
336
|
| `to_drawdown_series` | `OpenTimeSeries`, `OpenFrame` | Converts the series into drawdown series. |
|
336
337
|
| `rolling_return` | `OpenTimeSeries`, `OpenFrame` | Returns a pandas.DataFrame with rolling returns. |
|
337
338
|
| `rolling_vol` | `OpenTimeSeries`, `OpenFrame` | Returns a pandas.DataFrame with rolling volatilities. |
|
@@ -0,0 +1,16 @@
|
|
1
|
+
openseries/__init__.py,sha256=dKw_wEfgrCwwV1IRljesrtxjE9AVFwTyhE8k4CFIck8,1053
|
2
|
+
openseries/_common_model.py,sha256=oW-jM8CCAS4E7R-E7hPHDUkMJ5i2sc1DRGxvRB498SA,82789
|
3
|
+
openseries/_risk.py,sha256=lZzoP5yjq9vHtKhYe7kU3-iG8rADcu00bkT9kIgsi_E,2086
|
4
|
+
openseries/datefixer.py,sha256=7ugMIEKf5lhifd1FlC_aHlHt_Fwvof3aRSLaHM2fvR8,15525
|
5
|
+
openseries/frame.py,sha256=H3gAIKTDy5aStKTjBtudsJX15knH0t-8NfdD26JVu3Y,55654
|
6
|
+
openseries/load_plotly.py,sha256=VGDdS8ojPQK7AQr-dGi9IfShi5O0EfjM8kUQrJhG_Zw,2000
|
7
|
+
openseries/owntypes.py,sha256=j5KUbHqJTKyZPaQOurojtf7RoPgk5TC8A1KEtMO6EN0,9341
|
8
|
+
openseries/plotly_captor_logo.json,sha256=F5nhMzEyxKywtjvQqMTKgKRCJQYMDIiBgDSxdte8Clo,178
|
9
|
+
openseries/plotly_layouts.json,sha256=9tKAeittrjwJWhBMV8SnCDAWdhgbVnUqXcN6P_J_bos,1433
|
10
|
+
openseries/portfoliotools.py,sha256=6bgz64-B6qJVrHAE-pLp8JJCmJkO_JAExHL5G3AwPWE,19295
|
11
|
+
openseries/series.py,sha256=xYU4c1MA02AaFko5q72JoVDEKs60zDmxkfG4P_uCpOY,28265
|
12
|
+
openseries/simulation.py,sha256=LhKfA32uskMNr90V9r1_uYKC7FZgWRcdLzw2--D1qUM,14131
|
13
|
+
openseries-1.8.4.dist-info/LICENSE.md,sha256=wNupG-KLsG0aTncb_SMNDh1ExtrKXlpxSJ6RC-g-SWs,1516
|
14
|
+
openseries-1.8.4.dist-info/METADATA,sha256=D6rlANyAmZ72EonbQTMyjE10ctd1MuJqQ3nVXbqNO3A,46550
|
15
|
+
openseries-1.8.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
16
|
+
openseries-1.8.4.dist-info/RECORD,,
|
@@ -1,16 +0,0 @@
|
|
1
|
-
openseries/__init__.py,sha256=dKw_wEfgrCwwV1IRljesrtxjE9AVFwTyhE8k4CFIck8,1053
|
2
|
-
openseries/_common_model.py,sha256=wQ0tevEqrjckevW8UbTsx6I7t6unAYWAr4QkaIx7pHo,74522
|
3
|
-
openseries/_risk.py,sha256=lZzoP5yjq9vHtKhYe7kU3-iG8rADcu00bkT9kIgsi_E,2086
|
4
|
-
openseries/datefixer.py,sha256=5S4Ib9CRHfsVPKsDKcIW7x8G86zxkMJz2jZ_Sig2Asw,12535
|
5
|
-
openseries/frame.py,sha256=lqRwNNs82TCbl1rjVpy48VpndmIgRztIBNitjaHy2Mo,55859
|
6
|
-
openseries/load_plotly.py,sha256=VGDdS8ojPQK7AQr-dGi9IfShi5O0EfjM8kUQrJhG_Zw,2000
|
7
|
-
openseries/owntypes.py,sha256=rx0iINJhJDhe8_6udbhofNCyfrlfzEEGpoqm4h2FTjE,9091
|
8
|
-
openseries/plotly_captor_logo.json,sha256=F5nhMzEyxKywtjvQqMTKgKRCJQYMDIiBgDSxdte8Clo,178
|
9
|
-
openseries/plotly_layouts.json,sha256=FnC5le7YRSb1V8ed3aRr-dEqYtIeE1S6ihtYPpyBynU,1439
|
10
|
-
openseries/portfoliotools.py,sha256=6bgz64-B6qJVrHAE-pLp8JJCmJkO_JAExHL5G3AwPWE,19295
|
11
|
-
openseries/series.py,sha256=7le45RBcBqF9exDzfXfWbY8iiqgl70UUHNOWORvHAuQ,27221
|
12
|
-
openseries/simulation.py,sha256=WHmPU2sNl03YvaL7-Ots7i0I_ZZ9j0hBSCnDYWSypK0,13936
|
13
|
-
openseries-1.8.2.dist-info/LICENSE.md,sha256=wNupG-KLsG0aTncb_SMNDh1ExtrKXlpxSJ6RC-g-SWs,1516
|
14
|
-
openseries-1.8.2.dist-info/METADATA,sha256=NoHlH3cdCzJ7C6paTWqRS3yytteNOBqO6N8ZDY56UWc,45645
|
15
|
-
openseries-1.8.2.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
16
|
-
openseries-1.8.2.dist-info/RECORD,,
|
File without changes
|