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.

@@ -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',
@@ -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[0])
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: siglab_py
3
- Version: 0.5.68
3
+ Version: 0.5.70
4
4
  Summary: Market data fetches, TA calculations and generic order gateway.
5
5
  Author: r0bbarh00d
6
6
  Author-email: r0bbarh00d <r0bbarh00d@gmail.com>
@@ -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=90tC5wjaYtoma3DGwkQF7akAKkZ0R1LGDL8Jwna2TFg,5834
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=0PcWMP8ZNYzDBMvFViwGetAbUZIwCQq3iX2iJYKOxyI,61859
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=mUXg4uaiX3b6_klgJWIEgnUQU4IUd6CwTOqKLiQWRlU,31307
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.68.dist-info/METADATA,sha256=nRNrR6x8eARAQnZjwP2tT9ub_CGicL3pAy1z67FRm64,829
39
- siglab_py-0.5.68.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
40
- siglab_py-0.5.68.dist-info/top_level.txt,sha256=AbD4VR9OqmMOGlMJLkAVPGQMtUPIQv0t1BF5xmcLJSk,10
41
- siglab_py-0.5.68.dist-info/RECORD,,
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,,