siglab-py 0.2.8__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.
- {siglab_py-0.2.8 → siglab_py-0.2.9}/PKG-INFO +1 -1
- {siglab_py-0.2.8 → siglab_py-0.2.9}/pyproject.toml +1 -1
- {siglab_py-0.2.8 → siglab_py-0.2.9}/setup.cfg +1 -1
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/ordergateway/gateway.py +28 -10
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/util/notification_util.py +6 -2
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/util/slack_notification_util.py +4 -4
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py.egg-info/PKG-INFO +1 -1
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/__init__.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/constants.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/exchanges/__init__.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/exchanges/any_exchange.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/exchanges/futubull.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/__init__.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/aggregated_orderbook_provider.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/candles_provider.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/candles_ta_provider.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/ccxt_candles_ta_to_csv.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/deribit_options_expiry_provider.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/futu_candles_ta_to_csv.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/orderbooks_provider.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/test_provider.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/ordergateway/__init__.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/ordergateway/client.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/ordergateway/encrypt_keys_util.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/ordergateway/test_ordergateway.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/tests/__init__.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/tests/integration/__init__.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/tests/integration/market_data_util_tests.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/tests/unit/__init__.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/tests/unit/analytic_util_tests.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/tests/unit/market_data_util_tests.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/util/__init__.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/util/analytic_util.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/util/aws_util.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/util/market_data_util.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/util/retry_util.py +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py.egg-info/SOURCES.txt +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py.egg-info/dependency_links.txt +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py.egg-info/requires.txt +0 -0
- {siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "siglab_py"
|
|
7
|
-
version = "0.2.
|
|
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"}
|
|
@@ -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
|
-
|
|
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.
|
|
750
|
+
log(f"{json.dumps(position.to_dict(), indent=4)}")
|
|
738
751
|
|
|
739
|
-
|
|
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
|
-
|
|
743
|
-
|
|
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
|
-
|
|
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
|
|
|
@@ -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
|
|
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
|
-
|
|
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']
|
|
@@ -30,7 +30,7 @@ def slack_dispatch_notification(
|
|
|
30
30
|
return
|
|
31
31
|
|
|
32
32
|
data = {
|
|
33
|
-
"username": "
|
|
33
|
+
"username": "siglab_py",
|
|
34
34
|
"type": "section",
|
|
35
35
|
"blocks": [
|
|
36
36
|
{
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/aggregated_orderbook_provider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/ccxt_candles_ta_to_csv.py
RENAMED
|
File without changes
|
|
File without changes
|
{siglab_py-0.2.8 → siglab_py-0.2.9}/siglab_py/market_data_providers/futu_candles_ta_to_csv.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|