openseries 1.2.2__py3-none-any.whl → 1.2.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/__init__.py +1 -0
- openseries/common_model.py +265 -171
- openseries/datefixer.py +94 -111
- openseries/frame.py +252 -160
- openseries/load_plotly.py +11 -21
- openseries/risk.py +45 -23
- openseries/series.py +135 -110
- openseries/simulation.py +157 -109
- openseries/types.py +88 -21
- {openseries-1.2.2.dist-info → openseries-1.2.4.dist-info}/METADATA +11 -12
- openseries-1.2.4.dist-info/RECORD +15 -0
- {openseries-1.2.2.dist-info → openseries-1.2.4.dist-info}/WHEEL +1 -1
- openseries-1.2.2.dist-info/RECORD +0 -15
- {openseries-1.2.2.dist-info → openseries-1.2.4.dist-info}/LICENSE.md +0 -0
openseries/common_model.py
CHANGED
@@ -1,14 +1,13 @@
|
|
1
|
-
"""
|
2
|
-
Defining the CommonModel class
|
3
|
-
"""
|
1
|
+
"""Defining the CommonModel class."""
|
4
2
|
import datetime as dt
|
5
3
|
from json import dump
|
4
|
+
from math import ceil
|
5
|
+
from os import path
|
6
6
|
from pathlib import Path
|
7
7
|
from random import choices
|
8
8
|
from string import ascii_letters
|
9
|
-
from
|
10
|
-
|
11
|
-
from math import ceil
|
9
|
+
from typing import Any, Optional, TypeVar, Union, cast
|
10
|
+
|
12
11
|
from numpy import cumprod, log, sqrt
|
13
12
|
from openpyxl import Workbook
|
14
13
|
from openpyxl.utils.dataframe import dataframe_to_rows
|
@@ -17,24 +16,25 @@ from plotly.graph_objs import Figure
|
|
17
16
|
from plotly.offline import plot
|
18
17
|
from scipy.stats import kurtosis, norm, skew
|
19
18
|
|
19
|
+
from openseries.datefixer import get_calc_range
|
20
|
+
from openseries.load_plotly import load_plotly_dict
|
20
21
|
from openseries.risk import cvar_down_calc, drawdown_series, var_down_calc
|
21
22
|
from openseries.types import (
|
22
23
|
LiteralBarPlotMode,
|
23
24
|
LiteralLinePlotMode,
|
24
|
-
LiteralPlotlyOutput,
|
25
25
|
LiteralNanMethod,
|
26
|
+
LiteralPlotlyOutput,
|
27
|
+
LiteralQuantileInterp,
|
26
28
|
ValueType,
|
27
29
|
)
|
28
|
-
from openseries.load_plotly import load_plotly_dict
|
29
|
-
from openseries.datefixer import get_calc_range
|
30
|
-
from openseries.types import LiteralQuantileInterp
|
31
|
-
|
32
30
|
|
33
31
|
TypeCommonModel = TypeVar("TypeCommonModel", bound="CommonModel")
|
34
32
|
|
35
33
|
|
36
34
|
class CommonModel:
|
37
|
-
|
35
|
+
|
36
|
+
"""
|
37
|
+
CommonModel declared.
|
38
38
|
|
39
39
|
Parameters
|
40
40
|
----------
|
@@ -47,73 +47,80 @@ class CommonModel:
|
|
47
47
|
@property
|
48
48
|
def length(self: TypeCommonModel) -> int:
|
49
49
|
"""
|
50
|
+
Number of observations.
|
51
|
+
|
50
52
|
Returns
|
51
53
|
-------
|
52
54
|
int
|
53
55
|
Number of observations
|
54
56
|
"""
|
55
|
-
|
56
57
|
return len(self.tsdf.index)
|
57
58
|
|
58
59
|
@property
|
59
60
|
def first_idx(self: TypeCommonModel) -> dt.date:
|
60
61
|
"""
|
62
|
+
The first date in the timeseries.
|
63
|
+
|
61
64
|
Returns
|
62
65
|
-------
|
63
66
|
datetime.date
|
64
67
|
The first date in the timeseries
|
65
68
|
"""
|
66
|
-
|
67
69
|
return cast(dt.date, self.tsdf.index[0])
|
68
70
|
|
69
71
|
@property
|
70
72
|
def last_idx(self: TypeCommonModel) -> dt.date:
|
71
73
|
"""
|
74
|
+
The last date in the timeseries.
|
75
|
+
|
72
76
|
Returns
|
73
77
|
-------
|
74
78
|
datetime.date
|
75
79
|
The last date in the timeseries
|
76
80
|
"""
|
77
|
-
|
78
81
|
return cast(dt.date, self.tsdf.index[-1])
|
79
82
|
|
80
83
|
@property
|
81
84
|
def span_of_days(self: TypeCommonModel) -> int:
|
82
85
|
"""
|
86
|
+
Number of days from the first date to the last.
|
87
|
+
|
83
88
|
Returns
|
84
89
|
-------
|
85
90
|
int
|
86
91
|
Number of days from the first date to the last
|
87
92
|
"""
|
88
|
-
|
89
93
|
return (self.last_idx - self.first_idx).days
|
90
94
|
|
91
95
|
@property
|
92
96
|
def yearfrac(self: TypeCommonModel) -> float:
|
93
97
|
"""
|
98
|
+
Length of series expressed in years assuming all years have 365.25 days.
|
99
|
+
|
94
100
|
Returns
|
95
101
|
-------
|
96
102
|
float
|
97
103
|
Length of the timeseries expressed in years assuming all years
|
98
104
|
have 365.25 days
|
99
105
|
"""
|
100
|
-
|
101
106
|
return self.span_of_days / 365.25
|
102
107
|
|
103
108
|
@property
|
104
109
|
def periods_in_a_year(self: TypeCommonModel) -> float:
|
105
110
|
"""
|
111
|
+
The average number of observations per year.
|
112
|
+
|
106
113
|
Returns
|
107
114
|
-------
|
108
115
|
float
|
109
116
|
The average number of observations per year
|
110
117
|
"""
|
111
|
-
|
112
118
|
return self.length / self.yearfrac
|
113
119
|
|
114
120
|
@property
|
115
121
|
def max_drawdown_cal_year(self: TypeCommonModel) -> Union[float, Series]:
|
116
|
-
"""
|
122
|
+
"""
|
123
|
+
https://www.investopedia.com/terms/m/maximum-drawdown-mdd.asp.
|
117
124
|
|
118
125
|
Returns
|
119
126
|
-------
|
@@ -125,7 +132,7 @@ class CommonModel:
|
|
125
132
|
self.tsdf.groupby(years)
|
126
133
|
.apply(
|
127
134
|
lambda prices: (prices / prices.expanding(min_periods=1).max()).min()
|
128
|
-
- 1
|
135
|
+
- 1,
|
129
136
|
)
|
130
137
|
.min()
|
131
138
|
)
|
@@ -137,7 +144,8 @@ class CommonModel:
|
|
137
144
|
|
138
145
|
@property
|
139
146
|
def geo_ret(self: TypeCommonModel) -> Union[float, Series]:
|
140
|
-
"""
|
147
|
+
"""
|
148
|
+
https://www.investopedia.com/terms/c/cagr.asp.
|
141
149
|
|
142
150
|
Returns
|
143
151
|
-------
|
@@ -148,19 +156,21 @@ class CommonModel:
|
|
148
156
|
|
149
157
|
@property
|
150
158
|
def arithmetic_ret(self: TypeCommonModel) -> Union[float, Series]:
|
151
|
-
"""
|
159
|
+
"""
|
160
|
+
https://www.investopedia.com/terms/a/arithmeticmean.asp.
|
152
161
|
|
153
162
|
Returns
|
154
163
|
-------
|
155
164
|
Union[float, Pandas.Series]
|
156
165
|
Annualized arithmetic mean of returns
|
157
166
|
"""
|
158
|
-
|
159
167
|
return self.arithmetic_ret_func()
|
160
168
|
|
161
169
|
@property
|
162
170
|
def value_ret(self: TypeCommonModel) -> Union[float, Series]:
|
163
171
|
"""
|
172
|
+
Simple return.
|
173
|
+
|
164
174
|
Returns
|
165
175
|
-------
|
166
176
|
Union[float, Pandas.Series]
|
@@ -170,9 +180,11 @@ class CommonModel:
|
|
170
180
|
|
171
181
|
@property
|
172
182
|
def vol(self: TypeCommonModel) -> Union[float, Series]:
|
173
|
-
"""
|
174
|
-
|
175
|
-
|
183
|
+
"""
|
184
|
+
Annualized volatility.
|
185
|
+
|
186
|
+
Based on Pandas .std() which is the equivalent of stdev.s([...]) in MS Excel.
|
187
|
+
https://www.investopedia.com/terms/v/volatility.asp.
|
176
188
|
|
177
189
|
Returns
|
178
190
|
-------
|
@@ -183,10 +195,12 @@ class CommonModel:
|
|
183
195
|
|
184
196
|
@property
|
185
197
|
def downside_deviation(self: TypeCommonModel) -> Union[float, Series]:
|
186
|
-
"""
|
187
|
-
|
188
|
-
|
189
|
-
|
198
|
+
"""
|
199
|
+
Downside Deviation.
|
200
|
+
|
201
|
+
Standard deviation of returns that are below a Minimum Accepted Return
|
202
|
+
of zero. It is used to calculate the Sortino Ratio.
|
203
|
+
https://www.investopedia.com/terms/d/downside-deviation.asp.
|
190
204
|
|
191
205
|
Returns
|
192
206
|
-------
|
@@ -199,6 +213,8 @@ class CommonModel:
|
|
199
213
|
@property
|
200
214
|
def ret_vol_ratio(self: TypeCommonModel) -> Union[float, Series]:
|
201
215
|
"""
|
216
|
+
Ratio of annualized arithmetic mean of returns and annualized volatility.
|
217
|
+
|
202
218
|
Returns
|
203
219
|
-------
|
204
220
|
Union[float, Pandas.Series]
|
@@ -210,7 +226,8 @@ class CommonModel:
|
|
210
226
|
|
211
227
|
@property
|
212
228
|
def sortino_ratio(self: TypeCommonModel) -> Union[float, Series]:
|
213
|
-
"""
|
229
|
+
"""
|
230
|
+
https://www.investopedia.com/terms/s/sortinoratio.asp.
|
214
231
|
|
215
232
|
Returns
|
216
233
|
-------
|
@@ -222,23 +239,26 @@ class CommonModel:
|
|
222
239
|
riskfree_rate: float = 0.0
|
223
240
|
minimum_accepted_return: float = 0.0
|
224
241
|
return self.sortino_ratio_func(
|
225
|
-
riskfree_rate=riskfree_rate,
|
242
|
+
riskfree_rate=riskfree_rate,
|
243
|
+
min_accepted_return=minimum_accepted_return,
|
226
244
|
)
|
227
245
|
|
228
246
|
@property
|
229
247
|
def z_score(self: TypeCommonModel) -> Union[float, Series]:
|
230
|
-
"""
|
248
|
+
"""
|
249
|
+
https://www.investopedia.com/terms/z/zscore.asp.
|
231
250
|
|
232
251
|
Returns
|
233
252
|
-------
|
234
|
-
float
|
253
|
+
Union[float, Pandas.Series]
|
235
254
|
Z-score as (last return - mean return) / standard deviation of returns.
|
236
255
|
"""
|
237
256
|
return self.z_score_func()
|
238
257
|
|
239
258
|
@property
|
240
259
|
def max_drawdown(self: TypeCommonModel) -> Union[float, Series]:
|
241
|
-
"""
|
260
|
+
"""
|
261
|
+
https://www.investopedia.com/terms/m/maximum-drawdown-mdd.asp.
|
242
262
|
|
243
263
|
Returns
|
244
264
|
-------
|
@@ -250,6 +270,8 @@ class CommonModel:
|
|
250
270
|
@property
|
251
271
|
def worst(self: TypeCommonModel) -> Union[float, Series]:
|
252
272
|
"""
|
273
|
+
Most negative percentage change.
|
274
|
+
|
253
275
|
Returns
|
254
276
|
-------
|
255
277
|
Union[float, Pandas.Series]
|
@@ -261,6 +283,8 @@ class CommonModel:
|
|
261
283
|
@property
|
262
284
|
def positive_share(self: TypeCommonModel) -> Union[float, Series]:
|
263
285
|
"""
|
286
|
+
The share of percentage changes that are greater than zero.
|
287
|
+
|
264
288
|
Returns
|
265
289
|
-------
|
266
290
|
Union[float, Pandas.Series]
|
@@ -270,7 +294,8 @@ class CommonModel:
|
|
270
294
|
|
271
295
|
@property
|
272
296
|
def skew(self: TypeCommonModel) -> Union[float, Series]:
|
273
|
-
"""
|
297
|
+
"""
|
298
|
+
https://www.investopedia.com/terms/s/skewness.asp.
|
274
299
|
|
275
300
|
Returns
|
276
301
|
-------
|
@@ -281,7 +306,8 @@ class CommonModel:
|
|
281
306
|
|
282
307
|
@property
|
283
308
|
def kurtosis(self: TypeCommonModel) -> Union[float, Series]:
|
284
|
-
"""
|
309
|
+
"""
|
310
|
+
https://www.investopedia.com/terms/k/kurtosis.asp.
|
285
311
|
|
286
312
|
Returns
|
287
313
|
-------
|
@@ -292,7 +318,8 @@ class CommonModel:
|
|
292
318
|
|
293
319
|
@property
|
294
320
|
def cvar_down(self: TypeCommonModel) -> Union[float, Series]:
|
295
|
-
"""
|
321
|
+
"""
|
322
|
+
https://www.investopedia.com/terms/c/conditional_value_at_risk.asp.
|
296
323
|
|
297
324
|
Returns
|
298
325
|
-------
|
@@ -304,14 +331,16 @@ class CommonModel:
|
|
304
331
|
|
305
332
|
@property
|
306
333
|
def var_down(self: TypeCommonModel) -> Union[float, Series]:
|
307
|
-
"""
|
308
|
-
|
309
|
-
|
334
|
+
"""
|
335
|
+
Downside 95% Value At Risk (VaR).
|
336
|
+
|
337
|
+
The equivalent of percentile.inc([...], 1-level) over returns in MS Excel.
|
338
|
+
https://www.investopedia.com/terms/v/var.asp.
|
310
339
|
|
311
340
|
Returns
|
312
341
|
-------
|
313
342
|
Union[float, Pandas.Series]
|
314
|
-
Downside 95% Value At Risk
|
343
|
+
Downside 95% Value At Risk (VaR)
|
315
344
|
"""
|
316
345
|
level: float = 0.95
|
317
346
|
interpolation: LiteralQuantileInterp = "lower"
|
@@ -320,6 +349,10 @@ class CommonModel:
|
|
320
349
|
@property
|
321
350
|
def vol_from_var(self: TypeCommonModel) -> Union[float, Series]:
|
322
351
|
"""
|
352
|
+
Implied annualized volatility from Downside 95% Value at Risk.
|
353
|
+
|
354
|
+
Assumes that returns are normally distributed.
|
355
|
+
|
323
356
|
Returns
|
324
357
|
-------
|
325
358
|
Union[float, Pandas.Series]
|
@@ -331,15 +364,16 @@ class CommonModel:
|
|
331
364
|
return self.vol_from_var_func(level=level, interpolation=interpolation)
|
332
365
|
|
333
366
|
def value_to_log(self: TypeCommonModel) -> TypeCommonModel:
|
334
|
-
"""
|
335
|
-
|
367
|
+
"""
|
368
|
+
Series of values converted into logarithmic weighted series.
|
369
|
+
|
370
|
+
Equivalent to LN(value[t] / value[t=0]) in Excel.
|
336
371
|
|
337
372
|
Returns
|
338
373
|
-------
|
339
374
|
self
|
340
375
|
An object of the same class
|
341
376
|
"""
|
342
|
-
|
343
377
|
self.tsdf = DataFrame(
|
344
378
|
data=log(self.tsdf / self.tsdf.iloc[0]),
|
345
379
|
index=self.tsdf.index,
|
@@ -348,9 +382,11 @@ class CommonModel:
|
|
348
382
|
return self
|
349
383
|
|
350
384
|
def value_nan_handle(
|
351
|
-
self: TypeCommonModel,
|
385
|
+
self: TypeCommonModel,
|
386
|
+
method: LiteralNanMethod = "fill",
|
352
387
|
) -> TypeCommonModel:
|
353
|
-
"""
|
388
|
+
"""
|
389
|
+
Handle missing values in a valueseries.
|
354
390
|
|
355
391
|
Parameters
|
356
392
|
----------
|
@@ -363,15 +399,17 @@ class CommonModel:
|
|
363
399
|
An object of the same class
|
364
400
|
"""
|
365
401
|
if method == "fill":
|
366
|
-
self.tsdf.fillna(method="pad"
|
402
|
+
self.tsdf = self.tsdf.fillna(method="pad")
|
367
403
|
else:
|
368
|
-
self.tsdf.dropna(
|
404
|
+
self.tsdf = self.tsdf.dropna()
|
369
405
|
return self
|
370
406
|
|
371
407
|
def return_nan_handle(
|
372
|
-
self: TypeCommonModel,
|
408
|
+
self: TypeCommonModel,
|
409
|
+
method: LiteralNanMethod = "fill",
|
373
410
|
) -> TypeCommonModel:
|
374
|
-
"""
|
411
|
+
"""
|
412
|
+
Handle missing values in a returnseries.
|
375
413
|
|
376
414
|
Parameters
|
377
415
|
----------
|
@@ -384,28 +422,31 @@ class CommonModel:
|
|
384
422
|
An object of the same class
|
385
423
|
"""
|
386
424
|
if method == "fill":
|
387
|
-
self.tsdf.fillna(value=0.0
|
425
|
+
self.tsdf = self.tsdf.fillna(value=0.0)
|
388
426
|
else:
|
389
|
-
self.tsdf.dropna(
|
427
|
+
self.tsdf = self.tsdf.dropna()
|
390
428
|
return self
|
391
429
|
|
392
430
|
def to_drawdown_series(self: TypeCommonModel) -> TypeCommonModel:
|
393
|
-
"""
|
431
|
+
"""
|
432
|
+
Convert timeseries into a drawdown series.
|
394
433
|
|
395
434
|
Returns
|
396
435
|
-------
|
397
436
|
self
|
398
437
|
An object of the same class
|
399
438
|
"""
|
400
|
-
|
401
439
|
for serie in self.tsdf:
|
402
440
|
self.tsdf.loc[:, serie] = drawdown_series(self.tsdf.loc[:, serie])
|
403
441
|
return self
|
404
442
|
|
405
443
|
def to_json(
|
406
|
-
self: TypeCommonModel,
|
444
|
+
self: TypeCommonModel,
|
445
|
+
filename: str,
|
446
|
+
directory: Optional[str] = None,
|
407
447
|
) -> list[dict[str, Union[str, bool, ValueType, list[str], list[float]]]]:
|
408
|
-
"""
|
448
|
+
"""
|
449
|
+
Dump timeseries data into a json file.
|
409
450
|
|
410
451
|
The label and tsdf parameters are deleted before the json file is saved
|
411
452
|
|
@@ -415,6 +456,7 @@ class CommonModel:
|
|
415
456
|
Filename including filetype
|
416
457
|
directory: str, optional
|
417
458
|
File folder location
|
459
|
+
|
418
460
|
Returns
|
419
461
|
-------
|
420
462
|
list[Dict[str, Union[str, bool, ValueType, list[str], list[float]]]]
|
@@ -451,7 +493,8 @@ class CommonModel:
|
|
451
493
|
sheet_title: Optional[str] = None,
|
452
494
|
directory: Optional[str] = None,
|
453
495
|
) -> str:
|
454
|
-
"""
|
496
|
+
"""
|
497
|
+
Save .tsdf DataFrame to an Excel spreadsheet file.
|
455
498
|
|
456
499
|
Parameters
|
457
500
|
----------
|
@@ -461,12 +504,12 @@ class CommonModel:
|
|
461
504
|
Name of the sheet in the Excel file
|
462
505
|
directory: str, optional
|
463
506
|
The file directory where the Excel file is saved.
|
507
|
+
|
464
508
|
Returns
|
465
509
|
-------
|
466
510
|
str
|
467
511
|
The Excel file path
|
468
512
|
"""
|
469
|
-
|
470
513
|
if filename[-5:].lower() != ".xlsx":
|
471
514
|
raise NameError("Filename must end with .xlsx")
|
472
515
|
if directory:
|
@@ -499,7 +542,8 @@ class CommonModel:
|
|
499
542
|
add_logo: bool = True,
|
500
543
|
output_type: LiteralPlotlyOutput = "file",
|
501
544
|
) -> tuple[Figure, str]:
|
502
|
-
"""
|
545
|
+
"""
|
546
|
+
Create a Plotly Bar Figure.
|
503
547
|
|
504
548
|
Parameters
|
505
549
|
----------
|
@@ -525,7 +569,7 @@ class CommonModel:
|
|
525
569
|
|
526
570
|
Returns
|
527
571
|
-------
|
528
|
-
|
572
|
+
tuple[plotly.go.Figure, str]
|
529
573
|
Plotly Figure and html filename with location
|
530
574
|
"""
|
531
575
|
if labels:
|
@@ -584,11 +628,8 @@ class CommonModel:
|
|
584
628
|
show_last: bool = False,
|
585
629
|
output_type: LiteralPlotlyOutput = "file",
|
586
630
|
) -> tuple[Figure, str]:
|
587
|
-
"""
|
588
|
-
|
589
|
-
To scale the bubble size, use the attribute sizeref.
|
590
|
-
We recommend using the following formula to calculate a sizeref value:
|
591
|
-
sizeref = 2. * max(array of size values) / (desired maximum marker size ** 2)
|
631
|
+
"""
|
632
|
+
Create a Plotly Scatter Figure.
|
592
633
|
|
593
634
|
Parameters
|
594
635
|
----------
|
@@ -616,10 +657,9 @@ class CommonModel:
|
|
616
657
|
|
617
658
|
Returns
|
618
659
|
-------
|
619
|
-
|
660
|
+
tuple[plotly.go.Figure, str]
|
620
661
|
Plotly Figure and html filename with location
|
621
662
|
"""
|
622
|
-
|
623
663
|
if labels:
|
624
664
|
assert (
|
625
665
|
len(labels) == self.tsdf.shape[1]
|
@@ -686,7 +726,8 @@ class CommonModel:
|
|
686
726
|
to_date: Optional[dt.date] = None,
|
687
727
|
periods_in_a_year_fixed: Optional[int] = None,
|
688
728
|
) -> Union[float, Series]:
|
689
|
-
"""
|
729
|
+
"""
|
730
|
+
https://www.investopedia.com/terms/a/arithmeticmean.asp.
|
690
731
|
|
691
732
|
Parameters
|
692
733
|
----------
|
@@ -706,7 +747,6 @@ class CommonModel:
|
|
706
747
|
Union[float, Pandas.Series]
|
707
748
|
Annualized arithmetic mean of returns
|
708
749
|
"""
|
709
|
-
|
710
750
|
earlier, later = get_calc_range(
|
711
751
|
data=self.tsdf,
|
712
752
|
months_offset=months_from_last,
|
@@ -718,7 +758,8 @@ class CommonModel:
|
|
718
758
|
else:
|
719
759
|
fraction = (later - earlier).days / 365.25
|
720
760
|
how_many = self.tsdf.loc[
|
721
|
-
cast(int, earlier) : cast(int, later),
|
761
|
+
cast(int, earlier) : cast(int, later),
|
762
|
+
self.tsdf.columns.to_numpy()[0],
|
722
763
|
].count()
|
723
764
|
time_factor = how_many / fraction
|
724
765
|
|
@@ -742,9 +783,11 @@ class CommonModel:
|
|
742
783
|
to_date: Optional[dt.date] = None,
|
743
784
|
periods_in_a_year_fixed: Optional[int] = None,
|
744
785
|
) -> Union[float, Series]:
|
745
|
-
"""
|
746
|
-
|
747
|
-
|
786
|
+
"""
|
787
|
+
Annualized volatility.
|
788
|
+
|
789
|
+
Based on Pandas .std() which is the equivalent of stdev.s([...]) in MS Excel.
|
790
|
+
https://www.investopedia.com/terms/v/volatility.asp.
|
748
791
|
|
749
792
|
Parameters
|
750
793
|
----------
|
@@ -763,7 +806,6 @@ class CommonModel:
|
|
763
806
|
Union[float, Pandas.Series]
|
764
807
|
Annualized volatility
|
765
808
|
"""
|
766
|
-
|
767
809
|
earlier, later = get_calc_range(
|
768
810
|
data=self.tsdf,
|
769
811
|
months_offset=months_from_last,
|
@@ -803,9 +845,13 @@ class CommonModel:
|
|
803
845
|
periods_in_a_year_fixed: Optional[int] = None,
|
804
846
|
) -> Union[float, Series]:
|
805
847
|
"""
|
848
|
+
Implied annualized volatility.
|
849
|
+
|
850
|
+
Implied annualized volatility from the Downside VaR using the assumption
|
851
|
+
that returns are normally distributed.
|
852
|
+
|
806
853
|
Parameters
|
807
854
|
----------
|
808
|
-
|
809
855
|
level: float, default: 0.95
|
810
856
|
The sought VaR level
|
811
857
|
months_from_last : int, optional
|
@@ -853,8 +899,11 @@ class CommonModel:
|
|
853
899
|
drift_adjust: bool = False,
|
854
900
|
periods_in_a_year_fixed: Optional[int] = None,
|
855
901
|
) -> Union[float, Series]:
|
856
|
-
"""
|
857
|
-
|
902
|
+
"""
|
903
|
+
Target weight from VaR.
|
904
|
+
|
905
|
+
A position weight multiplier from the ratio between a VaR implied
|
906
|
+
volatility and a given target volatility. Multiplier = 1.0 -> target met.
|
858
907
|
|
859
908
|
Parameters
|
860
909
|
----------
|
@@ -908,7 +957,10 @@ class CommonModel:
|
|
908
957
|
from_date: Optional[dt.date] = None,
|
909
958
|
to_date: Optional[dt.date] = None,
|
910
959
|
) -> Union[float, Series]:
|
911
|
-
"""
|
960
|
+
"""
|
961
|
+
Downside Conditional Value At Risk "CVaR".
|
962
|
+
|
963
|
+
https://www.investopedia.com/terms/c/conditional_value_at_risk.asp.
|
912
964
|
|
913
965
|
Parameters
|
914
966
|
----------
|
@@ -927,7 +979,6 @@ class CommonModel:
|
|
927
979
|
Union[float, Pandas.Series]
|
928
980
|
Downside Conditional Value At Risk "CVaR"
|
929
981
|
"""
|
930
|
-
|
931
982
|
earlier, later = get_calc_range(
|
932
983
|
data=self.tsdf,
|
933
984
|
months_offset=months_from_last,
|
@@ -960,10 +1011,12 @@ class CommonModel:
|
|
960
1011
|
to_date: Optional[dt.date] = None,
|
961
1012
|
periods_in_a_year_fixed: Optional[int] = None,
|
962
1013
|
) -> Union[float, Series]:
|
963
|
-
"""
|
964
|
-
|
965
|
-
|
966
|
-
|
1014
|
+
"""
|
1015
|
+
Downside Deviation.
|
1016
|
+
|
1017
|
+
The standard deviation of returns that are below a Minimum Accepted
|
1018
|
+
Return of zero. It is used to calculate the Sortino Ratio.
|
1019
|
+
https://www.investopedia.com/terms/d/downside-deviation.asp.
|
967
1020
|
|
968
1021
|
Parameters
|
969
1022
|
----------
|
@@ -985,7 +1038,6 @@ class CommonModel:
|
|
985
1038
|
Union[float, Pandas.Series]
|
986
1039
|
Downside deviation
|
987
1040
|
"""
|
988
|
-
|
989
1041
|
earlier, later = get_calc_range(
|
990
1042
|
data=self.tsdf,
|
991
1043
|
months_offset=months_from_last,
|
@@ -1026,7 +1078,10 @@ class CommonModel:
|
|
1026
1078
|
from_date: Optional[dt.date] = None,
|
1027
1079
|
to_date: Optional[dt.date] = None,
|
1028
1080
|
) -> Union[float, Series]:
|
1029
|
-
"""
|
1081
|
+
"""
|
1082
|
+
Compounded Annual Growth Rate (CAGR).
|
1083
|
+
|
1084
|
+
https://www.investopedia.com/terms/c/cagr.asp.
|
1030
1085
|
|
1031
1086
|
Parameters
|
1032
1087
|
----------
|
@@ -1057,7 +1112,7 @@ class CommonModel:
|
|
1057
1112
|
):
|
1058
1113
|
raise ValueError(
|
1059
1114
|
"Geometric return cannot be calculated due to an initial "
|
1060
|
-
"value being zero or a negative value."
|
1115
|
+
"value being zero or a negative value.",
|
1061
1116
|
)
|
1062
1117
|
|
1063
1118
|
result = (self.tsdf.iloc[-1] / self.tsdf.iloc[0]) ** (1 / fraction) - 1
|
@@ -1071,13 +1126,65 @@ class CommonModel:
|
|
1071
1126
|
dtype="float64",
|
1072
1127
|
)
|
1073
1128
|
|
1129
|
+
def skew_func(
|
1130
|
+
self: TypeCommonModel,
|
1131
|
+
months_from_last: Optional[int] = None,
|
1132
|
+
from_date: Optional[dt.date] = None,
|
1133
|
+
to_date: Optional[dt.date] = None,
|
1134
|
+
) -> Union[float, Series]:
|
1135
|
+
"""
|
1136
|
+
Skew of the return distribution.
|
1137
|
+
|
1138
|
+
https://www.investopedia.com/terms/s/skewness.asp.
|
1139
|
+
|
1140
|
+
Parameters
|
1141
|
+
----------
|
1142
|
+
months_from_last : int, optional
|
1143
|
+
number of months offset as positive integer. Overrides use of from_date
|
1144
|
+
and to_date
|
1145
|
+
from_date : datetime.date, optional
|
1146
|
+
Specific from date
|
1147
|
+
to_date : datetime.date, optional
|
1148
|
+
Specific to date
|
1149
|
+
|
1150
|
+
Returns
|
1151
|
+
-------
|
1152
|
+
Union[float, Pandas.Series]
|
1153
|
+
Skew of the return distribution
|
1154
|
+
"""
|
1155
|
+
earlier, later = get_calc_range(
|
1156
|
+
data=self.tsdf,
|
1157
|
+
months_offset=months_from_last,
|
1158
|
+
from_dt=from_date,
|
1159
|
+
to_dt=to_date,
|
1160
|
+
)
|
1161
|
+
result = skew(
|
1162
|
+
a=self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1163
|
+
.pct_change()
|
1164
|
+
.to_numpy(),
|
1165
|
+
bias=True,
|
1166
|
+
nan_policy="omit",
|
1167
|
+
)
|
1168
|
+
|
1169
|
+
if self.tsdf.shape[1] == 1:
|
1170
|
+
return float(result[0])
|
1171
|
+
return Series(
|
1172
|
+
data=result,
|
1173
|
+
index=self.tsdf.columns,
|
1174
|
+
name="Skew",
|
1175
|
+
dtype="float64",
|
1176
|
+
)
|
1177
|
+
|
1074
1178
|
def kurtosis_func(
|
1075
1179
|
self: TypeCommonModel,
|
1076
1180
|
months_from_last: Optional[int] = None,
|
1077
1181
|
from_date: Optional[dt.date] = None,
|
1078
1182
|
to_date: Optional[dt.date] = None,
|
1079
1183
|
) -> Union[float, Series]:
|
1080
|
-
"""
|
1184
|
+
"""
|
1185
|
+
Kurtosis of the return distribution.
|
1186
|
+
|
1187
|
+
https://www.investopedia.com/terms/k/kurtosis.asp.
|
1081
1188
|
|
1082
1189
|
Parameters
|
1083
1190
|
----------
|
@@ -1094,7 +1201,6 @@ class CommonModel:
|
|
1094
1201
|
Union[float, Pandas.Series]
|
1095
1202
|
Kurtosis of the return distribution
|
1096
1203
|
"""
|
1097
|
-
|
1098
1204
|
earlier, later = get_calc_range(
|
1099
1205
|
data=self.tsdf,
|
1100
1206
|
months_offset=months_from_last,
|
@@ -1124,7 +1230,10 @@ class CommonModel:
|
|
1124
1230
|
to_date: Optional[dt.date] = None,
|
1125
1231
|
min_periods: int = 1,
|
1126
1232
|
) -> Union[float, Series]:
|
1127
|
-
"""
|
1233
|
+
"""
|
1234
|
+
Maximum drawdown without any limit on date range.
|
1235
|
+
|
1236
|
+
https://www.investopedia.com/terms/m/maximum-drawdown-mdd.asp.
|
1128
1237
|
|
1129
1238
|
Parameters
|
1130
1239
|
----------
|
@@ -1166,14 +1275,16 @@ class CommonModel:
|
|
1166
1275
|
|
1167
1276
|
@property
|
1168
1277
|
def max_drawdown_date(self: TypeCommonModel) -> Union[dt.date, Series]:
|
1169
|
-
"""
|
1278
|
+
"""
|
1279
|
+
Date when the maximum drawdown occurred.
|
1280
|
+
|
1281
|
+
https://www.investopedia.com/terms/m/maximum-drawdown-mdd.asp.
|
1170
1282
|
|
1171
1283
|
Returns
|
1172
1284
|
-------
|
1173
1285
|
Union[datetime.date, pandas.Series]
|
1174
1286
|
Date when the maximum drawdown occurred
|
1175
1287
|
"""
|
1176
|
-
|
1177
1288
|
mdddf = self.tsdf.copy()
|
1178
1289
|
mdddf.index = DatetimeIndex(mdddf.index)
|
1179
1290
|
result = (mdddf / mdddf.expanding(min_periods=1).max()).idxmin().dt.date
|
@@ -1184,8 +1295,8 @@ class CommonModel:
|
|
1184
1295
|
data=result,
|
1185
1296
|
index=self.tsdf.columns,
|
1186
1297
|
name="Max drawdown date",
|
1187
|
-
dtype="
|
1188
|
-
)
|
1298
|
+
dtype="datetime64[ns]",
|
1299
|
+
).dt.date
|
1189
1300
|
|
1190
1301
|
def positive_share_func(
|
1191
1302
|
self: TypeCommonModel,
|
@@ -1193,7 +1304,8 @@ class CommonModel:
|
|
1193
1304
|
from_date: Optional[dt.date] = None,
|
1194
1305
|
to_date: Optional[dt.date] = None,
|
1195
1306
|
) -> Union[float, Series]:
|
1196
|
-
"""
|
1307
|
+
"""
|
1308
|
+
Calculate share of percentage changes that are greater than zero.
|
1197
1309
|
|
1198
1310
|
Parameters
|
1199
1311
|
----------
|
@@ -1208,7 +1320,7 @@ class CommonModel:
|
|
1208
1320
|
Returns
|
1209
1321
|
-------
|
1210
1322
|
Union[float, Pandas.Series]
|
1211
|
-
|
1323
|
+
Calculate share of percentage changes that are greater than zero
|
1212
1324
|
"""
|
1213
1325
|
earlier, later = get_calc_range(
|
1214
1326
|
data=self.tsdf,
|
@@ -1244,11 +1356,14 @@ class CommonModel:
|
|
1244
1356
|
to_date: Optional[dt.date] = None,
|
1245
1357
|
periods_in_a_year_fixed: Optional[int] = None,
|
1246
1358
|
) -> Union[float, Series]:
|
1247
|
-
"""
|
1359
|
+
"""
|
1360
|
+
Ratio between arithmetic mean of returns and annualized volatility.
|
1361
|
+
|
1362
|
+
The ratio of annualized arithmetic mean of returns and annualized
|
1248
1363
|
volatility or, if riskfree return provided, Sharpe ratio calculated
|
1249
1364
|
as ( geometric return - risk-free return ) / volatility. The latter ratio
|
1250
|
-
implies that the riskfree asset has zero volatility.
|
1251
|
-
https://www.investopedia.com/terms/s/sharperatio.asp
|
1365
|
+
implies that the riskfree asset has zero volatility.
|
1366
|
+
https://www.investopedia.com/terms/s/sharperatio.asp.
|
1252
1367
|
|
1253
1368
|
Parameters
|
1254
1369
|
----------
|
@@ -1269,8 +1384,7 @@ class CommonModel:
|
|
1269
1384
|
-------
|
1270
1385
|
Union[float, Pandas.Series]
|
1271
1386
|
Ratio of the annualized arithmetic mean of returns and annualized
|
1272
|
-
volatility or,
|
1273
|
-
if risk-free return provided, Sharpe ratio
|
1387
|
+
volatility or, if risk-free return provided, Sharpe ratio
|
1274
1388
|
"""
|
1275
1389
|
ratio: Series = (
|
1276
1390
|
self.arithmetic_ret_func(
|
@@ -1293,50 +1407,6 @@ class CommonModel:
|
|
1293
1407
|
ratio = ratio.astype("float64")
|
1294
1408
|
return ratio
|
1295
1409
|
|
1296
|
-
def skew_func(
|
1297
|
-
self: TypeCommonModel,
|
1298
|
-
months_from_last: Optional[int] = None,
|
1299
|
-
from_date: Optional[dt.date] = None,
|
1300
|
-
to_date: Optional[dt.date] = None,
|
1301
|
-
) -> Union[float, Series]:
|
1302
|
-
"""https://www.investopedia.com/terms/s/skewness.asp
|
1303
|
-
|
1304
|
-
Parameters
|
1305
|
-
----------
|
1306
|
-
months_from_last : int, optional
|
1307
|
-
number of months offset as positive integer. Overrides use of from_date
|
1308
|
-
and to_date
|
1309
|
-
from_date : datetime.date, optional
|
1310
|
-
Specific from date
|
1311
|
-
to_date : datetime.date, optional
|
1312
|
-
Specific to date
|
1313
|
-
|
1314
|
-
Returns
|
1315
|
-
-------
|
1316
|
-
Union[float, Pandas.Series]
|
1317
|
-
Skew of the return distribution
|
1318
|
-
"""
|
1319
|
-
earlier, later = get_calc_range(
|
1320
|
-
data=self.tsdf,
|
1321
|
-
months_offset=months_from_last,
|
1322
|
-
from_dt=from_date,
|
1323
|
-
to_dt=to_date,
|
1324
|
-
)
|
1325
|
-
result = skew(
|
1326
|
-
a=self.tsdf.loc[cast(int, earlier) : cast(int, later)].pct_change().values,
|
1327
|
-
bias=True,
|
1328
|
-
nan_policy="omit",
|
1329
|
-
)
|
1330
|
-
|
1331
|
-
if self.tsdf.shape[1] == 1:
|
1332
|
-
return float(result[0])
|
1333
|
-
return Series(
|
1334
|
-
data=result,
|
1335
|
-
index=self.tsdf.columns,
|
1336
|
-
name="Skew",
|
1337
|
-
dtype="float64",
|
1338
|
-
)
|
1339
|
-
|
1340
1410
|
def sortino_ratio_func(
|
1341
1411
|
self: TypeCommonModel,
|
1342
1412
|
riskfree_rate: float = 0.0,
|
@@ -1346,11 +1416,14 @@ class CommonModel:
|
|
1346
1416
|
to_date: Optional[dt.date] = None,
|
1347
1417
|
periods_in_a_year_fixed: Optional[int] = None,
|
1348
1418
|
) -> Union[float, Series]:
|
1349
|
-
"""
|
1419
|
+
"""
|
1420
|
+
Sortino Ratio.
|
1421
|
+
|
1422
|
+
The Sortino ratio calculated as ( return - risk free return )
|
1350
1423
|
/ downside deviation. The ratio implies that the riskfree asset has zero
|
1351
1424
|
volatility, and a minimum acceptable return of zero. The ratio is
|
1352
|
-
calculated using the annualized arithmetic mean of returns.
|
1353
|
-
https://www.investopedia.com/terms/s/sortinoratio.asp
|
1425
|
+
calculated using the annualized arithmetic mean of returns.
|
1426
|
+
https://www.investopedia.com/terms/s/sortinoratio.asp.
|
1354
1427
|
|
1355
1428
|
Parameters
|
1356
1429
|
----------
|
@@ -1404,6 +1477,8 @@ class CommonModel:
|
|
1404
1477
|
to_date: Optional[dt.date] = None,
|
1405
1478
|
) -> Union[float, Series]:
|
1406
1479
|
"""
|
1480
|
+
Calculate simple return.
|
1481
|
+
|
1407
1482
|
Parameters
|
1408
1483
|
----------
|
1409
1484
|
months_from_last : int, optional
|
@@ -1417,9 +1492,8 @@ class CommonModel:
|
|
1417
1492
|
Returns
|
1418
1493
|
-------
|
1419
1494
|
Union[float, Pandas.Series]
|
1420
|
-
|
1495
|
+
Calculate simple return
|
1421
1496
|
"""
|
1422
|
-
|
1423
1497
|
earlier, later = get_calc_range(
|
1424
1498
|
data=self.tsdf,
|
1425
1499
|
months_offset=months_from_last,
|
@@ -1429,7 +1503,7 @@ class CommonModel:
|
|
1429
1503
|
if 0.0 in self.tsdf.iloc[0].tolist():
|
1430
1504
|
raise ValueError(
|
1431
1505
|
f"Simple return cannot be calculated due to an "
|
1432
|
-
f"initial value being zero. ({self.tsdf.head(3)})"
|
1506
|
+
f"initial value being zero. ({self.tsdf.head(3)})",
|
1433
1507
|
)
|
1434
1508
|
|
1435
1509
|
result = self.tsdf.loc[later] / self.tsdf.loc[earlier] - 1
|
@@ -1444,9 +1518,13 @@ class CommonModel:
|
|
1444
1518
|
)
|
1445
1519
|
|
1446
1520
|
def value_ret_calendar_period(
|
1447
|
-
self: TypeCommonModel,
|
1521
|
+
self: TypeCommonModel,
|
1522
|
+
year: int,
|
1523
|
+
month: Optional[int] = None,
|
1448
1524
|
) -> Union[float, Series]:
|
1449
1525
|
"""
|
1526
|
+
Calculate simple return for a specific calendar period.
|
1527
|
+
|
1450
1528
|
Parameters
|
1451
1529
|
----------
|
1452
1530
|
year : int
|
@@ -1457,9 +1535,8 @@ class CommonModel:
|
|
1457
1535
|
Returns
|
1458
1536
|
-------
|
1459
1537
|
Union[float, Pandas.Series]
|
1460
|
-
|
1538
|
+
Calculate simple return for a specific calendar period
|
1461
1539
|
"""
|
1462
|
-
|
1463
1540
|
if month is None:
|
1464
1541
|
period = str(year)
|
1465
1542
|
else:
|
@@ -1483,9 +1560,11 @@ class CommonModel:
|
|
1483
1560
|
to_date: Optional[dt.date] = None,
|
1484
1561
|
interpolation: LiteralQuantileInterp = "lower",
|
1485
1562
|
) -> Union[float, Series]:
|
1486
|
-
"""
|
1487
|
-
Downside Value At Risk, "VaR".
|
1488
|
-
|
1563
|
+
"""
|
1564
|
+
Downside Value At Risk, "VaR".
|
1565
|
+
|
1566
|
+
The equivalent of percentile.inc([...], 1-level) over returns in MS Excel.
|
1567
|
+
https://www.investopedia.com/terms/v/var.asp.
|
1489
1568
|
|
1490
1569
|
Parameters
|
1491
1570
|
----------
|
@@ -1534,8 +1613,8 @@ class CommonModel:
|
|
1534
1613
|
from_date: Optional[dt.date] = None,
|
1535
1614
|
to_date: Optional[dt.date] = None,
|
1536
1615
|
) -> Union[float, Series]:
|
1537
|
-
"""
|
1538
|
-
|
1616
|
+
"""
|
1617
|
+
Most negative percentage change over a rolling number of observations.
|
1539
1618
|
|
1540
1619
|
Parameters
|
1541
1620
|
----------
|
@@ -1584,7 +1663,10 @@ class CommonModel:
|
|
1584
1663
|
from_date: Optional[dt.date] = None,
|
1585
1664
|
to_date: Optional[dt.date] = None,
|
1586
1665
|
) -> Union[float, Series]:
|
1587
|
-
"""
|
1666
|
+
"""
|
1667
|
+
Z-score as (last return - mean return) / standard deviation of returns.
|
1668
|
+
|
1669
|
+
https://www.investopedia.com/terms/z/zscore.asp.
|
1588
1670
|
|
1589
1671
|
Parameters
|
1590
1672
|
----------
|
@@ -1601,7 +1683,6 @@ class CommonModel:
|
|
1601
1683
|
Union[float, Pandas.Series]
|
1602
1684
|
Z-score as (last return - mean return) / standard deviation of returns
|
1603
1685
|
"""
|
1604
|
-
|
1605
1686
|
earlier, later = get_calc_range(
|
1606
1687
|
data=self.tsdf,
|
1607
1688
|
months_offset=months_from_last,
|
@@ -1627,6 +1708,8 @@ class CommonModel:
|
|
1627
1708
|
observations: int = 252,
|
1628
1709
|
) -> DataFrame:
|
1629
1710
|
"""
|
1711
|
+
Calculate rolling annualized downside CVaR.
|
1712
|
+
|
1630
1713
|
Parameters
|
1631
1714
|
----------
|
1632
1715
|
column: int, default: 0
|
@@ -1639,7 +1722,7 @@ class CommonModel:
|
|
1639
1722
|
Returns
|
1640
1723
|
-------
|
1641
1724
|
Pandas.DataFrame
|
1642
|
-
|
1725
|
+
Calculate rolling annualized downside CVaR
|
1643
1726
|
"""
|
1644
1727
|
cvar_label = self.tsdf.iloc[:, column].name[0]
|
1645
1728
|
cvardf = (
|
@@ -1653,9 +1736,13 @@ class CommonModel:
|
|
1653
1736
|
return cvardf
|
1654
1737
|
|
1655
1738
|
def rolling_return(
|
1656
|
-
self: TypeCommonModel,
|
1739
|
+
self: TypeCommonModel,
|
1740
|
+
column: int = 0,
|
1741
|
+
observations: int = 21,
|
1657
1742
|
) -> DataFrame:
|
1658
1743
|
"""
|
1744
|
+
Calculate rolling returns.
|
1745
|
+
|
1659
1746
|
Parameters
|
1660
1747
|
----------
|
1661
1748
|
column: int, default: 0
|
@@ -1666,7 +1753,7 @@ class CommonModel:
|
|
1666
1753
|
Returns
|
1667
1754
|
-------
|
1668
1755
|
Pandas.DataFrame
|
1669
|
-
|
1756
|
+
Calculate rolling returns
|
1670
1757
|
"""
|
1671
1758
|
ret_label = self.tsdf.iloc[:, column].name[0]
|
1672
1759
|
retdf = (
|
@@ -1688,6 +1775,8 @@ class CommonModel:
|
|
1688
1775
|
interpolation: LiteralQuantileInterp = "lower",
|
1689
1776
|
) -> DataFrame:
|
1690
1777
|
"""
|
1778
|
+
Calculate rolling annualized downside Value At Risk "VaR".
|
1779
|
+
|
1691
1780
|
Parameters
|
1692
1781
|
----------
|
1693
1782
|
column: int, default: 0
|
@@ -1702,14 +1791,14 @@ class CommonModel:
|
|
1702
1791
|
Returns
|
1703
1792
|
-------
|
1704
1793
|
Pandas.DataFrame
|
1705
|
-
|
1794
|
+
Calculate rolling annualized downside Value At Risk "VaR"
|
1706
1795
|
"""
|
1707
1796
|
var_label = self.tsdf.iloc[:, column].name[0]
|
1708
1797
|
vardf = (
|
1709
1798
|
self.tsdf.iloc[:, column]
|
1710
1799
|
.rolling(observations, min_periods=observations)
|
1711
1800
|
.apply(
|
1712
|
-
lambda x: var_down_calc(x, level=level, interpolation=interpolation)
|
1801
|
+
lambda x: var_down_calc(x, level=level, interpolation=interpolation),
|
1713
1802
|
)
|
1714
1803
|
)
|
1715
1804
|
vardf = vardf.dropna().to_frame()
|
@@ -1724,6 +1813,8 @@ class CommonModel:
|
|
1724
1813
|
periods_in_a_year_fixed: Optional[int] = None,
|
1725
1814
|
) -> DataFrame:
|
1726
1815
|
"""
|
1816
|
+
Calculate rolling annualised volatilities.
|
1817
|
+
|
1727
1818
|
Parameters
|
1728
1819
|
----------
|
1729
1820
|
column: int, default: 0
|
@@ -1737,7 +1828,7 @@ class CommonModel:
|
|
1737
1828
|
Returns
|
1738
1829
|
-------
|
1739
1830
|
Pandas.DataFrame
|
1740
|
-
|
1831
|
+
Calculate rolling annualised volatilities
|
1741
1832
|
"""
|
1742
1833
|
if periods_in_a_year_fixed:
|
1743
1834
|
time_factor = float(periods_in_a_year_fixed)
|
@@ -1746,7 +1837,7 @@ class CommonModel:
|
|
1746
1837
|
vol_label = self.tsdf.iloc[:, column].name[0]
|
1747
1838
|
dframe = self.tsdf.iloc[:, column].pct_change()
|
1748
1839
|
voldf = dframe.rolling(observations, min_periods=observations).std() * sqrt(
|
1749
|
-
time_factor
|
1840
|
+
time_factor,
|
1750
1841
|
)
|
1751
1842
|
voldf = voldf.dropna().to_frame()
|
1752
1843
|
voldf.columns = [[vol_label], ["Rolling volatility"]]
|
@@ -1767,10 +1858,13 @@ def _var_implied_vol_and_target_func(
|
|
1767
1858
|
drift_adjust: bool = False,
|
1768
1859
|
periods_in_a_year_fixed: Optional[int] = None,
|
1769
1860
|
) -> Union[float, Series]:
|
1770
|
-
"""
|
1861
|
+
"""
|
1862
|
+
Volatility implied from VaR or Target Weight.
|
1863
|
+
|
1864
|
+
The function returns a position weight multiplier from the ratio between
|
1771
1865
|
a VaR implied volatility and a given target volatility if the argument
|
1772
1866
|
target_vol is provided. Otherwise the function returns the VaR implied
|
1773
|
-
volatility. Multiplier = 1.0 -> target met
|
1867
|
+
volatility. Multiplier = 1.0 -> target met.
|
1774
1868
|
|
1775
1869
|
Parameters
|
1776
1870
|
----------
|
@@ -1836,7 +1930,7 @@ def _var_implied_vol_and_target_func(
|
|
1836
1930
|
|
1837
1931
|
if target_vol:
|
1838
1932
|
result = imp_vol.apply(
|
1839
|
-
lambda x: max(min_leverage_local, min(target_vol / x, max_leverage_local))
|
1933
|
+
lambda x: max(min_leverage_local, min(target_vol / x, max_leverage_local)),
|
1840
1934
|
)
|
1841
1935
|
label = "Weight from target vol"
|
1842
1936
|
else:
|