openbb-technical 1.2.2__tar.gz → 1.3.0__tar.gz
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.
- {openbb_technical-1.2.2 → openbb_technical-1.3.0}/PKG-INFO +6 -5
- {openbb_technical-1.2.2 → openbb_technical-1.3.0}/openbb_technical/helpers.py +93 -70
- {openbb_technical-1.2.2 → openbb_technical-1.3.0}/openbb_technical/relative_rotation.py +61 -34
- {openbb_technical-1.2.2 → openbb_technical-1.3.0}/openbb_technical/technical_router.py +93 -3
- openbb_technical-1.3.0/openbb_technical/technical_views.py +544 -0
- {openbb_technical-1.2.2 → openbb_technical-1.3.0}/pyproject.toml +8 -4
- {openbb_technical-1.2.2 → openbb_technical-1.3.0}/README.md +0 -0
- {openbb_technical-1.2.2 → openbb_technical-1.3.0}/openbb_technical/__init__.py +0 -0
- {openbb_technical-1.2.2 → openbb_technical-1.3.0}/openbb_technical/py.typed +0 -0
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: openbb-technical
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Technical Analysis extension for OpenBB
|
|
5
5
|
License: AGPL-3.0-only
|
|
6
6
|
Author: OpenBB Team
|
|
7
7
|
Author-email: hello@openbb.co
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.9,<3.13
|
|
9
9
|
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.9
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
-
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Dist: numpy (>=1,<2)
|
|
16
|
+
Requires-Dist: openbb-core (>=1.3.0,<2.0.0)
|
|
16
17
|
Requires-Dist: pandas-ta (>=0.3.14b,<0.4.0)
|
|
17
|
-
Requires-Dist: scikit-learn (>=1.
|
|
18
|
+
Requires-Dist: scikit-learn (>=1.5.0,<2.0.0)
|
|
18
19
|
Requires-Dist: scipy (>=1.10.1,<2.0.0)
|
|
19
20
|
Requires-Dist: statsmodels (>=0.14.0,<0.15.0)
|
|
20
21
|
Description-Content-Type: text/markdown
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"""Technical Analysis Helpers."""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# pylint: disable=too-many-arguments, too-many-locals
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any, List, Literal, Optional, Tuple, Union
|
|
4
6
|
from warnings import warn
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from pandas import DataFrame, Series, Timestamp
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
def validate_data(data: list, length: Union[int, List[int]]) -> None:
|
|
@@ -19,12 +21,12 @@ def validate_data(data: list, length: Union[int, List[int]]) -> None:
|
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
def parkinson(
|
|
22
|
-
data:
|
|
24
|
+
data: "DataFrame",
|
|
23
25
|
window: int = 30,
|
|
24
26
|
trading_periods: Optional[int] = None,
|
|
25
27
|
is_crypto: bool = False,
|
|
26
28
|
clean=True,
|
|
27
|
-
) ->
|
|
29
|
+
) -> "DataFrame":
|
|
28
30
|
"""Parkinson volatility.
|
|
29
31
|
|
|
30
32
|
Uses the high and low price of the day rather than just close to close prices.
|
|
@@ -32,7 +34,7 @@ def parkinson(
|
|
|
32
34
|
|
|
33
35
|
Parameters
|
|
34
36
|
----------
|
|
35
|
-
data :
|
|
37
|
+
data : DataFrame
|
|
36
38
|
Dataframe of OHLC prices.
|
|
37
39
|
window : int [default: 30]
|
|
38
40
|
Length of window to calculate over.
|
|
@@ -45,9 +47,12 @@ def parkinson(
|
|
|
45
47
|
|
|
46
48
|
Returns
|
|
47
49
|
-------
|
|
48
|
-
|
|
50
|
+
DataFrame : results
|
|
49
51
|
Dataframe with results.
|
|
50
52
|
"""
|
|
53
|
+
# pylint: disable=import-outside-toplevel
|
|
54
|
+
from numpy import log
|
|
55
|
+
|
|
51
56
|
if window < 1:
|
|
52
57
|
warn("Error: Window must be at least 1, defaulting to 30.")
|
|
53
58
|
window = 30
|
|
@@ -58,9 +63,7 @@ def parkinson(
|
|
|
58
63
|
if not trading_periods:
|
|
59
64
|
trading_periods = 365 if is_crypto else 252
|
|
60
65
|
|
|
61
|
-
rs = (1.0 / (4.0 *
|
|
62
|
-
(data["high"] / data["low"]).apply(np.log)
|
|
63
|
-
) ** 2.0
|
|
66
|
+
rs = (1.0 / (4.0 * log(2.0))) * ((data["high"] / data["low"]).apply(log)) ** 2.0
|
|
64
67
|
|
|
65
68
|
def f(v):
|
|
66
69
|
return (trading_periods * v.mean()) ** 0.5
|
|
@@ -74,12 +77,12 @@ def parkinson(
|
|
|
74
77
|
|
|
75
78
|
|
|
76
79
|
def standard_deviation(
|
|
77
|
-
data:
|
|
80
|
+
data: "DataFrame",
|
|
78
81
|
window: int = 30,
|
|
79
82
|
trading_periods: Optional[int] = None,
|
|
80
83
|
is_crypto: bool = False,
|
|
81
84
|
clean: bool = True,
|
|
82
|
-
) ->
|
|
85
|
+
) -> "DataFrame":
|
|
83
86
|
"""Calculate the Standard deviation.
|
|
84
87
|
|
|
85
88
|
Measures how widely returns are dispersed from the average return.
|
|
@@ -87,7 +90,7 @@ def standard_deviation(
|
|
|
87
90
|
|
|
88
91
|
Parameters
|
|
89
92
|
----------
|
|
90
|
-
data :
|
|
93
|
+
data : DataFrame
|
|
91
94
|
Dataframe of OHLC prices.
|
|
92
95
|
window : int [default: 30]
|
|
93
96
|
Length of window to calculate over.
|
|
@@ -100,9 +103,12 @@ def standard_deviation(
|
|
|
100
103
|
|
|
101
104
|
Returns
|
|
102
105
|
-------
|
|
103
|
-
|
|
106
|
+
DataFrame : results
|
|
104
107
|
Dataframe with results.
|
|
105
108
|
"""
|
|
109
|
+
# pylint: disable=import-outside-toplevel
|
|
110
|
+
from numpy import log, sqrt
|
|
111
|
+
|
|
106
112
|
if window < 2:
|
|
107
113
|
warn("Error: Window must be at least 2, defaulting to 30.")
|
|
108
114
|
window = 30
|
|
@@ -113,9 +119,9 @@ def standard_deviation(
|
|
|
113
119
|
if not trading_periods:
|
|
114
120
|
trading_periods = 365 if is_crypto else 252
|
|
115
121
|
|
|
116
|
-
log_return = (data["close"] / data["close"].shift(1)).apply(
|
|
122
|
+
log_return = (data["close"] / data["close"].shift(1)).apply(log)
|
|
117
123
|
|
|
118
|
-
result = log_return.rolling(window=window, center=False).std() *
|
|
124
|
+
result = log_return.rolling(window=window, center=False).std() * sqrt(
|
|
119
125
|
trading_periods
|
|
120
126
|
)
|
|
121
127
|
|
|
@@ -126,12 +132,12 @@ def standard_deviation(
|
|
|
126
132
|
|
|
127
133
|
|
|
128
134
|
def garman_klass(
|
|
129
|
-
data:
|
|
135
|
+
data: "DataFrame",
|
|
130
136
|
window: int = 30,
|
|
131
137
|
trading_periods: Optional[int] = None,
|
|
132
138
|
is_crypto: bool = False,
|
|
133
139
|
clean=True,
|
|
134
|
-
) ->
|
|
140
|
+
) -> "DataFrame":
|
|
135
141
|
"""Garman-Klass volatility.
|
|
136
142
|
|
|
137
143
|
Extends Parkinson volatility by taking into account the opening and closing price.
|
|
@@ -140,7 +146,7 @@ def garman_klass(
|
|
|
140
146
|
|
|
141
147
|
Parameters
|
|
142
148
|
----------
|
|
143
|
-
data :
|
|
149
|
+
data : DataFrame
|
|
144
150
|
Dataframe of OHLC prices.
|
|
145
151
|
window : int [default: 30]
|
|
146
152
|
Length of window to calculate over.
|
|
@@ -153,9 +159,12 @@ def garman_klass(
|
|
|
153
159
|
|
|
154
160
|
Returns
|
|
155
161
|
-------
|
|
156
|
-
|
|
162
|
+
DataFrame : results
|
|
157
163
|
Dataframe with results.
|
|
158
164
|
"""
|
|
165
|
+
# pylint: disable=import-outside-toplevel
|
|
166
|
+
from numpy import log
|
|
167
|
+
|
|
159
168
|
if window < 1:
|
|
160
169
|
warn("Error: Window must be at least 1, defaulting to 30.")
|
|
161
170
|
window = 30
|
|
@@ -166,10 +175,10 @@ def garman_klass(
|
|
|
166
175
|
if not trading_periods:
|
|
167
176
|
trading_periods = 365 if is_crypto else 252
|
|
168
177
|
|
|
169
|
-
log_hl = (data["high"] / data["low"]).apply(
|
|
170
|
-
log_co = (data["close"] / data["open"]).apply(
|
|
178
|
+
log_hl = (data["high"] / data["low"]).apply(log)
|
|
179
|
+
log_co = (data["close"] / data["open"]).apply(log)
|
|
171
180
|
|
|
172
|
-
rs = 0.5 * log_hl**2 - (2 *
|
|
181
|
+
rs = 0.5 * log_hl**2 - (2 * log(2) - 1) * log_co**2
|
|
173
182
|
|
|
174
183
|
def f(v):
|
|
175
184
|
return (trading_periods * v.mean()) ** 0.5
|
|
@@ -183,12 +192,12 @@ def garman_klass(
|
|
|
183
192
|
|
|
184
193
|
|
|
185
194
|
def hodges_tompkins(
|
|
186
|
-
data:
|
|
195
|
+
data: "DataFrame",
|
|
187
196
|
window: int = 30,
|
|
188
197
|
trading_periods: Optional[int] = None,
|
|
189
198
|
is_crypto: bool = False,
|
|
190
199
|
clean=True,
|
|
191
|
-
) ->
|
|
200
|
+
) -> "DataFrame":
|
|
192
201
|
"""Hodges-Tompkins volatility.
|
|
193
202
|
|
|
194
203
|
Is a bias correction for estimation using an overlapping data sample.
|
|
@@ -196,7 +205,7 @@ def hodges_tompkins(
|
|
|
196
205
|
|
|
197
206
|
Parameters
|
|
198
207
|
----------
|
|
199
|
-
data :
|
|
208
|
+
data : DataFrame
|
|
200
209
|
Dataframe of OHLC prices.
|
|
201
210
|
window : int [default: 30]
|
|
202
211
|
Length of window to calculate over.
|
|
@@ -209,7 +218,7 @@ def hodges_tompkins(
|
|
|
209
218
|
|
|
210
219
|
Returns
|
|
211
220
|
-------
|
|
212
|
-
|
|
221
|
+
DataFrame : results
|
|
213
222
|
Dataframe with results.
|
|
214
223
|
|
|
215
224
|
Example
|
|
@@ -217,6 +226,9 @@ def hodges_tompkins(
|
|
|
217
226
|
>>> data = obb.equity.price.historical('BTC-USD')
|
|
218
227
|
>>> df = obb.technical.hodges_tompkins(data, is_crypto = True)
|
|
219
228
|
"""
|
|
229
|
+
# pylint: disable=import-outside-toplevel
|
|
230
|
+
from numpy import log, sqrt
|
|
231
|
+
|
|
220
232
|
if window < 2:
|
|
221
233
|
warn("Error: Window must be at least 2, defaulting to 30.")
|
|
222
234
|
window = 30
|
|
@@ -227,11 +239,9 @@ def hodges_tompkins(
|
|
|
227
239
|
if not trading_periods:
|
|
228
240
|
trading_periods = 365 if is_crypto else 252
|
|
229
241
|
|
|
230
|
-
log_return = (data["close"] / data["close"].shift(1)).apply(
|
|
242
|
+
log_return = (data["close"] / data["close"].shift(1)).apply(log)
|
|
231
243
|
|
|
232
|
-
vol = log_return.rolling(window=window, center=False).std() *
|
|
233
|
-
trading_periods
|
|
234
|
-
)
|
|
244
|
+
vol = log_return.rolling(window=window, center=False).std() * sqrt(trading_periods)
|
|
235
245
|
|
|
236
246
|
h = window
|
|
237
247
|
n = (log_return.count() - h) + 1
|
|
@@ -247,12 +257,12 @@ def hodges_tompkins(
|
|
|
247
257
|
|
|
248
258
|
|
|
249
259
|
def rogers_satchell(
|
|
250
|
-
data:
|
|
260
|
+
data: "DataFrame",
|
|
251
261
|
window: int = 30,
|
|
252
262
|
trading_periods: Optional[int] = None,
|
|
253
263
|
is_crypto: bool = False,
|
|
254
264
|
clean=True,
|
|
255
|
-
) ->
|
|
265
|
+
) -> "Series":
|
|
256
266
|
"""Rogers-Satchell Estimator.
|
|
257
267
|
|
|
258
268
|
Is an estimator for measuring the volatility with an average return not equal to zero.
|
|
@@ -261,7 +271,7 @@ def rogers_satchell(
|
|
|
261
271
|
|
|
262
272
|
Parameters
|
|
263
273
|
----------
|
|
264
|
-
data :
|
|
274
|
+
data : DataFrame
|
|
265
275
|
Dataframe of OHLC prices.
|
|
266
276
|
window : int [default: 30]
|
|
267
277
|
Length of window to calculate over.
|
|
@@ -274,9 +284,12 @@ def rogers_satchell(
|
|
|
274
284
|
|
|
275
285
|
Returns
|
|
276
286
|
-------
|
|
277
|
-
|
|
287
|
+
Series : results
|
|
278
288
|
Pandas Series with results.
|
|
279
289
|
"""
|
|
290
|
+
# pylint: disable=import-outside-toplevel
|
|
291
|
+
from numpy import log
|
|
292
|
+
|
|
280
293
|
if window < 1:
|
|
281
294
|
warn("Error: Window must be at least 1, defaulting to 30.")
|
|
282
295
|
window = 30
|
|
@@ -287,9 +300,9 @@ def rogers_satchell(
|
|
|
287
300
|
if not trading_periods:
|
|
288
301
|
trading_periods = 365 if is_crypto else 252
|
|
289
302
|
|
|
290
|
-
log_ho = (data["high"] / data["open"]).apply(
|
|
291
|
-
log_lo = (data["low"] / data["open"]).apply(
|
|
292
|
-
log_co = (data["close"] / data["open"]).apply(
|
|
303
|
+
log_ho = (data["high"] / data["open"]).apply(log)
|
|
304
|
+
log_lo = (data["low"] / data["open"]).apply(log)
|
|
305
|
+
log_co = (data["close"] / data["open"]).apply(log)
|
|
293
306
|
|
|
294
307
|
rs = log_ho * (log_ho - log_co) + log_lo * (log_lo - log_co)
|
|
295
308
|
|
|
@@ -305,12 +318,12 @@ def rogers_satchell(
|
|
|
305
318
|
|
|
306
319
|
|
|
307
320
|
def yang_zhang(
|
|
308
|
-
data:
|
|
321
|
+
data: "DataFrame",
|
|
309
322
|
window: int = 30,
|
|
310
323
|
trading_periods: Optional[int] = None,
|
|
311
324
|
is_crypto: bool = False,
|
|
312
325
|
clean=True,
|
|
313
|
-
) ->
|
|
326
|
+
) -> "DataFrame":
|
|
314
327
|
"""Yang-Zhang Volatility.
|
|
315
328
|
|
|
316
329
|
Is the combination of the overnight (close-to-open volatility).
|
|
@@ -318,7 +331,7 @@ def yang_zhang(
|
|
|
318
331
|
|
|
319
332
|
Parameters
|
|
320
333
|
----------
|
|
321
|
-
data :
|
|
334
|
+
data : DataFrame
|
|
322
335
|
Dataframe of OHLC prices.
|
|
323
336
|
window : int [default: 30]
|
|
324
337
|
Length of window to calculate standard deviation.
|
|
@@ -331,9 +344,12 @@ def yang_zhang(
|
|
|
331
344
|
|
|
332
345
|
Returns
|
|
333
346
|
-------
|
|
334
|
-
|
|
347
|
+
DataFrame : results
|
|
335
348
|
Dataframe with results.
|
|
336
349
|
"""
|
|
350
|
+
# pylint: disable=import-outside-toplevel
|
|
351
|
+
from numpy import log, sqrt
|
|
352
|
+
|
|
337
353
|
if window < 2:
|
|
338
354
|
warn("Error: Window must be at least 2, defaulting to 30.")
|
|
339
355
|
window = 30
|
|
@@ -344,14 +360,14 @@ def yang_zhang(
|
|
|
344
360
|
if not trading_periods:
|
|
345
361
|
trading_periods = 365 if is_crypto else 252
|
|
346
362
|
|
|
347
|
-
log_ho = (data["high"] / data["open"]).apply(
|
|
348
|
-
log_lo = (data["low"] / data["open"]).apply(
|
|
349
|
-
log_co = (data["close"] / data["open"]).apply(
|
|
363
|
+
log_ho = (data["high"] / data["open"]).apply(log)
|
|
364
|
+
log_lo = (data["low"] / data["open"]).apply(log)
|
|
365
|
+
log_co = (data["close"] / data["open"]).apply(log)
|
|
350
366
|
|
|
351
|
-
log_oc = (data["open"] / data["close"].shift(1)).apply(
|
|
367
|
+
log_oc = (data["open"] / data["close"].shift(1)).apply(log)
|
|
352
368
|
log_oc_sq = log_oc**2
|
|
353
369
|
|
|
354
|
-
log_cc = (data["close"] / data["close"].shift(1)).apply(
|
|
370
|
+
log_cc = (data["close"] / data["close"].shift(1)).apply(log)
|
|
355
371
|
log_cc_sq = log_cc**2
|
|
356
372
|
|
|
357
373
|
rs = log_ho * (log_ho - log_co) + log_lo * (log_lo - log_co)
|
|
@@ -365,7 +381,7 @@ def yang_zhang(
|
|
|
365
381
|
window_rs = rs.rolling(window=window, center=False).sum() * (1.0 / (window - 1.0))
|
|
366
382
|
|
|
367
383
|
k = 0.34 / (1.34 + (window + 1) / (window - 1))
|
|
368
|
-
result = (open_vol + k * close_vol + (1 - k) * window_rs).apply(
|
|
384
|
+
result = (open_vol + k * close_vol + (1 - k) * window_rs).apply(sqrt) * sqrt(
|
|
369
385
|
trading_periods
|
|
370
386
|
)
|
|
371
387
|
|
|
@@ -376,7 +392,7 @@ def yang_zhang(
|
|
|
376
392
|
|
|
377
393
|
|
|
378
394
|
def calculate_cones(
|
|
379
|
-
data:
|
|
395
|
+
data: "DataFrame",
|
|
380
396
|
lower_q: float,
|
|
381
397
|
upper_q: float,
|
|
382
398
|
is_crypto: bool,
|
|
@@ -389,9 +405,12 @@ def calculate_cones(
|
|
|
389
405
|
"yang_zhang",
|
|
390
406
|
],
|
|
391
407
|
trading_periods: Optional[int] = None,
|
|
392
|
-
) ->
|
|
408
|
+
) -> "DataFrame":
|
|
393
409
|
"""Calculate Cones."""
|
|
394
|
-
|
|
410
|
+
# pylint: disable=import-outside-toplevel
|
|
411
|
+
from pandas import DataFrame
|
|
412
|
+
|
|
413
|
+
estimator = DataFrame()
|
|
395
414
|
|
|
396
415
|
if lower_q > upper_q:
|
|
397
416
|
lower_q, upper_q = upper_q, lower_q
|
|
@@ -443,7 +462,7 @@ def calculate_cones(
|
|
|
443
462
|
|
|
444
463
|
df_ = [realized, min_, bottom_q, median, top_q, max_]
|
|
445
464
|
df_windows = allowed_windows
|
|
446
|
-
df =
|
|
465
|
+
df = DataFrame(df_, columns=df_windows)
|
|
447
466
|
df = df.rename(
|
|
448
467
|
index={
|
|
449
468
|
0: "realized",
|
|
@@ -459,8 +478,8 @@ def calculate_cones(
|
|
|
459
478
|
|
|
460
479
|
|
|
461
480
|
def clenow_momentum(
|
|
462
|
-
values:
|
|
463
|
-
) -> Tuple[float, float,
|
|
481
|
+
values: "Series", window: int = 90
|
|
482
|
+
) -> Tuple[float, float, "Series"]:
|
|
464
483
|
"""Clenow Volatility Adjusted Momentum.
|
|
465
484
|
|
|
466
485
|
This is defined as the regression coefficient on log prices multiplied by the R^2
|
|
@@ -468,7 +487,7 @@ def clenow_momentum(
|
|
|
468
487
|
|
|
469
488
|
Parameters
|
|
470
489
|
----------
|
|
471
|
-
values:
|
|
490
|
+
values: Series
|
|
472
491
|
Values to perform regression for
|
|
473
492
|
window: int
|
|
474
493
|
Length of look back period
|
|
@@ -479,43 +498,44 @@ def clenow_momentum(
|
|
|
479
498
|
R2 of fit to log data
|
|
480
499
|
float:
|
|
481
500
|
Coefficient of linear regression
|
|
482
|
-
|
|
501
|
+
Series:
|
|
483
502
|
Values for best fit line
|
|
484
503
|
"""
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
504
|
+
# pylint: disable=import-outside-toplevel
|
|
505
|
+
from numpy import arange, exp, log
|
|
506
|
+
from pandas import Series
|
|
507
|
+
from sklearn.linear_model import LinearRegression
|
|
488
508
|
|
|
489
509
|
if len(values) < window:
|
|
490
510
|
raise ValueError(f"Calculation asks for at least last {window} days of data")
|
|
491
511
|
|
|
492
512
|
values = values[-window:]
|
|
493
513
|
|
|
494
|
-
y =
|
|
495
|
-
X =
|
|
514
|
+
y = log(values)
|
|
515
|
+
X = arange(len(y)).reshape(-1, 1) # pylint: disable=invalid-name
|
|
496
516
|
|
|
497
517
|
lr = LinearRegression()
|
|
498
518
|
lr.fit(X, y)
|
|
499
519
|
|
|
500
520
|
r2 = lr.score(X, y)
|
|
501
521
|
coef = lr.coef_[0]
|
|
502
|
-
annualized_coef = (
|
|
522
|
+
annualized_coef = (exp(coef) ** 252) - 1
|
|
503
523
|
|
|
504
|
-
return r2, annualized_coef,
|
|
524
|
+
return r2, annualized_coef, Series(lr.predict(X))
|
|
505
525
|
|
|
506
526
|
|
|
507
527
|
def calculate_fib_levels(
|
|
508
|
-
data:
|
|
528
|
+
data: "DataFrame",
|
|
509
529
|
close_col: str,
|
|
510
530
|
limit: int = 120,
|
|
511
531
|
start_date: Optional[Any] = None,
|
|
512
532
|
end_date: Optional[Any] = None,
|
|
513
|
-
) -> Tuple[
|
|
533
|
+
) -> Tuple["DataFrame", "Timestamp", "Timestamp", float, float, str]:
|
|
514
534
|
"""Calculate Fibonacci levels.
|
|
515
535
|
|
|
516
536
|
Parameters
|
|
517
537
|
----------
|
|
518
|
-
data :
|
|
538
|
+
data : DataFrame
|
|
519
539
|
Dataframe of prices
|
|
520
540
|
close_col : str
|
|
521
541
|
Column name of close prices
|
|
@@ -528,17 +548,20 @@ def calculate_fib_levels(
|
|
|
528
548
|
|
|
529
549
|
Returns
|
|
530
550
|
-------
|
|
531
|
-
df :
|
|
551
|
+
df : DataFrame
|
|
532
552
|
Dataframe of fib levels
|
|
533
|
-
min_date:
|
|
553
|
+
min_date: Timestamp
|
|
534
554
|
Date of min point
|
|
535
|
-
max_date:
|
|
555
|
+
max_date: Timestamp:
|
|
536
556
|
Date of max point
|
|
537
557
|
min_pr: float
|
|
538
558
|
Price at min point
|
|
539
559
|
max_pr: float
|
|
540
560
|
Price at max point
|
|
541
561
|
"""
|
|
562
|
+
# pylint: disable=import-outside-toplevel
|
|
563
|
+
from pandas import DataFrame
|
|
564
|
+
|
|
542
565
|
if close_col not in data.columns:
|
|
543
566
|
raise ValueError(f"Column {close_col} not in data")
|
|
544
567
|
|
|
@@ -588,7 +611,7 @@ def calculate_fib_levels(
|
|
|
588
611
|
for f_lev in fib_levels
|
|
589
612
|
]
|
|
590
613
|
|
|
591
|
-
df =
|
|
614
|
+
df = DataFrame()
|
|
592
615
|
df["Level"] = fib_levels
|
|
593
616
|
df["Level"] = df["Level"].apply(lambda x: str(x * 100) + "%")
|
|
594
617
|
df["Price"] = levels
|