siglab-py 0.5.68__py3-none-any.whl → 0.5.70__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 +1 -1
- siglab_py/util/analytic_util.py +30 -1
- siglab_py/util/market_data_util.py +49 -2
- {siglab_py-0.5.68.dist-info → siglab_py-0.5.70.dist-info}/METADATA +1 -1
- {siglab_py-0.5.68.dist-info → siglab_py-0.5.70.dist-info}/RECORD +7 -7
- {siglab_py-0.5.68.dist-info → siglab_py-0.5.70.dist-info}/WHEEL +0 -0
- {siglab_py-0.5.68.dist-info → siglab_py-0.5.70.dist-info}/top_level.txt +0 -0
|
@@ -70,7 +70,7 @@ class AnalyticUtilTests(unittest.TestCase):
|
|
|
70
70
|
'rsi', 'rsi_bucket', 'ema_rsi', 'rsi_max', 'rsi_idmax', 'rsi_min', 'rsi_idmin', 'rsi_trend', 'rsi_trend_from_highs', 'rsi_trend_from_lows', 'rsi_divergence',
|
|
71
71
|
'typical_price',
|
|
72
72
|
'money_flow', 'money_flow_positive', 'money_flow_negative', 'positive_flow_sum', 'negative_flow_sum', 'money_flow_ratio', 'mfi', 'mfi_bucket',
|
|
73
|
-
'macd', 'signal', 'macd_minus_signal',
|
|
73
|
+
'macd', 'signal', 'macd_minus_signal', 'macd_cross', 'macd_bullish_cross_last_id', 'macd_bearish_cross_last_id', 'macd_cross_last',
|
|
74
74
|
'fib_0.618_short_periods', 'fib_0.618_long_periods',
|
|
75
75
|
'gap_close_vs_ema', 'gap_close_vs_ema_percent',
|
|
76
76
|
'close_above_or_below_ema',
|
siglab_py/util/analytic_util.py
CHANGED
|
@@ -548,7 +548,36 @@ def compute_candles_stats(
|
|
|
548
548
|
# https://www.youtube.com/watch?v=jmPCL3l08ss
|
|
549
549
|
pd_candles['macd'] = pd_candles['ema_short_periods'] - pd_candles['ema_long_periods']
|
|
550
550
|
pd_candles['signal'] = pd_candles['macd'].ewm(span=int(sliding_window_how_many_candles/slow_fast_interval_ratio), adjust=False).mean()
|
|
551
|
-
pd_candles['macd_minus_signal'] = pd_candles['macd'] - pd_candles['signal']
|
|
551
|
+
pd_candles['macd_minus_signal'] = pd_candles['macd'] - pd_candles['signal'] # MACD histogram
|
|
552
|
+
macd_cur = pd_candles['macd_minus_signal']
|
|
553
|
+
macd_prev = pd_candles['macd_minus_signal'].shift(1)
|
|
554
|
+
bullish_macd_crosses = (macd_prev < 0) & (macd_cur > 0)
|
|
555
|
+
bearish_macd_crosses = (macd_prev > 0) & (macd_cur < 0)
|
|
556
|
+
pd_candles.loc[bullish_macd_crosses, 'macd_cross'] = 1
|
|
557
|
+
pd_candles.loc[bearish_macd_crosses, 'macd_cross'] = -1
|
|
558
|
+
bullish_indices = pd.Series(pd_candles.index.where(pd_candles['macd_cross'] == 1), index=pd_candles.index).astype('Int64')
|
|
559
|
+
bearish_indices = pd.Series(pd_candles.index.where(pd_candles['macd_cross'] == -1), index=pd_candles.index).astype('Int64')
|
|
560
|
+
pd_candles['macd_bullish_cross_last_id'] = bullish_indices.rolling(window=pd_candles.shape[0], min_periods=1).max().astype('Int64')
|
|
561
|
+
pd_candles['macd_bearish_cross_last_id'] = bearish_indices.rolling(window=pd_candles.shape[0], min_periods=1).max().astype('Int64')
|
|
562
|
+
conditions = [
|
|
563
|
+
(pd_candles['macd_bullish_cross_last_id'].notna() &
|
|
564
|
+
pd_candles['macd_bearish_cross_last_id'].notna() &
|
|
565
|
+
(pd_candles['macd_bullish_cross_last_id'] > pd_candles['macd_bearish_cross_last_id'])),
|
|
566
|
+
|
|
567
|
+
(pd_candles['macd_bullish_cross_last_id'].notna() &
|
|
568
|
+
pd_candles['macd_bearish_cross_last_id'].notna() &
|
|
569
|
+
(pd_candles['macd_bearish_cross_last_id'] > pd_candles['macd_bullish_cross_last_id'])),
|
|
570
|
+
|
|
571
|
+
(pd_candles['macd_bullish_cross_last_id'].notna() &
|
|
572
|
+
pd_candles['macd_bearish_cross_last_id'].isna()),
|
|
573
|
+
|
|
574
|
+
(pd_candles['macd_bearish_cross_last_id'].notna() &
|
|
575
|
+
pd_candles['macd_bullish_cross_last_id'].isna())
|
|
576
|
+
]
|
|
577
|
+
choices = ['bullish', 'bearish', 'bullish', 'bearish']
|
|
578
|
+
pd_candles['macd_cross_last'] = np.select(conditions, choices, default=None) # type: ignore
|
|
579
|
+
pd_candles.loc[bullish_macd_crosses, 'macd_cross'] = 'bullish'
|
|
580
|
+
pd_candles.loc[bearish_macd_crosses, 'macd_cross'] = 'bearish'
|
|
552
581
|
|
|
553
582
|
if not pypy_compat:
|
|
554
583
|
calculate_slope(
|
|
@@ -426,6 +426,45 @@ class YahooExchange:
|
|
|
426
426
|
|
|
427
427
|
return exchange_candles
|
|
428
428
|
|
|
429
|
+
def aggregate_candles(
|
|
430
|
+
interval : str,
|
|
431
|
+
pd_candles : pd.DataFrame
|
|
432
|
+
) -> pd.DataFrame:
|
|
433
|
+
if interval[-1]=='m':
|
|
434
|
+
# 'm' for pandas means months!
|
|
435
|
+
interval = interval.replace('m','min')
|
|
436
|
+
pd_candles.set_index('datetime', inplace=True)
|
|
437
|
+
pd_candles_aggregated = pd_candles.resample(interval).agg({
|
|
438
|
+
'exchange' : 'first',
|
|
439
|
+
'symbol' : 'first',
|
|
440
|
+
'timestamp_ms' : 'first',
|
|
441
|
+
|
|
442
|
+
'open': 'first',
|
|
443
|
+
'high': 'max',
|
|
444
|
+
'low': 'min',
|
|
445
|
+
'close': 'last',
|
|
446
|
+
'volume': 'sum',
|
|
447
|
+
|
|
448
|
+
'datetime_utc' : 'first',
|
|
449
|
+
'year' : 'first',
|
|
450
|
+
'month' : 'first',
|
|
451
|
+
'day' : 'first',
|
|
452
|
+
'hour' : 'first',
|
|
453
|
+
'minute' : 'first',
|
|
454
|
+
'dayofweek' : 'first',
|
|
455
|
+
'week_of_month' : 'first',
|
|
456
|
+
|
|
457
|
+
'apac_trading_hr' : 'first',
|
|
458
|
+
'emea_trading_hr' : 'first',
|
|
459
|
+
'amer_trading_hr' : 'first',
|
|
460
|
+
|
|
461
|
+
'pct_chg_on_close' : 'sum',
|
|
462
|
+
|
|
463
|
+
})
|
|
464
|
+
pd_candles.reset_index(inplace=True)
|
|
465
|
+
pd_candles_aggregated.reset_index(inplace=True)
|
|
466
|
+
return pd_candles_aggregated
|
|
467
|
+
|
|
429
468
|
def fetch_historical_price(
|
|
430
469
|
exchange,
|
|
431
470
|
normalized_symbol : str,
|
|
@@ -472,7 +511,8 @@ def fetch_candles(
|
|
|
472
511
|
validation_max_gaps : int = 10,
|
|
473
512
|
validation_max_end_date_intervals : int = 1
|
|
474
513
|
) -> Dict[str, Union[pd.DataFrame, None]]:
|
|
475
|
-
|
|
514
|
+
num_intervals = int(candle_size.replace(candle_size[-1],''))
|
|
515
|
+
|
|
476
516
|
if end_ts>datetime.now().timestamp():
|
|
477
517
|
end_ts = int(datetime.now().timestamp())
|
|
478
518
|
|
|
@@ -501,6 +541,8 @@ def fetch_candles(
|
|
|
501
541
|
pd_candles = exchange_candles[symbol]
|
|
502
542
|
if not pd_candles is None:
|
|
503
543
|
fix_column_types(pd_candles) # You don't want to do this from Futubull as you'd need import Futubull from there: Circular references
|
|
544
|
+
if num_intervals!=1:
|
|
545
|
+
exchange_candles[symbol] = aggregate_candles(candle_size, pd_candles)
|
|
504
546
|
return exchange_candles
|
|
505
547
|
elif issubclass(exchange.__class__, CcxtExchange):
|
|
506
548
|
return _fetch_candles_ccxt(
|
|
@@ -547,6 +589,8 @@ def _fetch_candles_ccxt(
|
|
|
547
589
|
|
|
548
590
|
rsp = {}
|
|
549
591
|
|
|
592
|
+
num_intervals = int(candle_size.replace(candle_size[-1],''))
|
|
593
|
+
|
|
550
594
|
exchange.load_markets()
|
|
551
595
|
|
|
552
596
|
num_tickers = len(normalized_symbols)
|
|
@@ -563,7 +607,7 @@ def _fetch_candles_ccxt(
|
|
|
563
607
|
|
|
564
608
|
def _calc_increment(candle_size):
|
|
565
609
|
increment = 1
|
|
566
|
-
num_intervals = int(candle_size[
|
|
610
|
+
num_intervals = int(candle_size.replace(candle_size[-1],''))
|
|
567
611
|
interval_type = candle_size[-1]
|
|
568
612
|
if interval_type == "m":
|
|
569
613
|
increment = 60
|
|
@@ -609,6 +653,9 @@ def _fetch_candles_ccxt(
|
|
|
609
653
|
fix_column_types(pd_all_candles)
|
|
610
654
|
pd_all_candles['pct_chg_on_close'] = pd_all_candles['close'].pct_change()
|
|
611
655
|
|
|
656
|
+
if num_intervals!=1:
|
|
657
|
+
pd_all_candles = aggregate_candles(candle_size, pd_all_candles)
|
|
658
|
+
|
|
612
659
|
rsp[ticker] = pd_all_candles
|
|
613
660
|
|
|
614
661
|
i+=1
|
|
@@ -22,20 +22,20 @@ 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=wbasww0ZN9Kb-6e8V_q4o4hpstzVBvQ6Bop_0HZQUtw,5926
|
|
26
26
|
siglab_py/tests/unit/market_data_util_tests.py,sha256=A1y83itISmMJdn6wLpfwcr4tGola8wTf1D1xbelMvgw,2026
|
|
27
27
|
siglab_py/tests/unit/simple_math_tests.py,sha256=rWqq93W4Vlqmu0UeZCmSOfLirr0gPh2ASVIZ8O77qXY,9653
|
|
28
28
|
siglab_py/tests/unit/trading_util_tests.py,sha256=LiflZrduWXyLMbpSFQCaydA7jdJx3vFR-3KuKRRGhjQ,2927
|
|
29
29
|
siglab_py/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
|
-
siglab_py/util/analytic_util.py,sha256=
|
|
30
|
+
siglab_py/util/analytic_util.py,sha256=ywp-VI8UlmoYVej2SaJMrOyheFwyh9KVjsnfw55dpMU,63785
|
|
31
31
|
siglab_py/util/aws_util.py,sha256=KGmjHrr1rpnnxr33nXHNzTul4tvyyxl9p6gpwNv0Ygc,2557
|
|
32
|
-
siglab_py/util/market_data_util.py,sha256=
|
|
32
|
+
siglab_py/util/market_data_util.py,sha256=o0OAqv5ZLEvtvg2WvkUu7ZIs7Qa-ARc1JNaFJgDuC0o,32800
|
|
33
33
|
siglab_py/util/notification_util.py,sha256=tNZMUkkjz4q1CKqcQq62oEmZgHgNIwz2Iw9J22V22Zw,2668
|
|
34
34
|
siglab_py/util/retry_util.py,sha256=g-UU6pkPouWZZRZEqP99R2Z0lX5xzckYkzjwqqSDpVQ,922
|
|
35
35
|
siglab_py/util/simple_math.py,sha256=F7vGj0O2Y9EAGcMFR6SN1tTjBWO_a7YZeiTzk3eHaVI,8518
|
|
36
36
|
siglab_py/util/slack_notification_util.py,sha256=G27n-adbT3Q6oaHSMvu_Nom794rrda5PprSF-zvmzkM,1912
|
|
37
37
|
siglab_py/util/trading_util.py,sha256=dlIOzoMGnddLSFODcJ61EBH1Aeruq4IT2MsxIdFkV9I,5252
|
|
38
|
-
siglab_py-0.5.
|
|
39
|
-
siglab_py-0.5.
|
|
40
|
-
siglab_py-0.5.
|
|
41
|
-
siglab_py-0.5.
|
|
38
|
+
siglab_py-0.5.70.dist-info/METADATA,sha256=R2s8me8ZPbvgMENhVN-niWA2JWcXWSzbPXFoaign4X4,829
|
|
39
|
+
siglab_py-0.5.70.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
|
40
|
+
siglab_py-0.5.70.dist-info/top_level.txt,sha256=AbD4VR9OqmMOGlMJLkAVPGQMtUPIQv0t1BF5xmcLJSk,10
|
|
41
|
+
siglab_py-0.5.70.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|