siglab-py 0.3.0__tar.gz → 0.3.2__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.

Potentially problematic release.


This version of siglab-py might be problematic. Click here for more details.

Files changed (42) hide show
  1. {siglab_py-0.3.0 → siglab_py-0.3.2}/PKG-INFO +1 -1
  2. {siglab_py-0.3.0 → siglab_py-0.3.2}/pyproject.toml +1 -1
  3. {siglab_py-0.3.0 → siglab_py-0.3.2}/setup.cfg +1 -1
  4. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/ordergateway/gateway.py +11 -10
  5. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/tests/unit/analytic_util_tests.py +1 -1
  6. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/tests/unit/trading_util_tests.py +6 -6
  7. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/util/analytic_util.py +16 -6
  8. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/util/trading_util.py +7 -7
  9. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py.egg-info/PKG-INFO +1 -1
  10. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/__init__.py +0 -0
  11. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/constants.py +0 -0
  12. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/exchanges/__init__.py +0 -0
  13. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/exchanges/any_exchange.py +0 -0
  14. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/exchanges/futubull.py +0 -0
  15. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/market_data_providers/__init__.py +0 -0
  16. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/market_data_providers/aggregated_orderbook_provider.py +0 -0
  17. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/market_data_providers/candles_provider.py +0 -0
  18. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/market_data_providers/candles_ta_provider.py +0 -0
  19. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/market_data_providers/ccxt_candles_ta_to_csv.py +0 -0
  20. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/market_data_providers/deribit_options_expiry_provider.py +0 -0
  21. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/market_data_providers/futu_candles_ta_to_csv.py +0 -0
  22. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/market_data_providers/orderbooks_provider.py +0 -0
  23. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/market_data_providers/test_provider.py +0 -0
  24. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/ordergateway/__init__.py +0 -0
  25. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/ordergateway/client.py +0 -0
  26. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/ordergateway/encrypt_keys_util.py +0 -0
  27. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/ordergateway/test_ordergateway.py +0 -0
  28. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/tests/__init__.py +0 -0
  29. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/tests/integration/__init__.py +0 -0
  30. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/tests/integration/market_data_util_tests.py +0 -0
  31. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/tests/unit/__init__.py +0 -0
  32. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/tests/unit/market_data_util_tests.py +0 -0
  33. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/util/__init__.py +0 -0
  34. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/util/aws_util.py +0 -0
  35. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/util/market_data_util.py +0 -0
  36. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/util/notification_util.py +0 -0
  37. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/util/retry_util.py +0 -0
  38. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py/util/slack_notification_util.py +0 -0
  39. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py.egg-info/SOURCES.txt +0 -0
  40. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py.egg-info/dependency_links.txt +0 -0
  41. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py.egg-info/requires.txt +0 -0
  42. {siglab_py-0.3.0 → siglab_py-0.3.2}/siglab_py.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: siglab_py
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Market data fetches, TA calculations and generic order gateway.
5
5
  Author: r0bbarh00d
6
6
  Author-email: r0bbarh00d <r0bbarh00d@gmail.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "siglab_py"
7
- version = "0.3.0"
7
+ version = "0.3.2"
8
8
  description = "Market data fetches, TA calculations and generic order gateway."
9
9
  authors = [{name = "r0bbarh00d", email = "r0bbarh00d@gmail.com"}]
10
10
  license = {text = "MIT"}
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = siglab_py
3
- version = 0.3.0
3
+ version = 0.3.2
4
4
  description = Market data fetches, TA calculations and generic order gateway.
5
5
  author = r0bbarh00d
6
6
  author_email = r0bbarh00d@gmail.com
