siglab-py 0.5.21__py3-none-any.whl → 0.5.23__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.
Potentially problematic release.
This version of siglab-py might be problematic. Click here for more details.
- siglab_py/tests/unit/analytic_util_tests.py +2 -1
- siglab_py/util/analytic_util.py +54 -4
- {siglab_py-0.5.21.dist-info → siglab_py-0.5.23.dist-info}/METADATA +1 -1
- {siglab_py-0.5.21.dist-info → siglab_py-0.5.23.dist-info}/RECORD +6 -6
- {siglab_py-0.5.21.dist-info → siglab_py-0.5.23.dist-info}/WHEEL +0 -0
- {siglab_py-0.5.21.dist-info → siglab_py-0.5.23.dist-info}/top_level.txt +0 -0
|
@@ -57,13 +57,14 @@ class AnalyticUtilTests(unittest.TestCase):
|
|
|
57
57
|
'ema_volume_short_periods', 'ema_volume_long_periods',
|
|
58
58
|
'max_short_periods', 'max_long_periods', 'idmax_short_periods', 'idmax_long_periods', 'min_short_periods', 'min_long_periods', 'idmin_short_periods', 'idmin_long_periods',
|
|
59
59
|
'price_swing_short_periods', 'price_swing_long_periods',
|
|
60
|
+
'higher_highs_long_periods', 'lower_lows_long_periods', 'higher_highs_short_periods', 'lower_lows_short_periods',
|
|
60
61
|
'h_l', 'h_pc', 'l_pc', 'tr', 'atr', 'atr_avg_short_periods', 'atr_avg_long_periods',
|
|
61
62
|
'hurst_exp',
|
|
62
63
|
'boillenger_upper', 'boillenger_lower', 'boillenger_channel_height', 'boillenger_upper_agg', 'boillenger_lower_agg', 'boillenger_channel_height_agg',
|
|
63
64
|
'aggressive_up', 'aggressive_up_index', 'aggressive_up_candle_height', 'aggressive_up_candle_high', 'aggressive_up_candle_low', 'aggressive_down', 'aggressive_down_index', 'aggressive_down_candle_height', 'aggressive_down_candle_high', 'aggressive_down_candle_low',
|
|
64
65
|
'fvg_low', 'fvg_high', 'fvg_gap', 'fvg_mitigated',
|
|
65
66
|
'close_delta', 'close_delta_percent', 'up', 'down',
|
|
66
|
-
'rsi', 'ema_rsi', 'rsi_max', 'rsi_idmax', 'rsi_min', 'rsi_idmin', 'rsi_trend',
|
|
67
|
+
'rsi', 'ema_rsi', 'rsi_max', 'rsi_idmax', 'rsi_min', 'rsi_idmin', 'rsi_trend', 'rsi_higher_highs', 'rsi_lower_lows', 'rsi_divergence',
|
|
67
68
|
'typical_price',
|
|
68
69
|
'money_flow', 'money_flow_positive', 'money_flow_negative', 'positive_flow_sum', 'negative_flow_sum', 'money_flow_ratio', 'mfi',
|
|
69
70
|
'macd', 'signal', 'macd_minus_signal',
|
siglab_py/util/analytic_util.py
CHANGED
|
@@ -50,7 +50,31 @@ def calculate_slope(
|
|
|
50
50
|
pd_data[f"normalized_{slope_col_name}_max"] = normalized_slope_rolling.max()
|
|
51
51
|
pd_data[f"normalized_{slope_col_name}_idmin"] = normalized_slope_rolling.apply(lambda x : x.idxmin())
|
|
52
52
|
pd_data[f"normalized_{slope_col_name}_idmax"] = normalized_slope_rolling.apply(lambda x : x.idxmax())
|
|
53
|
-
|
|
53
|
+
|
|
54
|
+
def higherhighs(series: pd.Series) -> str:
|
|
55
|
+
unique_maxima = series.dropna()[series.dropna().diff().ne(0)]
|
|
56
|
+
if len(unique_maxima) < 2:
|
|
57
|
+
return 'sideways'
|
|
58
|
+
first, last = unique_maxima.iloc[0], unique_maxima.iloc[-1]
|
|
59
|
+
if first > last:
|
|
60
|
+
return 'lower_highs'
|
|
61
|
+
elif first < last:
|
|
62
|
+
return 'higher_highs'
|
|
63
|
+
else:
|
|
64
|
+
return 'sideways'
|
|
65
|
+
|
|
66
|
+
def lowerlows(series: pd.Series) -> str:
|
|
67
|
+
unique_minima = series.dropna()[series.dropna().diff().ne(0)]
|
|
68
|
+
if len(unique_minima) < 2:
|
|
69
|
+
return 'sideways'
|
|
70
|
+
first, last = unique_minima.iloc[0], unique_minima.iloc[-1]
|
|
71
|
+
if first > last:
|
|
72
|
+
return 'lower_lows'
|
|
73
|
+
elif first < last:
|
|
74
|
+
return 'higher_lows'
|
|
75
|
+
else:
|
|
76
|
+
return 'sideways'
|
|
77
|
+
|
|
54
78
|
'''
|
|
55
79
|
compute_candles_stats will calculate typical/basic technical indicators using in many trading strategies:
|
|
56
80
|
a. Basic SMA/EMAs (And slopes)
|
|
@@ -180,6 +204,11 @@ def compute_candles_stats(
|
|
|
180
204
|
pd_candles['min_long_periods'] - pd_candles['max_long_periods'] # Down swing (negative)
|
|
181
205
|
)
|
|
182
206
|
|
|
207
|
+
pd_candles['higher_highs_long_periods'] = higherhighs(pd_candles['max_long_periods'])
|
|
208
|
+
pd_candles['lower_lows_long_periods'] = lowerlows(pd_candles['min_long_periods'])
|
|
209
|
+
pd_candles['higher_highs_short_periods'] = higherhighs(pd_candles['max_short_periods'])
|
|
210
|
+
pd_candles['lower_lows_short_periods'] = lowerlows(pd_candles['min_short_periods'])
|
|
211
|
+
|
|
183
212
|
# ATR https://medium.com/codex/detecting-ranging-and-trending-markets-with-choppiness-index-in-python-1942e6450b58
|
|
184
213
|
pd_candles.loc[:,'h_l'] = pd_candles['high'] - pd_candles['low']
|
|
185
214
|
pd_candles.loc[:,'h_pc'] = abs(pd_candles['high'] - pd_candles['close'].shift(1))
|
|
@@ -199,10 +228,10 @@ def compute_candles_stats(
|
|
|
199
228
|
Sometimes you may encounter "Exception has occurred: FloatingPointError invalid value encountered in scalar divide"
|
|
200
229
|
And for example adjusting window size from 120 to 125 will resolve the issue.
|
|
201
230
|
'''
|
|
231
|
+
if not hurst_exp_window_how_many_candles:
|
|
232
|
+
hurst_exp_window_how_many_candles = (sliding_window_how_many_candles if sliding_window_how_many_candles>=125 else 125)
|
|
202
233
|
pd_candles['hurst_exp'] = pd_candles['close'].rolling(
|
|
203
|
-
window=
|
|
204
|
-
hurst_exp_window_how_many_candles if hurst_exp_window_how_many_candles else (sliding_window_how_many_candles if sliding_window_how_many_candles>=125 else 125)
|
|
205
|
-
)
|
|
234
|
+
window=hurst_exp_window_how_many_candles
|
|
206
235
|
).apply(lambda x: compute_Hc(x, kind='price', simplified=True)[0])
|
|
207
236
|
|
|
208
237
|
|
|
@@ -395,6 +424,20 @@ def compute_candles_stats(
|
|
|
395
424
|
return 'up' if row.name > row['rsi_idmin'] and row['rsi'] >= rsi_lower_threshold else 'down'
|
|
396
425
|
|
|
397
426
|
pd_candles['rsi_trend'] = pd_candles.apply(lambda row: rsi_trend(row), axis=1)
|
|
427
|
+
|
|
428
|
+
pd_candles['rsi_higher_highs'] = higherhighs(pd_candles['rsi_max'])
|
|
429
|
+
pd_candles['rsi_lower_lows'] = lowerlows(pd_candles['rsi_min'])
|
|
430
|
+
|
|
431
|
+
def _rsi_divergence(row):
|
|
432
|
+
# Bullish Divergence: Price lower low + RSI higher low
|
|
433
|
+
if row['lower_lows_long_periods']=='lower_lows' and row['rsi_lower_lows']=='higher_lows':
|
|
434
|
+
return 'bullish_divergence'
|
|
435
|
+
# Bearish Divergence: Price higher high + RSI lower high
|
|
436
|
+
elif row['higher_highs_long_periods']=='higher_highs' and row['rsi_higher_highs']=='lower_highs':
|
|
437
|
+
return 'bearish_divergence'
|
|
438
|
+
else:
|
|
439
|
+
return 'no_divergence'
|
|
440
|
+
pd_candles['rsi_divergence'] = pd_candles.apply(_rsi_divergence, axis=1)
|
|
398
441
|
|
|
399
442
|
|
|
400
443
|
# MFI (Money Flow Index) https://randerson112358.medium.com/algorithmic-trading-strategy-using-money-flow-index-mfi-python-aa46461a5ea5
|
|
@@ -474,6 +517,13 @@ def compute_candles_stats(
|
|
|
474
517
|
(pd_candles['ema_long_slope'] > 0) & (pd_candles['ema_rsi_slope'] < 0) |
|
|
475
518
|
(pd_candles['ema_long_slope'] < 0) & (pd_candles['ema_rsi_slope'] > 0)
|
|
476
519
|
)
|
|
520
|
+
|
|
521
|
+
calculate_slope(
|
|
522
|
+
pd_data=pd_candles,
|
|
523
|
+
src_col_name='hurst_exp',
|
|
524
|
+
slope_col_name='hurst_exp_slope',
|
|
525
|
+
sliding_window_how_many_candles=hurst_exp_window_how_many_candles
|
|
526
|
+
)
|
|
477
527
|
|
|
478
528
|
|
|
479
529
|
# Fibonacci
|
|
@@ -22,18 +22,18 @@ siglab_py/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
22
22
|
siglab_py/tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
siglab_py/tests/integration/market_data_util_tests.py,sha256=p-RWIJZLyj0lAdfi4QTIeAttCm_e8mEVWFKh4OWuogU,7189
|
|
24
24
|
siglab_py/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
-
siglab_py/tests/unit/analytic_util_tests.py,sha256=
|
|
25
|
+
siglab_py/tests/unit/analytic_util_tests.py,sha256=aY6OvICgIrNz-Is4lPPlBtDBF0c8TC7NDPTwhzRJeVI,4237
|
|
26
26
|
siglab_py/tests/unit/market_data_util_tests.py,sha256=A1y83itISmMJdn6wLpfwcr4tGola8wTf1D1xbelMvgw,2026
|
|
27
27
|
siglab_py/tests/unit/trading_util_tests.py,sha256=9DZmTZlW55lPtNfTCukgDdiyBiMYv9R4mEFWJIJiTNg,3870
|
|
28
28
|
siglab_py/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
-
siglab_py/util/analytic_util.py,sha256=
|
|
29
|
+
siglab_py/util/analytic_util.py,sha256=rVP7srGSgCidhB79GXWdYjuAy3G1HCGPblV-kmHAiKg,51713
|
|
30
30
|
siglab_py/util/aws_util.py,sha256=KGmjHrr1rpnnxr33nXHNzTul4tvyyxl9p6gpwNv0Ygc,2557
|
|
31
31
|
siglab_py/util/market_data_util.py,sha256=mUXg4uaiX3b6_klgJWIEgnUQU4IUd6CwTOqKLiQWRlU,31307
|
|
32
32
|
siglab_py/util/notification_util.py,sha256=vySgHjpHgwFDLW0tHSi_AGh9JBbPc25IUgvWxmjAeT8,2658
|
|
33
33
|
siglab_py/util/retry_util.py,sha256=g-UU6pkPouWZZRZEqP99R2Z0lX5xzckYkzjwqqSDpVQ,922
|
|
34
34
|
siglab_py/util/slack_notification_util.py,sha256=G27n-adbT3Q6oaHSMvu_Nom794rrda5PprSF-zvmzkM,1912
|
|
35
35
|
siglab_py/util/trading_util.py,sha256=-TGNgJdy4HMDPgq31KQn_lRawFxuXnFU5NnLRb1XM5o,5757
|
|
36
|
-
siglab_py-0.5.
|
|
37
|
-
siglab_py-0.5.
|
|
38
|
-
siglab_py-0.5.
|
|
39
|
-
siglab_py-0.5.
|
|
36
|
+
siglab_py-0.5.23.dist-info/METADATA,sha256=PkNx6i-RLTKhh1iIaFM3SOQIgXEGg4LTGDiXoKg2i-E,829
|
|
37
|
+
siglab_py-0.5.23.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
|
38
|
+
siglab_py-0.5.23.dist-info/top_level.txt,sha256=AbD4VR9OqmMOGlMJLkAVPGQMtUPIQv0t1BF5xmcLJSk,10
|
|
39
|
+
siglab_py-0.5.23.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|