siglab-py 0.2.7__tar.gz → 0.2.9__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 (40) hide show
  1. {siglab_py-0.2.7 → siglab_py-0.2.9}/PKG-INFO +1 -1
  2. {siglab_py-0.2.7 → siglab_py-0.2.9}/pyproject.toml +1 -1
  3. {siglab_py-0.2.7 → siglab_py-0.2.9}/setup.cfg +1 -1
  4. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/ordergateway/gateway.py +28 -10
  5. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/ordergateway/test_ordergateway.py +1 -2
  6. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/util/notification_util.py +6 -2
  7. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/util/slack_notification_util.py +13 -22
  8. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py.egg-info/PKG-INFO +1 -1
  9. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/__init__.py +0 -0
  10. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/constants.py +0 -0
  11. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/exchanges/__init__.py +0 -0
  12. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/exchanges/any_exchange.py +0 -0
  13. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/exchanges/futubull.py +0 -0
  14. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/market_data_providers/__init__.py +0 -0
  15. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/market_data_providers/aggregated_orderbook_provider.py +0 -0
  16. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/market_data_providers/candles_provider.py +0 -0
  17. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/market_data_providers/candles_ta_provider.py +0 -0
  18. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/market_data_providers/ccxt_candles_ta_to_csv.py +0 -0
  19. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/market_data_providers/deribit_options_expiry_provider.py +0 -0
  20. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/market_data_providers/futu_candles_ta_to_csv.py +0 -0
  21. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/market_data_providers/orderbooks_provider.py +0 -0
  22. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/market_data_providers/test_provider.py +0 -0
  23. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/ordergateway/__init__.py +0 -0
  24. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/ordergateway/client.py +0 -0
  25. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/ordergateway/encrypt_keys_util.py +0 -0
  26. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/tests/__init__.py +0 -0
  27. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/tests/integration/__init__.py +0 -0
  28. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/tests/integration/market_data_util_tests.py +0 -0
  29. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/tests/unit/__init__.py +0 -0
  30. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/tests/unit/analytic_util_tests.py +0 -0
  31. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/tests/unit/market_data_util_tests.py +0 -0
  32. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/util/__init__.py +0 -0
  33. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/util/analytic_util.py +0 -0
  34. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/util/aws_util.py +0 -0
  35. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/util/market_data_util.py +0 -0
  36. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py/util/retry_util.py +0 -0
  37. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py.egg-info/SOURCES.txt +0 -0
  38. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py.egg-info/dependency_links.txt +0 -0
  39. {siglab_py-0.2.7 → siglab_py-0.2.9}/siglab_py.egg-info/requires.txt +0 -0
  40. {siglab_py-0.2.7 → siglab_py-0.2.9}/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.2.7
3
+ Version: 0.2.9
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.2.7"
7
+ version = "0.2.9"
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.2.7
3
+ version = 0.2.9
4
4
  description = Market data fetches, TA calculations and generic order gateway.
5
5
  author = r0bbarh00d
6
6
  author_email = r0bbarh00d@gmail.com
@@ -25,8 +25,10 @@ import ccxt.pro as ccxtpro
25
25
 
26
26
  from siglab_py.exchanges.any_exchange import AnyExchange
27
27
  from siglab_py.ordergateway.client import Order, DivisiblePosition
28
- from siglab_py.util import notification_util
29
28
  from siglab_py.constants import LogLevel # type: ignore
29
+ from util.notification_util import dispatch_notification
30
+
31
+ current_filename = os.path.basename(__file__)
30
32
 