@@ -502,14 +502,15 @@ async def execute_one_position(
502
502
  slices : List[Order] = position.to_slices()
503
503
 
504
504
  # Residual handling in last slice
505
- last_slice = slices[-1]
506
- last_slice_rounded_amount_in_base_ccy = exchange.amount_to_precision(position.ticker, last_slice.amount/multiplier) # After divided by multiplier, rounded_slice_amount_in_base_ccy in number of contracts actually (Not in base ccy).
507
- last_slice_rounded_amount_in_base_ccy = float(last_slice_rounded_amount_in_base_ccy) if last_slice_rounded_amount_in_base_ccy else 0
508
- if last_slice_rounded_amount_in_base_ccy<=min_amount:
509
- slices.pop()
510
- slices[-1].amount += last_slice.amount
505
+ if len(slices)>1:
506
+ last_slice = slices[-1]
507
+ last_slice_rounded_amount_in_base_ccy = exchange.amount_to_precision(position.ticker, last_slice.amount/multiplier) # After divided by multiplier, rounded_slice_amount_in_base_ccy in number of contracts actually (Not in base ccy).
508
+ last_slice_rounded_amount_in_base_ccy = float(last_slice_rounded_amount_in_base_ccy) if last_slice_rounded_amount_in_base_ccy else 0
509
+ if last_slice_rounded_amount_in_base_ccy<=min_amount:
510
+ slices.pop()
511
+ slices[-1].amount += last_slice.amount
511
512
 
512
- log(f"{position.ticker} Last slice residual smaller than min_amount. Amount is added to prev slice instead. last_slice_amount: {last_slice.amount/multiplier}, last_slice_rounded_amount: {last_slice_rounded_amount_in_base_ccy}")
513
+ log(f"{position.ticker} Last slice residual smaller than min_amount. Amount is added to prev slice instead. last_slice_amount: {last_slice.amount/multiplier}, last_slice_rounded_amount: {last_slice_rounded_amount_in_base_ccy}")
513
514
 
514
515
  i = 0
515
516
  for slice in slices:
@@ -796,10 +797,10 @@ async def execute_one_position(
796
797
  dispatch_notification(title=f"{param['current_filename']} {param['gateway_id']} execute_one_position done. {position.ticker} {position.side} {position.amount}", message=notification_summary, footer=param['notification']['footer'], params=notification_params, log_level=LogLevel.CRITICAL, logger=logger)
797
798
 
798
799
  except Exception as position_execution_err:
799
- err_msg = f"Execution failed: {position_execution_err} {str(sys.exc_info()[0])} {str(sys.exc_info()[1])} {traceback.format_exc()}"
800
- log(f"Execution failed: {err_msg}")
800
+ err_msg = f"{position.ticker} Execution failed: {position_execution_err} {str(sys.exc_info()[0])} {str(sys.exc_info()[1])} {traceback.format_exc()}"
801
+ log(err_msg)
801
802
 
802
- dispatch_notification(title=f"{param['current_filename']} {param['gateway_id']} execute_one_position failed!!! {position.ticker} {position.side} {position.amount}", message=position.get_executions(), footer=param['notification']['footer'], params=notification_params, log_level=LogLevel.ERROR, logger=logger) # type: ignore
803
+ dispatch_notification(title=f"{param['current_filename']} {param['gateway_id']} {position.ticker} execute_one_position failed!!!", message=err_msg, footer=param['notification']['footer'], params=notification_params, log_level=LogLevel.ERROR, logger=logger) # type: ignore
803
804
 
804
805
  position.done = False
805
806
  position.execution_err = err_msg
@@ -51,7 +51,7 @@ class AnalyticUtilTests(unittest.TestCase):
51
51
  'sma_short_periods', 'sma_long_periods', 'ema_short_periods', 'ema_long_periods', 'ema_close',
52
52
  'std', 'std_percent',
53
53
  'candle_height_percent', 'candle_height_percent_rounded',
54
- 'log_return', 'interval_historical_volatility',
54
+ 'log_return', 'interval_hist_vol', 'annualized_hist_vol',
55
55
  'chop_against_ema',
56
56
  'ema_volume_short_periods', 'ema_volume_long_periods',
57
57
  'max_short_periods', 'max_long_periods', 'idmax_short_periods', 'idmax_long_periods', 'min_short_periods', 'min_long_periods', 'idmin_short_periods', 'idmin_long_periods',
@@ -12,7 +12,7 @@ class TradingUtilTests(unittest.TestCase):
12
12
  tp_min_percent : float = 1.5
13
13
  tp_max_percent : float = 2.5
14
14
  sl_percent_trailing : float = 50 # Trailing stop loss in percent
15
- default_effective_sl_percent_trailing : float = 50
15
+ default_effective_tp_trailing_percent : float = 50
16
16
 
17
17
  pnl_percent_notional : float = 0.5 # Trade's current pnl in percent.
18
18
 
@@ -21,7 +21,7 @@ class TradingUtilTests(unittest.TestCase):
21
21
  tp_max_percent = tp_max_percent,
22
22
  sl_percent_trailing = sl_percent_trailing,
23
23
  pnl_percent_notional = pnl_percent_notional,
24
- default_effective_sl_percent_trailing = default_effective_sl_percent_trailing
24
+ default_effective_tp_trailing_percent = default_effective_tp_trailing_percent
25
25
  )
26
26
  assert(effective_tp_trailing_percent==50) # Generous trailing SL when trading starting out and pnl small.
27
27
 
@@ -29,7 +29,7 @@ class TradingUtilTests(unittest.TestCase):
29
29
  tp_min_percent : float = 1.5
30
30
  tp_max_percent : float = 2.5
31
31
  sl_percent_trailing : float = 50 # Trailing stop loss in percent
32
- default_effective_sl_percent_trailing : float = 50
32
+ default_effective_tp_trailing_percent : float = 50
33
33
 
34
34
  pnl_percent_notional : float = 2 # Trade's current pnl in percent.
35
35
 
@@ -38,7 +38,7 @@ class TradingUtilTests(unittest.TestCase):
38
38
  tp_max_percent = tp_max_percent,
39
39
  sl_percent_trailing = sl_percent_trailing,
40
40
  pnl_percent_notional = pnl_percent_notional,
41
- default_effective_sl_percent_trailing = default_effective_sl_percent_trailing
41
+ default_effective_tp_trailing_percent = default_effective_tp_trailing_percent
42
42
  )
