openseries 1.4.8__py3-none-any.whl → 1.4.10__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 +90 -7
- openseries/_risk.py +4 -0
- openseries/datefixer.py +8 -5
- openseries/frame.py +37 -30
- openseries/load_plotly.py +2 -0
- openseries/series.py +25 -31
- openseries/simulation.py +10 -0
- openseries/types.py +1 -2
- {openseries-1.4.8.dist-info → openseries-1.4.10.dist-info}/METADATA +17 -10
- openseries-1.4.10.dist-info/RECORD +15 -0
- openseries-1.4.8.dist-info/RECORD +0 -15
- {openseries-1.4.8.dist-info → openseries-1.4.10.dist-info}/LICENSE.md +0 -0
- {openseries-1.4.8.dist-info → openseries-1.4.10.dist-info}/WHEEL +0 -0
openseries/_common_model.py
CHANGED
@@ -10,7 +10,7 @@ from secrets import choice
|
|
10
10
|
from string import ascii_letters
|
11
11
|
from typing import Any, Optional, Union, cast
|
12
12
|
|
13
|
-
from numpy import Inf, isnan, log, maximum, sqrt
|
13
|
+
from numpy import Inf, float64, isnan, log, maximum, sqrt
|
14
14
|
from openpyxl.utils.dataframe import dataframe_to_rows
|
15
15
|
from openpyxl.workbook.workbook import Workbook
|
16
16
|
from openpyxl.worksheet.worksheet import Worksheet
|
@@ -67,6 +67,7 @@ class _CommonModel(BaseModel):
|
|
67
67
|
-------
|
68
68
|
int
|
69
69
|
Number of observations
|
70
|
+
|
70
71
|
"""
|
71
72
|
return len(self.tsdf.index)
|
72
73
|
|
@@ -79,6 +80,7 @@ class _CommonModel(BaseModel):
|
|
79
80
|
-------
|
80
81
|
datetime.date
|
81
82
|
The first date in the timeseries
|
83
|
+
|
82
84
|
"""
|
83
85
|
return cast(dt.date, self.tsdf.index[0])
|
84
86
|
|
@@ -91,6 +93,7 @@ class _CommonModel(BaseModel):
|
|
91
93
|
-------
|
92
94
|
datetime.date
|
93
95
|
The last date in the timeseries
|
96
|
+
|
94
97
|
"""
|
95
98
|
return cast(dt.date, self.tsdf.index[-1])
|
96
99
|
|
@@ -103,6 +106,7 @@ class _CommonModel(BaseModel):
|
|
103
106
|
-------
|
104
107
|
int
|
105
108
|
Number of days from the first date to the last
|
109
|
+
|
106
110
|
"""
|
107
111
|
return (self.last_idx - self.first_idx).days
|
108
112
|
|
@@ -116,6 +120,7 @@ class _CommonModel(BaseModel):
|
|
116
120
|
float
|
117
121
|
Length of the timeseries expressed in years assuming all years
|
118
122
|
have 365.25 days
|
123
|
+
|
119
124
|
"""
|
120
125
|
return self.span_of_days / 365.25
|
121
126
|
|
@@ -128,6 +133,7 @@ class _CommonModel(BaseModel):
|
|
128
133
|
-------
|
129
134
|
float
|
130
135
|
The average number of observations per year
|
136
|
+
|
131
137
|
"""
|
132
138
|
return self.length / self.yearfrac
|
133
139
|
|
@@ -140,6 +146,7 @@ class _CommonModel(BaseModel):
|
|
140
146
|
-------
|
141
147
|
Union[float, Pandas.Series[float]]
|
142
148
|
Maximum drawdown in a single calendar year.
|
149
|
+
|
143
150
|
"""
|
144
151
|
years = Index(d.year for d in self.tsdf.index)
|
145
152
|
mddc = (
|
@@ -168,6 +175,7 @@ class _CommonModel(BaseModel):
|
|
168
175
|
-------
|
169
176
|
Union[float, Pandas.Series[float]]
|
170
177
|
Compounded Annual Growth Rate (CAGR)
|
178
|
+
|
171
179
|
"""
|
172
180
|
return self.geo_ret_func()
|
173
181
|
|
@@ -180,6 +188,7 @@ class _CommonModel(BaseModel):
|
|
180
188
|
-------
|
181
189
|
Union[float, Pandas.Series[float]]
|
182
190
|
Annualized arithmetic mean of returns
|
191
|
+
|
183
192
|
"""
|
184
193
|
return self.arithmetic_ret_func()
|
185
194
|
|
@@ -192,6 +201,7 @@ class _CommonModel(BaseModel):
|
|
192
201
|
-------
|
193
202
|
Union[float, Pandas.Series[float]]
|
194
203
|
Simple return
|
204
|
+
|
195
205
|
"""
|
196
206
|
return self.value_ret_func()
|
197
207
|
|
@@ -207,6 +217,7 @@ class _CommonModel(BaseModel):
|
|
207
217
|
-------
|
208
218
|
Union[float, Pandas.Series[float]]
|
209
219
|
Annualized volatility
|
220
|
+
|
210
221
|
"""
|
211
222
|
return self.vol_func()
|
212
223
|
|
@@ -223,6 +234,7 @@ class _CommonModel(BaseModel):
|
|
223
234
|
-------
|
224
235
|
Union[float, Pandas.Series[float]]
|
225
236
|
Downside deviation
|
237
|
+
|
226
238
|
"""
|
227
239
|
min_accepted_return: float = 0.0
|
228
240
|
return self.downside_deviation_func(min_accepted_return=min_accepted_return)
|
@@ -237,6 +249,7 @@ class _CommonModel(BaseModel):
|
|
237
249
|
Union[float, Pandas.Series[float]]
|
238
250
|
Ratio of the annualized arithmetic mean of returns and annualized
|
239
251
|
volatility.
|
252
|
+
|
240
253
|
"""
|
241
254
|
riskfree_rate: float = 0.0
|
242
255
|
return self.ret_vol_ratio_func(riskfree_rate=riskfree_rate)
|
@@ -252,6 +265,7 @@ class _CommonModel(BaseModel):
|
|
252
265
|
Sortino ratio calculated as the annualized arithmetic mean of returns
|
253
266
|
/ downside deviation. The ratio implies that the riskfree asset has zero
|
254
267
|
volatility, and a minimum acceptable return of zero.
|
268
|
+
|
255
269
|
"""
|
256
270
|
riskfree_rate: float = 0.0
|
257
271
|
minimum_accepted_return: float = 0.0
|
@@ -269,6 +283,7 @@ class _CommonModel(BaseModel):
|
|
269
283
|
-------
|
270
284
|
Union[float, Pandas.Series[float]]
|
271
285
|
Z-score as (last return - mean return) / standard deviation of returns.
|
286
|
+
|
272
287
|
"""
|
273
288
|
return self.z_score_func()
|
274
289
|
|
@@ -281,6 +296,7 @@ class _CommonModel(BaseModel):
|
|
281
296
|
-------
|
282
297
|
Union[float, Pandas.Series[float]]
|
283
298
|
Maximum drawdown without any limit on date range
|
299
|
+
|
284
300
|
"""
|
285
301
|
return self.max_drawdown_func()
|
286
302
|
|
@@ -295,6 +311,7 @@ class _CommonModel(BaseModel):
|
|
295
311
|
-------
|
296
312
|
Union[datetime.date, pandas.Series[dt.date]]
|
297
313
|
Date when the maximum drawdown occurred
|
314
|
+
|
298
315
|
"""
|
299
316
|
mdddf = self.tsdf.copy()
|
300
317
|
mdddf.index = DatetimeIndex(mdddf.index)
|
@@ -318,10 +335,37 @@ class _CommonModel(BaseModel):
|
|
318
335
|
-------
|
319
336
|
Union[float, Pandas.Series[float]]
|
320
337
|
Most negative percentage change
|
338
|
+
|
321
339
|
"""
|
322
340
|
observations: int = 1
|
323
341
|
return self.worst_func(observations=observations)
|
324
342
|
|
343
|
+
@property
|
344
|
+
def worst_month(self: Self) -> Union[float, Series[float]]:
|
345
|
+
"""
|
346
|
+
Most negative month.
|
347
|
+
|
348
|
+
Returns
|
349
|
+
-------
|
350
|
+
Pandas.Series[float]
|
351
|
+
Most negative month
|
352
|
+
|
353
|
+
"""
|
354
|
+
wmdf = self.tsdf.copy()
|
355
|
+
wmdf.index = DatetimeIndex(wmdf.index)
|
356
|
+
result = (
|
357
|
+
wmdf.resample("BME").last().pct_change(fill_method=cast(str, None)).min()
|
358
|
+
)
|
359
|
+
|
360
|
+
if self.tsdf.shape[1] == 1:
|
361
|
+
return float(result.iloc[0])
|
362
|
+
return Series(
|
363
|
+
data=result,
|
364
|
+
index=self.tsdf.columns,
|
365
|
+
name="Worst month",
|
366
|
+
dtype="float64",
|
367
|
+
)
|
368
|
+
|
325
369
|
@property
|
326
370
|
def positive_share(self: Self) -> Union[float, Series[float]]:
|
327
371
|
"""
|
@@ -331,6 +375,7 @@ class _CommonModel(BaseModel):
|
|
331
375
|
-------
|
332
376
|
Union[float, Pandas.Series[float]]
|
333
377
|
The share of percentage changes that are greater than zero
|
378
|
+
|
334
379
|
"""
|
335
380
|
return self.positive_share_func()
|
336
381
|
|
@@ -343,6 +388,7 @@ class _CommonModel(BaseModel):
|
|
343
388
|
-------
|
344
389
|
Union[float, Pandas.Series[float]]
|
345
390
|
Skew of the return distribution
|
391
|
+
|
346
392
|
"""
|
347
393
|
return self.skew_func()
|
348
394
|
|
@@ -355,6 +401,7 @@ class _CommonModel(BaseModel):
|
|
355
401
|
-------
|
356
402
|
Union[float, Pandas.Series[float]]
|
357
403
|
Kurtosis of the return distribution
|
404
|
+
|
358
405
|
"""
|
359
406
|
return self.kurtosis_func()
|
360
407
|
|
@@ -367,6 +414,7 @@ class _CommonModel(BaseModel):
|
|
367
414
|
-------
|
368
415
|
Union[float, Pandas.Series[float]]
|
369
416
|
Downside 95% Conditional Value At Risk "CVaR"
|
417
|
+
|
370
418
|
"""
|
371
419
|
level: float = 0.95
|
372
420
|
return self.cvar_down_func(level=level)
|
@@ -383,6 +431,7 @@ class _CommonModel(BaseModel):
|
|
383
431
|
-------
|
384
432
|
Union[float, Pandas.Series[float]]
|
385
433
|
Downside 95% Value At Risk (VaR)
|
434
|
+
|
386
435
|
"""
|
387
436
|
level: float = 0.95
|
388
437
|
interpolation: LiteralQuantileInterp = "lower"
|
@@ -400,6 +449,7 @@ class _CommonModel(BaseModel):
|
|
400
449
|
Union[float, Pandas.Series[float]]
|
401
450
|
Implied annualized volatility from the Downside 95% VaR using the
|
402
451
|
assumption that returns are normally distributed.
|
452
|
+
|
403
453
|
"""
|
404
454
|
level: float = 0.95
|
405
455
|
interpolation: LiteralQuantileInterp = "lower"
|
@@ -428,6 +478,7 @@ class _CommonModel(BaseModel):
|
|
428
478
|
-------
|
429
479
|
tuple[datetime.date, datetime.date]
|
430
480
|
Start and end date of the chosen date range
|
481
|
+
|
431
482
|
"""
|
432
483
|
earlier, later = self.tsdf.index[0], self.tsdf.index[-1]
|
433
484
|
if any([months_offset, from_dt, to_dt]):
|
@@ -484,6 +535,7 @@ class _CommonModel(BaseModel):
|
|
484
535
|
-------
|
485
536
|
OpenFrame
|
486
537
|
An OpenFrame object
|
538
|
+
|
487
539
|
"""
|
488
540
|
startyear = self.tsdf.index[0].year
|
489
541
|
endyear = self.tsdf.index[-1].year
|
@@ -515,6 +567,7 @@ class _CommonModel(BaseModel):
|
|
515
567
|
-------
|
516
568
|
self
|
517
569
|
An object of the same class
|
570
|
+
|
518
571
|
"""
|
519
572
|
self.tsdf = DataFrame(
|
520
573
|
data=log(self.tsdf / self.tsdf.iloc[0]),
|
@@ -536,6 +589,7 @@ class _CommonModel(BaseModel):
|
|
536
589
|
-------
|
537
590
|
self
|
538
591
|
An object of the same class
|
592
|
+
|
539
593
|
"""
|
540
594
|
if method == "fill":
|
541
595
|
self.tsdf = self.tsdf.ffill()
|
@@ -556,6 +610,7 @@ class _CommonModel(BaseModel):
|
|
556
610
|
-------
|
557
611
|
self
|
558
612
|
An object of the same class
|
613
|
+
|
559
614
|
"""
|
560
615
|
if method == "fill":
|
561
616
|
self.tsdf = self.tsdf.fillna(value=0.0)
|
@@ -571,6 +626,7 @@ class _CommonModel(BaseModel):
|
|
571
626
|
-------
|
572
627
|
self
|
573
628
|
An object of the same class
|
629
|
+
|
574
630
|
"""
|
575
631
|
drawdown = self.tsdf.copy()
|
576
632
|
drawdown[isnan(drawdown)] = -Inf
|
@@ -599,6 +655,7 @@ class _CommonModel(BaseModel):
|
|
599
655
|
-------
|
600
656
|
list[Dict[str, Union[str, bool, ValueType, list[str], list[float]]]]
|
601
657
|
A list of dictionaries with the raw original data of the series
|
658
|
+
|
602
659
|
"""
|
603
660
|
if directory:
|
604
661
|
dirpath = Path(directory).resolve()
|
@@ -656,6 +713,7 @@ class _CommonModel(BaseModel):
|
|
656
713
|
-------
|
657
714
|
str
|
658
715
|
The Excel file path
|
716
|
+
|
659
717
|
"""
|
660
718
|
if filename[-5:].lower() != ".xlsx":
|
661
719
|
msg = "Filename must end with .xlsx"
|
@@ -731,6 +789,7 @@ class _CommonModel(BaseModel):
|
|
731
789
|
-------
|
732
790
|
tuple[plotly.go.Figure, str]
|
733
791
|
Plotly Figure and a div section or a html filename with location
|
792
|
+
|
734
793
|
"""
|
735
794
|
if labels:
|
736
795
|
if len(labels) != self.tsdf.shape[1]:
|
@@ -783,7 +842,7 @@ class _CommonModel(BaseModel):
|
|
783
842
|
auto_open=auto_open,
|
784
843
|
auto_play=False,
|
785
844
|
link_text="",
|
786
|
-
include_plotlyjs=include_plotlyjs,
|
845
|
+
include_plotlyjs=cast(bool, include_plotlyjs),
|
787
846
|
config=fig["config"],
|
788
847
|
output_type=output_type,
|
789
848
|
)
|
@@ -794,7 +853,7 @@ class _CommonModel(BaseModel):
|
|
794
853
|
fig=figure,
|
795
854
|
config=fig["config"],
|
796
855
|
auto_play=False,
|
797
|
-
include_plotlyjs=include_plotlyjs,
|
856
|
+
include_plotlyjs=cast(bool, include_plotlyjs),
|
798
857
|
full_html=False,
|
799
858
|
div_id=div_id,
|
800
859
|
)
|
@@ -848,6 +907,7 @@ class _CommonModel(BaseModel):
|
|
848
907
|
-------
|
849
908
|
tuple[plotly.go.Figure, str]
|
850
909
|
Plotly Figure and a div section or a html filename with location
|
910
|
+
|
851
911
|
"""
|
852
912
|
if labels:
|
853
913
|
if len(labels) != self.tsdf.shape[1]:
|
@@ -915,7 +975,7 @@ class _CommonModel(BaseModel):
|
|
915
975
|
auto_open=auto_open,
|
916
976
|
auto_play=False,
|
917
977
|
link_text="",
|
918
|
-
include_plotlyjs=include_plotlyjs,
|
978
|
+
include_plotlyjs=cast(bool, include_plotlyjs),
|
919
979
|
config=fig["config"],
|
920
980
|
output_type=output_type,
|
921
981
|
)
|
@@ -926,7 +986,7 @@ class _CommonModel(BaseModel):
|
|
926
986
|
fig=figure,
|
927
987
|
config=fig["config"],
|
928
988
|
auto_play=False,
|
929
|
-
include_plotlyjs=include_plotlyjs,
|
989
|
+
include_plotlyjs=cast(bool, include_plotlyjs),
|
930
990
|
full_html=False,
|
931
991
|
div_id=div_id,
|
932
992
|
)
|
@@ -960,6 +1020,7 @@ class _CommonModel(BaseModel):
|
|
960
1020
|
-------
|
961
1021
|
Union[float, Pandas.Series[float]]
|
962
1022
|
Annualized arithmetic mean of returns
|
1023
|
+
|
963
1024
|
"""
|
964
1025
|
earlier, later = self.calc_range(
|
965
1026
|
months_offset=months_from_last,
|
@@ -1021,6 +1082,7 @@ class _CommonModel(BaseModel):
|
|
1021
1082
|
-------
|
1022
1083
|
Union[float, Pandas.Series[float]]
|
1023
1084
|
Annualized volatility
|
1085
|
+
|
1024
1086
|
"""
|
1025
1087
|
earlier, later = self.calc_range(
|
1026
1088
|
months_offset=months_from_last,
|
@@ -1091,6 +1153,7 @@ class _CommonModel(BaseModel):
|
|
1091
1153
|
Union[float, Pandas.Series[float]]
|
1092
1154
|
Implied annualized volatility from the Downside VaR using the
|
1093
1155
|
assumption that returns are normally distributed.
|
1156
|
+
|
1094
1157
|
"""
|
1095
1158
|
return self._var_implied_vol_and_target_func(
|
1096
1159
|
level=level,
|
@@ -1152,6 +1215,7 @@ class _CommonModel(BaseModel):
|
|
1152
1215
|
Union[float, Pandas.Series[float]]
|
1153
1216
|
A position weight multiplier from the ratio between a VaR implied
|
1154
1217
|
volatility and a given target volatility. Multiplier = 1.0 -> target met
|
1218
|
+
|
1155
1219
|
"""
|
1156
1220
|
return self._var_implied_vol_and_target_func(
|
1157
1221
|
target_vol=target_vol,
|
@@ -1218,6 +1282,7 @@ class _CommonModel(BaseModel):
|
|
1218
1282
|
Union[float, Pandas.Series[float]]
|
1219
1283
|
Target volatility if target_vol is provided otherwise the VaR
|
1220
1284
|
implied volatility.
|
1285
|
+
|
1221
1286
|
"""
|
1222
1287
|
earlier, later = self.calc_range(
|
1223
1288
|
months_offset=months_from_last,
|
@@ -1304,6 +1369,7 @@ class _CommonModel(BaseModel):
|
|
1304
1369
|
-------
|
1305
1370
|
Union[float, Pandas.Series[float]]
|
1306
1371
|
Downside Conditional Value At Risk "CVaR"
|
1372
|
+
|
1307
1373
|
"""
|
1308
1374
|
earlier, later = self.calc_range(
|
1309
1375
|
months_offset=months_from_last,
|
@@ -1371,6 +1437,7 @@ class _CommonModel(BaseModel):
|
|
1371
1437
|
-------
|
1372
1438
|
Union[float, Pandas.Series[float]]
|
1373
1439
|
Downside deviation
|
1440
|
+
|
1374
1441
|
"""
|
1375
1442
|
zero: float = 0.0
|
1376
1443
|
earlier, later = self.calc_range(
|
@@ -1437,6 +1504,7 @@ class _CommonModel(BaseModel):
|
|
1437
1504
|
-------
|
1438
1505
|
Union[float, Pandas.Series[float]]
|
1439
1506
|
Compounded Annual Growth Rate (CAGR)
|
1507
|
+
|
1440
1508
|
"""
|
1441
1509
|
zero: float = 0.0
|
1442
1510
|
earlier, later = self.calc_range(
|
@@ -1494,6 +1562,7 @@ class _CommonModel(BaseModel):
|
|
1494
1562
|
-------
|
1495
1563
|
Union[float, Pandas.Series[float]]
|
1496
1564
|
Skew of the return distribution
|
1565
|
+
|
1497
1566
|
"""
|
1498
1567
|
earlier, later = self.calc_range(
|
1499
1568
|
months_offset=months_from_last,
|
@@ -1542,6 +1611,7 @@ class _CommonModel(BaseModel):
|
|
1542
1611
|
-------
|
1543
1612
|
Union[float, Pandas.Series[float]]
|
1544
1613
|
Kurtosis of the return distribution
|
1614
|
+
|
1545
1615
|
"""
|
1546
1616
|
earlier, later = self.calc_range(
|
1547
1617
|
months_offset=months_from_last,
|
@@ -1594,6 +1664,7 @@ class _CommonModel(BaseModel):
|
|
1594
1664
|
-------
|
1595
1665
|
Union[float, Pandas.Series[float]]
|
1596
1666
|
Maximum drawdown without any limit on date range
|
1667
|
+
|
1597
1668
|
"""
|
1598
1669
|
earlier, later = self.calc_range(
|
1599
1670
|
months_offset=months_from_last,
|
@@ -1638,6 +1709,7 @@ class _CommonModel(BaseModel):
|
|
1638
1709
|
-------
|
1639
1710
|
Union[float, Pandas.Series[float]]
|
1640
1711
|
Calculate share of percentage changes that are greater than zero
|
1712
|
+
|
1641
1713
|
"""
|
1642
1714
|
zero: float = 0.0
|
1643
1715
|
earlier, later = self.calc_range(
|
@@ -1707,6 +1779,7 @@ class _CommonModel(BaseModel):
|
|
1707
1779
|
Union[float, Pandas.Series[float]]
|
1708
1780
|
Ratio of the annualized arithmetic mean of returns and annualized
|
1709
1781
|
volatility or, if risk-free return provided, Sharpe ratio
|
1782
|
+
|
1710
1783
|
"""
|
1711
1784
|
ratio = Series(
|
1712
1785
|
self.arithmetic_ret_func(
|
@@ -1724,7 +1797,7 @@ class _CommonModel(BaseModel):
|
|
1724
1797
|
)
|
1725
1798
|
|
1726
1799
|
if self.tsdf.shape[1] == 1:
|
1727
|
-
return float(ratio.iloc[0])
|
1800
|
+
return float(cast(float64, ratio.iloc[0]))
|
1728
1801
|
return Series(
|
1729
1802
|
data=ratio,
|
1730
1803
|
index=self.tsdf.columns,
|
@@ -1772,6 +1845,7 @@ class _CommonModel(BaseModel):
|
|
1772
1845
|
Union[float, Pandas.Series[float]]
|
1773
1846
|
Sortino ratio calculated as ( return - riskfree return ) /
|
1774
1847
|
downside deviation (std dev of returns below MAR)
|
1848
|
+
|
1775
1849
|
"""
|
1776
1850
|
ratio = Series(
|
1777
1851
|
self.arithmetic_ret_func(
|
@@ -1790,7 +1864,7 @@ class _CommonModel(BaseModel):
|
|
1790
1864
|
)
|
1791
1865
|
|
1792
1866
|
if self.tsdf.shape[1] == 1:
|
1793
|
-
return float(ratio.iloc[0])
|
1867
|
+
return float(cast(float64, ratio.iloc[0]))
|
1794
1868
|
return Series(
|
1795
1869
|
data=ratio,
|
1796
1870
|
index=self.tsdf.columns,
|
@@ -1821,6 +1895,7 @@ class _CommonModel(BaseModel):
|
|
1821
1895
|
-------
|
1822
1896
|
Union[float, Pandas.Series[float]]
|
1823
1897
|
Calculate simple return
|
1898
|
+
|
1824
1899
|
"""
|
1825
1900
|
zero: float = 0.0
|
1826
1901
|
earlier, later = self.calc_range(
|
@@ -1867,6 +1942,7 @@ class _CommonModel(BaseModel):
|
|
1867
1942
|
-------
|
1868
1943
|
Union[float, Pandas.Series[float]]
|
1869
1944
|
Calculate simple return for a specific calendar period
|
1945
|
+
|
1870
1946
|
"""
|
1871
1947
|
if month is None:
|
1872
1948
|
period = str(year)
|
@@ -1918,6 +1994,7 @@ class _CommonModel(BaseModel):
|
|
1918
1994
|
-------
|
1919
1995
|
Union[float, Pandas.Series[float]]
|
1920
1996
|
Downside Value At Risk
|
1997
|
+
|
1921
1998
|
"""
|
1922
1999
|
earlier, later = self.calc_range(
|
1923
2000
|
months_offset=months_from_last,
|
@@ -1966,6 +2043,7 @@ class _CommonModel(BaseModel):
|
|
1966
2043
|
Union[float, Pandas.Series[float]]
|
1967
2044
|
Most negative percentage change over a rolling number of observations
|
1968
2045
|
within a chosen date range
|
2046
|
+
|
1969
2047
|
"""
|
1970
2048
|
earlier, later = self.calc_range(
|
1971
2049
|
months_offset=months_from_last,
|
@@ -2014,6 +2092,7 @@ class _CommonModel(BaseModel):
|
|
2014
2092
|
-------
|
2015
2093
|
Union[float, Pandas.Series[float]]
|
2016
2094
|
Z-score as (last return - mean return) / standard deviation of returns
|
2095
|
+
|
2017
2096
|
"""
|
2018
2097
|
earlier, later = self.calc_range(
|
2019
2098
|
months_offset=months_from_last,
|
@@ -2056,6 +2135,7 @@ class _CommonModel(BaseModel):
|
|
2056
2135
|
-------
|
2057
2136
|
Pandas.DataFrame
|
2058
2137
|
Calculate rolling annualized downside CVaR
|
2138
|
+
|
2059
2139
|
"""
|
2060
2140
|
cvar_label = cast(tuple[str], self.tsdf.iloc[:, column].name)[0]
|
2061
2141
|
cvarseries = (
|
@@ -2087,6 +2167,7 @@ class _CommonModel(BaseModel):
|
|
2087
2167
|
-------
|
2088
2168
|
Pandas.DataFrame
|
2089
2169
|
Calculate rolling returns
|
2170
|
+
|
2090
2171
|
"""
|
2091
2172
|
ret_label = cast(tuple[str], self.tsdf.iloc[:, column].name)[0]
|
2092
2173
|
retseries = (
|
@@ -2125,6 +2206,7 @@ class _CommonModel(BaseModel):
|
|
2125
2206
|
-------
|
2126
2207
|
Pandas.DataFrame
|
2127
2208
|
Calculate rolling annualized downside Value At Risk "VaR"
|
2209
|
+
|
2128
2210
|
"""
|
2129
2211
|
var_label = cast(tuple[str], self.tsdf.iloc[:, column].name)[0]
|
2130
2212
|
varseries = (
|
@@ -2162,6 +2244,7 @@ class _CommonModel(BaseModel):
|
|
2162
2244
|
-------
|
2163
2245
|
Pandas.DataFrame
|
2164
2246
|
Calculate rolling annualised volatilities
|
2247
|
+
|
2165
2248
|
"""
|
2166
2249
|
if periods_in_a_year_fixed:
|
2167
2250
|
time_factor = float(periods_in_a_year_fixed)
|
openseries/_risk.py
CHANGED
@@ -43,6 +43,7 @@ def _cvar_down_calc(
|
|
43
43
|
-------
|
44
44
|
float
|
45
45
|
Downside Conditional Value At Risk "CVaR"
|
46
|
+
|
46
47
|
"""
|
47
48
|
if isinstance(data, DataFrame):
|
48
49
|
clean = nan_to_num(data.iloc[:, 0])
|
@@ -77,6 +78,7 @@ def _var_down_calc(
|
|
77
78
|
-------
|
78
79
|
float
|
79
80
|
Downside Value At Risk
|
81
|
+
|
80
82
|
"""
|
81
83
|
if isinstance(data, DataFrame):
|
82
84
|
clean = nan_to_num(data.iloc[:, 0])
|
@@ -110,6 +112,7 @@ def _ewma_calc(
|
|
110
112
|
-------
|
111
113
|
float
|
112
114
|
EWMA volatility value
|
115
|
+
|
113
116
|
"""
|
114
117
|
return cast(
|
115
118
|
float,
|
@@ -133,6 +136,7 @@ def _calc_inv_vol_weights(returns: DataFrame) -> NDArray[float64]:
|
|
133
136
|
-------
|
134
137
|
NDArray[float64]
|
135
138
|
Calculated weights
|
139
|
+
|
136
140
|
"""
|
137
141
|
vol = divide(1.0, std(returns, axis=0, ddof=1))
|
138
142
|
vol[isinf(vol)] = NaN
|
openseries/datefixer.py
CHANGED
@@ -27,7 +27,6 @@ from openseries.types import (
|
|
27
27
|
DateType,
|
28
28
|
HolidayType,
|
29
29
|
LiteralBizDayFreq,
|
30
|
-
LiteralPandasResampleConvention,
|
31
30
|
)
|
32
31
|
|
33
32
|
|
@@ -56,6 +55,7 @@ def holiday_calendar(
|
|
56
55
|
-------
|
57
56
|
numpy.busdaycalendar
|
58
57
|
Generate a business calendar
|
58
|
+
|
59
59
|
"""
|
60
60
|
startyear -= 1
|
61
61
|
endyear += 1
|
@@ -106,6 +106,7 @@ def date_fix(
|
|
106
106
|
-------
|
107
107
|
datetime.date
|
108
108
|
Parsed date
|
109
|
+
|
109
110
|
"""
|
110
111
|
if isinstance(fixerdate, (Timestamp, dt.datetime)):
|
111
112
|
return fixerdate.date()
|
@@ -161,6 +162,7 @@ def date_offset_foll(
|
|
161
162
|
-------
|
162
163
|
datetime.date
|
163
164
|
Off-set date
|
165
|
+
|
164
166
|
"""
|
165
167
|
raw_date = date_fix(raw_date)
|
166
168
|
month_delta = relativedelta(months=months_offset)
|
@@ -206,6 +208,7 @@ def get_previous_business_day_before_today(
|
|
206
208
|
-------
|
207
209
|
datetime.date
|
208
210
|
The previous business day
|
211
|
+
|
209
212
|
"""
|
210
213
|
if today is None:
|
211
214
|
today = dt.datetime.now(tz=dt.timezone.utc).date()
|
@@ -249,6 +252,7 @@ def offset_business_days(
|
|
249
252
|
-------
|
250
253
|
datetime.date
|
251
254
|
The new offset business day
|
255
|
+
|
252
256
|
"""
|
253
257
|
if days <= 0:
|
254
258
|
scaledtoyeardays = int((days * 372 / 250) // 1) - 365
|
@@ -320,6 +324,7 @@ def generate_calendar_date_range(
|
|
320
324
|
-------
|
321
325
|
list[dt.date]
|
322
326
|
List of business day calendar dates
|
327
|
+
|
323
328
|
"""
|
324
329
|
if start and not end:
|
325
330
|
tmp_range = date_range(
|
@@ -372,7 +377,6 @@ def do_resample_to_business_period_ends(
|
|
372
377
|
tail: Series[float],
|
373
378
|
freq: LiteralBizDayFreq,
|
374
379
|
countries: CountriesType,
|
375
|
-
convention: LiteralPandasResampleConvention,
|
376
380
|
) -> DatetimeIndex:
|
377
381
|
"""
|
378
382
|
Resample timeseries frequency to business calendar month end dates.
|
@@ -392,18 +396,17 @@ def do_resample_to_business_period_ends(
|
|
392
396
|
countries: CountriesType
|
393
397
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
394
398
|
to create a business day calendar used for date adjustments
|
395
|
-
convention: LiteralPandasResampleConvention
|
396
|
-
Controls whether to use the start or end of `rule`.
|
397
399
|
|
398
400
|
Returns
|
399
401
|
-------
|
400
402
|
Pandas.DatetimeIndex
|
401
403
|
A date range aligned to business period ends
|
404
|
+
|
402
405
|
"""
|
403
406
|
newhead = head.to_frame().T
|
404
407
|
newtail = tail.to_frame().T
|
405
408
|
data.index = DatetimeIndex(data.index)
|
406
|
-
data = data.resample(rule=freq
|
409
|
+
data = data.resample(rule=freq).last()
|
407
410
|
data = data.drop(index=data.index[-1])
|
408
411
|
data.index = Index(d.date() for d in DatetimeIndex(data.index))
|
409
412
|
|