31
33
  '''
32
34
  Usage:
@@ -200,6 +202,8 @@ param : Dict = {
200
202
  "loop_freq_ms" : 500, # reduce this if you need trade faster
201
203
  "loops_random_delay_multiplier" : 1, # Add randomness to time between slices are sent off. Set to 1 if no random delay needed.
202
204
 
205
+ 'current_filename' : current_filename,
206
+
203
207
  'notification' : {
204
208
  'footer' : None,
205
209
 
@@ -327,7 +331,8 @@ def parse_args():
327
331
  param['notification']['slack']['info']['webhook_url'] = args.slack_info_url
328
332
  param['notification']['slack']['critical']['webhook_url'] = args.slack_critial_url
329
333
  param['notification']['slack']['alert']['webhook_url'] = args.slack_alert_url
330
- param['notification']['footer'] = f"From gateway {param['gateway_id']}"
334
+
335
+ param['notification']['footer'] = f"From {param['current_filename']} {param['gateway_id']}"
331
336
 
332
337
  def init_redis_client() -> StrictRedis:
333
338
  redis_client : StrictRedis = StrictRedis(
@@ -451,7 +456,7 @@ async def watch_orders_task(
451
456
  order_id = order_update['id']
452
457
  executions[order_id] = order_update
453
458
 
454
- log(f"order updates: {order_updates}", log_level=LogLevel.INFO)
459
+ log(f"order updates: {json.dumps(order_updates, indent=4)}", log_level=LogLevel.INFO)
455
460
  except Exception as loop_err:
456
461
  print(f"watch_orders_task error: {loop_err}")
457
462
 
@@ -637,7 +642,7 @@ async def execute_one_position(
637
642
  position.append_execution(order_id, order_update)
638
643
 
639
644
  if remaining_amount <= 0:
640
- log(f"Limit order fully filled: {order_id}", log_level=LogLevel.INFO)
645
+ log(f"Limit order fully filled: {order_id}, order_update: {json.dumps(order_update, indent=4)}", log_level=LogLevel.INFO)
641
646
  break
642
647
 
643
648
  loops_random_delay_multiplier : int = random.randint(1, param['loops_random_delay_multiplier']) if param['loops_random_delay_multiplier']!=1 else 1
@@ -653,6 +658,9 @@ async def execute_one_position(
653
658
  filled_amount = order_update['filled']
654
659
  remaining_amount = order_update['remaining']
655
660
  order_update['multiplier'] = multiplier
661
+
662
+ log(f"Final order_update before cancel+resend: {json.dumps(order_update, indent=4)}", log_level=LogLevel.INFO)
663
+
656
664
  position.append_execution(order_id, order_update)
657
665
 
658
666
  if order_status!='closed':
@@ -717,6 +725,11 @@ async def execute_one_position(
717
725
  i += 1
718
726
 
719
727
  position.patch_executions()
728
+
729
+ log(f"Dispatched slices:")
730
+ for dispatched_slice in position.dispatched_slices:
731
+ log(f"{json.dumps(dispatched_slice.to_dict(), indent=4)}")
732
+
720
733
  position.filled_amount = position.get_filled_amount()
721
734
  position.average_cost = position.get_average_cost()
722
735
  position.fees = position.get_fees()
@@ -734,14 +747,19 @@ async def execute_one_position(
734
747
  position.done = True
735
748
 
736
749
  log(f"Executions:")
737
- log(f"{json.dumps(position.get_executions(), indent=4)}")
750
+ log(f"{json.dumps(position.to_dict(), indent=4)}")
738
751
 
739
- notification_util.dispatch_notification(title=f"{param['gateway_id']} execute_one_position {position.ticker} {position.side} {position.amount}", message=position.get_executions(), footer=param['notification']['footer'], params=notification_params, log_level=LogLevel.CRITICAL)
752
+ dispatch_notification(title=f"{param['current_filename']} {param['gateway_id']} execute_one_position done. {position.ticker} {position.side} {position.amount}", message=position.get_executions(), footer=param['notification']['footer'], params=notification_params, log_level=LogLevel.CRITICAL)
740
753
 
741
754
  except Exception as position_execution_err:
742
- position.done = False
743
- position.execution_err = f"Execution failed: {position_execution_err} {str(sys.exc_info()[0])} {str(sys.exc_info()[1])} {traceback.format_exc()}"
755
+ err_msg = f"Execution failed: {position_execution_err} {str(sys.exc_info()[0])} {str(sys.exc_info()[1])} {traceback.format_exc()}"
756
+ log(f"Execution failed: {err_msg}")
757
+
758
+ 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) # type: ignore
744
759
 
760
+ position.done = False
761
+ position.execution_err = err_msg
762
+
745
763
  async def work(
746
764
  param : Dict,
747
765
  exchange : AnyExchange,
@@ -800,7 +818,7 @@ async def work(
800
818
 
801
819
  i = 0
802
820
  for position in positions:
803
- log(f"{i} {position.ticker}, {position.side} # executions: {len(position.get_executions())}, filled_amount: {position.filled_amount}, average_cost: {position.average_cost}, pos: {position.pos}, order_dispatch_elapsed_ms: {order_dispatch_elapsed_ms}")
821
+ log(f"{i} {position.ticker}, {position.side} # executions: {len(position.get_executions())}, filled_amount: {position.filled_amount}, average_cost: {position.average_cost}, pos: {position.pos}, done: {position.done}, error: {position.execution_err}, order_dispatch_elapsed_ms: {order_dispatch_elapsed_ms}")
804
822
  i += 1
805
823
 
806
824
  start = time.time()
@@ -880,7 +898,7 @@ async def main():
880
898
  # Once exchange instantiated, try fetch_balance to confirm connectivity and test credentials.
881
899
  balances = await exchange.fetch_balance() # type: ignore
882
900
  log(f"{param['gateway_id']}: account balances {balances}")
883
- notification_util.dispatch_notification(title=f"{param['gateway_id']} started", message=balances, footer=param['notification']['footer'], params=notification_params, log_level=LogLevel.CRITICAL)
901
+ dispatch_notification(title=f"{param['current_filename']} {param['gateway_id']} started", message=balances, footer=param['notification']['footer'], params=notification_params, log_level=LogLevel.CRITICAL)
884
902
 
885
903
  await work(param=param, exchange=exchange, redis_client=redis_client, notification_params=notification_params)
886
904
 
@@ -6,7 +6,6 @@ from typing import Any, Dict, List, Union
6
6
  import logging
7
7
  import json
8
8
  from redis import StrictRedis
9
- from sympy import false
10
9
 
11
10
  from ordergateway.client import DivisiblePosition, execute_positions
12
11
  from constants import JSON_SERIALIZABLE_TYPES
@@ -96,7 +95,7 @@ if __name__ == '__main__':
96
95
  side = 'sell',
97
96
  amount = 0.00100,
98
97
  leg_room_bps = 5,
99
- reduce_only=False,
98
+ reduce_only=True,
100
99
  order_type = 'limit',
101
100
  slices=1,
102
101
  wait_fill_threshold_ms=60000,
@@ -1,10 +1,11 @@
1
1
  import json
2
2
  from typing import Any, Dict, Union
3
+ from datetime import datetime, timezone
3
4
  import pandas as pd
4
5
  import numpy as np
5
6
  from tabulate import tabulate
6
7
 
7
- from siglab_py.util import slack_notification_util
8
+ from util.slack_notification_util import slack_dispatch_notification
8
9
 
9
10
  from siglab_py.constants import LogLevel
10
11
 
@@ -22,7 +23,10 @@ def dispatch_notification(
22
23
  else:
23
24
  _message = message
24
25
 
25
- slack_notification_util.slack_dispatch_notification(title, _message, footer, params, log_level)
26
+ utc_time = datetime.now(timezone.utc)
27
+ footer = f"UTC {utc_time} {footer}"
28
+
29
+ slack_dispatch_notification(title, _message, footer, params, log_level)
26
30
 
27
31
  if __name__ == '__main__':
28
32
  params : Dict[str, Any] = {
@@ -17,11 +17,11 @@ def slack_dispatch_notification(
17
17
  ):
18
18
  slack_params = params['slack']
19
19
 
20
- if log_level==LogLevel.INFO or log_level==LogLevel.DEBUG:
20
+ if log_level.value==LogLevel.INFO.value or log_level.value==LogLevel.DEBUG.value:
21
21
  webhook_url = slack_params['info']['webhook_url']
22
- elif log_level==LogLevel.CRITICAL:
22
+ elif log_level.value==LogLevel.CRITICAL.value:
23
23
  webhook_url = slack_params['critical']['webhook_url']
24
- elif log_level==LogLevel.ERROR:
24
+ elif log_level.value==LogLevel.ERROR.value:
25
25
  webhook_url = slack_params['alert']['webhook_url']
26
26
  else:
27
27
  webhook_url = slack_params['info']['webhook_url']
@@ -29,36 +29,27 @@ def slack_dispatch_notification(
29
29
  if not webhook_url:
30
30
  return
31
31
 
32
- slack_data = {
33
- "username": "NotificationBot",
32
+ data = {
33
+ "username": "siglab_py",
34
34
  "type": "section",
35
35
  "blocks": [
36
36
  {
37
37
  "type": "header",
38
- "text": {
39
- "type": "plain_text",
40
- "text": f"{title}"
41
- }
38
+ "text": { "type": "plain_text", "text": f"{title}" }
42
39
  },
43
40
  {
44
41
  "type": "section",
45
- "text": {
46
- "type": "mrkdwn",
47
- "text": message
48
- }
42
+ "text": { "type": "mrkdwn", "text": message }
49
43
  },
50
44
  {
51
45
  "type": "section",
52
- "text": {
53
- "type": "plain_text",
54
- "text": footer
55
- }
46
+ "text": { "type": "plain_text", "text": footer }
56
47
  }
57
48
  ]
58
49
  }
59
50
 
60
- byte_length = str(sys.getsizeof(slack_data, 2000))
61
- headers = {'Content-Type': "application/json", 'Content-Length': byte_length}
62
- response = requests.post(webhook_url, data=json.dumps(slack_data), headers=headers)
63
- if response.status_code != 200:
64
- raise Exception(response.status_code, response.text)
51
+ byte_size = str(sys.getsizeof(data, 2000))
52
+ req_headers = { 'Content-Length': byte_size, 'Content-Type': "application/json"}
53
+ rsp = requests.post(webhook_url, headers=req_headers, data=json.dumps(data))
54
+ if rsp.status_code != 200:
55
+ raise Exception(rsp.status_code, rsp.text)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: siglab-py
3
- Version: 0.2.7
3
+ Version: 0.2.9
4
4
  Summary: Market data fetches, TA calculations and generic order gateway.
5
5
  Author: r0bbarh00d
6
6
  Author-email: r0bbarh00d <r0bbarh00d@gmail.com>