43
43
  assert(effective_tp_trailing_percent==25) # Intermediate trailing SL
44
44
 
@@ -46,7 +46,7 @@ class TradingUtilTests(unittest.TestCase):
46
46
  tp_min_percent : float = 1.5
47
47
  tp_max_percent : float = 2.5
48
48
  sl_percent_trailing : float = 50 # Trailing stop loss in percent
49
- default_effective_sl_percent_trailing : float = 50
49
+ default_effective_tp_trailing_percent : float = 50
50
50
 
51
51
  pnl_percent_notional : float = 2.5 # Trade's current pnl in percent.
52
52
 
@@ -55,6 +55,6 @@ class TradingUtilTests(unittest.TestCase):
55
55
  tp_max_percent = tp_max_percent,
56
56
  sl_percent_trailing = sl_percent_trailing,
57
57
  pnl_percent_notional = pnl_percent_notional,
58
- default_effective_sl_percent_trailing = default_effective_sl_percent_trailing
58
+ default_effective_tp_trailing_percent = default_effective_tp_trailing_percent
59
59
  )
60
60
  assert(effective_tp_trailing_percent==0) # Most tight trailing SL
@@ -98,10 +98,13 @@ def compute_candles_stats(
98
98
  pd_candles['ema_short_periods'] = close_short_periods_ewm.mean()
99
99
  pd_candles['ema_long_periods'] = close_long_periods_ewm.mean()
100
100
  pd_candles['ema_close'] = pd_candles['ema_long_periods'] # Alias, shorter name
101
- pd_candles['std'] = pd_candles['close'].rolling(window=sliding_window_how_many_candles).std()
101
+ pd_candles['std'] = close_long_periods_rolling.std()
102
102
 
103
103
  pd_candles['std_percent'] = pd_candles['std'] / pd_candles['ema_close'] * 100
104
104
 
105
+ pd_candles['normalized_close_short'] = (pd_candles['close'] - pd_candles['sma_short_periods']) / close_short_periods_rolling.std()
106
+ pd_candles['normalized_close_long'] = (pd_candles['close'] - pd_candles['sma_long_periods']) / pd_candles['std']
107
+
105
108
  pd_candles['candle_height_percent'] = pd_candles['candle_height'] / pd_candles['ema_close'] * 100
106
109
  pd_candles['candle_height_percent_rounded'] = pd_candles['candle_height_percent'].round().astype('Int64')
107
110
 
@@ -118,7 +121,14 @@ def compute_candles_stats(
118
121
  )
119
122
  '''
120
123
  pd_candles['log_return'] = np.log(pd_candles['close'] / pd_candles['close'].shift(1))
121
- pd_candles['interval_historical_volatility'] = pd_candles['log_return'].rolling(window=sliding_window_how_many_candles).std()
124
+ pd_candles['interval_hist_vol'] = pd_candles['log_return'].rolling(window=sliding_window_how_many_candles).std()
125
+
126
+ time_gap_sec = int(pd_candles['timestamp_ms'].iloc[1] - pd_candles['timestamp_ms'].iloc[0])/1000
127
+ seconds_in_year = 365 * 24 * 60 * 60
128
+ candles_per_year = seconds_in_year / time_gap_sec
129
+ annualization_factor = np.sqrt(candles_per_year)
130
+ pd_candles['annualized_hist_vol'] = pd_candles['interval_hist_vol'] * annualization_factor
131
+
122
132
 
123
133
  pd_candles['chop_against_ema'] = (
124
134
  (~pd_candles['is_green'] & (pd_candles['close'] > pd_candles['ema_close'])) | # Case 1: Green candle and close > EMA
@@ -361,12 +371,12 @@ def compute_candles_stats(
361
371
  import statsmodels.api as sm # in-compatible with pypy
362
372
 
363
373
  # Slopes
364
- X = sm.add_constant(range(len(pd_candles['close'])))
365
- rolling_slope = pd_candles['close'].rolling(window=int(sliding_window_how_many_candles/slow_fast_interval_ratio)).apply(lambda x: sm.OLS(x, X[:len(x)]).fit().params[1], raw=False)
374
+ X = sm.add_constant(range(len(pd_candles['normalized_close_short'])))
375
+ rolling_slope = pd_candles['normalized_close_short'].rolling(window=int(sliding_window_how_many_candles/slow_fast_interval_ratio)).apply(lambda x: sm.OLS(x, X[:len(x)]).fit().params[1], raw=False)
366
376
  pd_candles['close_short_slope'] = rolling_slope
367
377
 
368
- X = sm.add_constant(range(len(pd_candles['close'])))
369
- rolling_slope = pd_candles['close'].rolling(window=sliding_window_how_many_candles).apply(lambda x: sm.OLS(x, X[:len(x)]).fit().params[1], raw=False)
378
+ X = sm.add_constant(range(len(pd_candles['normalized_close_long'])))
379
+ rolling_slope = pd_candles['normalized_close_long'].rolling(window=sliding_window_how_many_candles).apply(lambda x: sm.OLS(x, X[:len(x)]).fit().params[1], raw=False)
370
380
  pd_candles['close_long_slope'] = rolling_slope
371
381
 
372
382
  X = sm.add_constant(range(len(pd_candles['ema_short_periods'])))
@@ -11,11 +11,11 @@ Examples,
11
11
  min TP = 1.5% <-- min TP
12
12
  max TP = 2.5% <-- max TP
13
13
 
14
- slope = (0-50)/(2.5-1.5) = -50
14
+ slope = (0-50)/(2.5-1.5) = -50/+1 = -50
15
15
  effective_tp_trailing_percent = slope * (pnl_percent_notional - 1.5%) + sl_percent_trailing
16
16
 
17
- Case 1. pnl_percent_notional = 0.5% (Trade starting off, only +50bps pnl. i.e. min TP)
18
- effective_tp_trailing_percent = slope * (pnl_percent_notional - 0.5%) + sl_percent_trailing
17
+ Case 1. pnl_percent_notional = 1.5% (Trade starting off, only +50bps pnl. i.e. min TP)
18
+ effective_tp_trailing_percent = slope * (pnl_percent_notional - 1.5%) + sl_percent_trailing
19
19
  = -50 * (1.5-1.5) + 50%
20
20
  = 0 + 50
21
21
  = 50% (Most loose)
@@ -55,12 +55,12 @@ def calc_eff_trailing_sl(
55
55
  tp_max_percent : float,
56
56
  sl_percent_trailing : float,
57
57
  pnl_percent_notional : float,
58
- default_effective_sl_percent_trailing : float = 50
58
+ default_effective_tp_trailing_percent : float = 50
59
59
  ) -> float:
60
60
  slope = (0 - sl_percent_trailing) / (tp_max_percent - tp_min_percent)
61
- effective_sl_percent_trailing = (
61
+ effective_tp_trailing_percent = (
62
62
  slope * (pnl_percent_notional - tp_min_percent) + sl_percent_trailing
63
63
  if pnl_percent_notional>tp_min_percent
64
- else default_effective_sl_percent_trailing
64
+ else default_effective_tp_trailing_percent
65
65
  )
66
- return effective_sl_percent_trailing
66
+ return effective_tp_trailing_percent
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: siglab-py
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Market data fetches, TA calculations and generic order gateway.
5
5
  Author: r0bbarh00d
6
6
  Author-email: r0bbarh00d <r0bbarh00d@gmail.com>