siglab-py 0.1.12__tar.gz → 0.1.15__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.1.12 → siglab_py-0.1.15}/PKG-INFO +1 -1
- {siglab_py-0.1.12 → siglab_py-0.1.15}/pyproject.toml +1 -1
- {siglab_py-0.1.12 → siglab_py-0.1.15}/setup.cfg +1 -1
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/market_data_providers/orderbooks_provider.py +18 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/ordergateway/client.py +7 -1
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/ordergateway/gateway.py +35 -4
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/ordergateway/test_ordergateway.py +3 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py.egg-info/PKG-INFO +1 -1
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/__init__.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/constants.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/exchanges/__init__.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/exchanges/any_exchange.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/market_data_providers/__init__.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/market_data_providers/aggregated_orderbook_provider.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/market_data_providers/candles_provider.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/market_data_providers/candles_ta_provider.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/market_data_providers/deribit_options_expiry_provider.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/market_data_providers/test_provider.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/ordergateway/__init__.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/ordergateway/encrypt_keys_util.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/tests/__init__.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/tests/integration/__init__.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/tests/integration/market_data_util_tests.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/tests/unit/__init__.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/tests/unit/analytic_util_tests.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/util/__init__.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/util/analytic_util.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/util/aws_util.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/util/market_data_util.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/util/retry_util.py +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py.egg-info/SOURCES.txt +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py.egg-info/dependency_links.txt +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py.egg-info/requires.txt +0 -0
- {siglab_py-0.1.12 → siglab_py-0.1.15}/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.1.
|
|
7
|
+
version = "0.1.15"
|
|
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"}
|
{siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/market_data_providers/orderbooks_provider.py
RENAMED
|
@@ -290,6 +290,9 @@ async def _handle_ticker(
|
|
|
290
290
|
task : ThreadTask
|
|
291
291
|
):
|
|
292
292
|
exchange = await instantiate_exhange(exchange_name=exchange_name, old_exchange=None)
|
|
293
|
+
|
|
294
|
+
asyncio.create_task(send_heartbeat(exchange))
|
|
295
|
+
|
|
293
296
|
ob = OrderBook(ticker=ticker, exchange_name=exchange_name)
|
|
294
297
|
candles_publish_topic = candles_publish_topic.replace("$SYMBOL$", ticker)
|
|
295
298
|
candles_publish_topic = candles_publish_topic.replace("$EXCHANGE$", exchange_name)
|
|
@@ -318,6 +321,21 @@ async def _handle_ticker(
|
|
|
318
321
|
exchange = await instantiate_exhange(exchange_name=exchange_name, old_exchange=exchange) # type: ignore Otherwise, Error: Argument of type "Coroutine[Any, Any, Exchange] | Exchange" cannot be assigned to parameter "old_exchange" of type "Exchange | None" in function "instantiate_exhange"
|
|
319
322
|
ob = OrderBook(ticker=ticker, exchange_name=exchange_name)
|
|
320
323
|
|
|
324
|
+
async def send_heartbeat(exchange):
|
|
325
|
+
|
|
326
|
+
await asyncio.sleep(10)
|
|
327
|
+
|
|
328
|
+
while True:
|
|
329
|
+
try:
|
|
330
|
+
first_ws_url = next(iter(exchange.clients))
|
|
331
|
+
client = exchange.clients[first_ws_url]
|
|
332
|
+
message = exchange.ping(client)
|
|
333
|
+
await client.send(message)
|
|
334
|
+
log('Heartbeat sent')
|
|
335
|
+
except Exception as hb_error:
|
|
336
|
+
log(f'Failed to send heartbeat: {hb_error}')
|
|
337
|
+
finally:
|
|
338
|
+
await asyncio.sleep(30)
|
|
321
339
|
|
|
322
340
|
async def main():
|
|
323
341
|
parse_args()
|
|
@@ -32,6 +32,7 @@ class Order:
|
|
|
32
32
|
amount : float,
|
|
33
33
|
order_type : str, # market/limit
|
|
34
34
|
leg_room_bps : float = 0,
|
|
35
|
+
reduce_only : bool = False,
|
|
35
36
|
fees_ccy : Union[str, None] = None
|
|
36
37
|
) -> None:
|
|
37
38
|
self.ticker = ticker
|
|
@@ -39,6 +40,7 @@ class Order:
|
|
|
39
40
|
self.amount = amount
|
|
40
41
|
self.order_type = order_type.strip().lower()
|
|
41
42
|
self.leg_room_bps = leg_room_bps
|
|
43
|
+
self.reduce_only = reduce_only
|
|
42
44
|
self.fees_ccy = fees_ccy
|
|
43
45
|
|
|
44
46
|
def to_dict(self) -> Dict[JSON_SERIALIZABLE_TYPES, JSON_SERIALIZABLE_TYPES]:
|
|
@@ -48,6 +50,7 @@ class Order:
|
|
|
48
50
|
"amount" : self.amount,
|
|
49
51
|
"order_type" : self.order_type,
|
|
50
52
|
"leg_room_bps" : self.leg_room_bps,
|
|
53
|
+
"reduce_only" : self.reduce_only,
|
|
51
54
|
"fees_ccy" : self.fees_ccy
|
|
52
55
|
}
|
|
53
56
|
|
|
@@ -63,11 +66,12 @@ class DivisiblePosition(Order):
|
|
|
63
66
|
amount : float,
|
|
64
67
|
order_type : str, # market/limit
|
|
65
68
|
leg_room_bps : float,
|
|
69
|
+
reduce_only : bool = False,
|
|
66
70
|
fees_ccy : Union[str, None] = None,
|
|
67
71
|
slices : int = 1,
|
|
68
72
|
wait_fill_threshold_ms : float = -1
|
|
69
73
|
) -> None:
|
|
70
|
-
super().__init__(ticker, side, amount, order_type, leg_room_bps, fees_ccy)
|
|
74
|
+
super().__init__(ticker, side, amount, order_type, leg_room_bps, reduce_only, fees_ccy)
|
|
71
75
|
self.slices = slices
|
|
72
76
|
self.wait_fill_threshold_ms = wait_fill_threshold_ms
|
|
73
77
|
self.multiplier = 1
|
|
@@ -91,6 +95,7 @@ class DivisiblePosition(Order):
|
|
|
91
95
|
side=self.side,
|
|
92
96
|
amount=slice_amount_in_base_ccy,
|
|
93
97
|
leg_room_bps=self.leg_room_bps,
|
|
98
|
+
reduce_only=self.reduce_only,
|
|
94
99
|
fees_ccy=self.fees_ccy,
|
|
95
100
|
order_type=self.order_type)
|
|
96
101
|
|
|
@@ -101,6 +106,7 @@ class DivisiblePosition(Order):
|
|
|
101
106
|
side=self.side,
|
|
102
107
|
amount=remaining_amount_in_base_ccy,
|
|
103
108
|
leg_room_bps=self.leg_room_bps,
|
|
109
|
+
reduce_only=self.reduce_only,
|
|
104
110
|
fees_ccy=self.fees_ccy,
|
|
105
111
|
order_type=self.order_type)
|
|
106
112
|
|
|
@@ -184,7 +184,8 @@ param : Dict = {
|
|
|
184
184
|
"incoming_orders_topic_regex" : r"ordergateway_pending_orders_$GATEWAY_ID$",
|
|
185
185
|
"executions_publish_topic" : r"ordergateway_executions_$GATEWAY_ID$",
|
|
186
186
|
|
|
187
|
-
"
|
|
187
|
+
"default_fees_ccy" : None,
|
|
188
|
+
"loop_freq_ms" : 500, # reduce this if you need trade faster
|
|
188
189
|
|
|
189
190
|
'mds' : {
|
|
190
191
|
'topics' : {
|
|
@@ -261,6 +262,9 @@ def parse_args():
|
|
|
261
262
|
parser.add_argument("--default_type", help="default_type: spot, linear, inverse, futures ...etc", default='linear')
|
|
262
263
|
parser.add_argument("--rate_limit_ms", help="rate_limit_ms: Check your exchange rules", default=100)
|
|
263
264
|
|
|
265
|
+
parser.add_argument("--default_fees_ccy", help="If you're trading crypto, CEX fees USDT, DEX fees USDC in many cases. Default None, in which case gateway won't aggregatge fees from executions for you.", default=None)
|
|
266
|
+
parser.add_argument("--loop_freq_ms", help="Loop delays. Reduce this if you want to trade faster.", default=500)
|
|
267
|
+
|
|
264
268
|
parser.add_argument("--encrypt_decrypt_with_aws_kms", help="Y or N. If encrypt_decrypt_with_aws_kms=N, pass in apikey, secret and passphrase unencrypted (Not recommended, for testing only). If Y, they will be decrypted using AMS KMS key.", default='N')
|
|
265
269
|
parser.add_argument("--aws_kms_key_id", help="AWS KMS key ID", default=None)
|
|
266
270
|
parser.add_argument("--apikey", help="Exchange apikey", default=None)
|
|
@@ -280,6 +284,8 @@ def parse_args():
|
|
|
280
284
|
|
|
281
285
|
param['default_type'] = args.default_type
|
|
282
286
|
param['rate_limit_ms'] = int(args.rate_limit_ms)
|
|
287
|
+
param['default_fees_ccy'] = args.default_fees_ccy
|
|
288
|
+
param['loop_freq_ms'] = int(args.loop_freq_ms)
|
|
283
289
|
|
|
284
290
|
if args.encrypt_decrypt_with_aws_kms:
|
|
285
291
|
if args.encrypt_decrypt_with_aws_kms=='Y':
|
|
@@ -422,6 +428,22 @@ async def watch_orders_task(
|
|
|
422
428
|
|
|
423
429
|
await asyncio.sleep(int(param['loop_freq_ms']/1000))
|
|
424
430
|
|
|
431
|
+
async def send_heartbeat(exchange):
|
|
432
|
+
|
|
433
|
+
await asyncio.sleep(10)
|
|
434
|
+
|
|
435
|
+
while True:
|
|
436
|
+
try:
|
|
437
|
+
first_ws_url = next(iter(exchange.clients))
|
|
438
|
+
client = exchange.clients[first_ws_url]
|
|
439
|
+
message = exchange.ping(client)
|
|
440
|
+
await client.send(message)
|
|
441
|
+
log('Heartbeat sent')
|
|
442
|
+
except Exception as hb_error:
|
|
443
|
+
log(f'Failed to send heartbeat: {hb_error}')
|
|
444
|
+
finally:
|
|
445
|
+
await asyncio.sleep(30)
|
|
446
|
+
|
|
425
447
|
async def execute_one_position(
|
|
426
448
|
exchange : AnyExchange,
|
|
427
449
|
position : DivisiblePosition,
|
|
@@ -461,6 +483,9 @@ async def execute_one_position(
|
|
|
461
483
|
rounded_limit_price : float = exchange.price_to_precision(position.ticker, limit_price) # type: ignore
|
|
462
484
|
rounded_limit_price = float(rounded_limit_price)
|
|
463
485
|
|
|
486
|
+
order_params = {
|
|
487
|
+
'reduceOnly': slice.reduce_only
|
|
488
|
+
}
|
|
464
489
|
if position.order_type=='limit':
|
|
465
490
|
if not param['dry_run']:
|
|
466
491
|
executed_order = await exchange.create_order( # type: ignore
|
|
@@ -468,7 +493,8 @@ async def execute_one_position(
|
|
|
468
493
|
type = position.order_type,
|
|
469
494
|
amount = rounded_slice_amount_in_base_ccy,
|
|
470
495
|
price = rounded_limit_price,
|
|
471
|
-
side = position.side
|
|
496
|
+
side = position.side,
|
|
497
|
+
params = order_params
|
|
472
498
|
)
|
|
473
499
|
else:
|
|
474
500
|
executed_order = DUMMY_EXECUTION.copy()
|
|
@@ -493,7 +519,8 @@ async def execute_one_position(
|
|
|
493
519
|
symbol = position.ticker,
|
|
494
520
|
type = position.order_type,
|
|
495
521
|
amount = rounded_slice_amount_in_base_ccy,
|
|
496
|
-
side = position.side
|
|
522
|
+
side = position.side,
|
|
523
|
+
params = order_params
|
|
497
524
|
)
|
|
498
525
|
else:
|
|
499
526
|
executed_order = DUMMY_EXECUTION.copy()
|
|
@@ -674,10 +701,12 @@ async def work(
|
|
|
674
701
|
|
|
675
702
|
# This is how we avoid reprocess same message twice. We check message hash and cache it.
|
|
676
703
|
processed_hash_queue = deque(maxlen=10)
|
|
677
|
-
|
|
704
|
+
|
|
678
705
|
executions : Dict[str, Dict[str, Any]] = {}
|
|
679
706
|
asyncio.create_task(watch_orders_task(exchange, executions))
|
|
680
707
|
|
|
708
|
+
asyncio.create_task(send_heartbeat(exchange))
|
|
709
|
+
|
|
681
710
|
while True:
|
|
682
711
|
try:
|
|
683
712
|
keys = redis_client.keys()
|
|
@@ -701,6 +730,8 @@ async def work(
|
|
|
701
730
|
amount=order['amount'],
|
|
702
731
|
order_type=order['order_type'],
|
|
703
732
|
leg_room_bps=order['leg_room_bps'],
|
|
733
|
+
reduce_only=order['reduce_only'],
|
|
734
|
+
fees_ccy=order['fees_ccy'] if 'fees_ccy' in order else param['default_fees_ccy'],
|
|
704
735
|
slices=order['slices'],
|
|
705
736
|
wait_fill_threshold_ms=order['wait_fill_threshold_ms']
|
|
706
737
|
)
|
|
@@ -69,6 +69,7 @@ if __name__ == '__main__':
|
|
|
69
69
|
side = 'buy',
|
|
70
70
|
amount = 10,
|
|
71
71
|
leg_room_bps = 5,
|
|
72
|
+
reduce_only=False,
|
|
72
73
|
order_type = 'limit',
|
|
73
74
|
slices=5,
|
|
74
75
|
wait_fill_threshold_ms=15000
|
|
@@ -81,6 +82,7 @@ if __name__ == '__main__':
|
|
|
81
82
|
side = 'buy',
|
|
82
83
|
amount = 10,
|
|
83
84
|
leg_room_bps = 5,
|
|
85
|
+
reduce_only=False,
|
|
84
86
|
order_type = 'limit',
|
|
85
87
|
slices=5,
|
|
86
88
|
wait_fill_threshold_ms=15000
|
|
@@ -93,6 +95,7 @@ if __name__ == '__main__':
|
|
|
93
95
|
side = 'sell',
|
|
94
96
|
amount = 0.01,
|
|
95
97
|
leg_room_bps = 5,
|
|
98
|
+
reduce_only=False,
|
|
96
99
|
order_type = 'limit',
|
|
97
100
|
slices=1,
|
|
98
101
|
wait_fill_threshold_ms=60000
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{siglab_py-0.1.12 → siglab_py-0.1.15}/siglab_py/market_data_providers/candles_ta_provider.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
|