siglab-py 0.1.9__tar.gz → 0.1.10__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.9 → siglab_py-0.1.10}/PKG-INFO +1 -1
- {siglab_py-0.1.9 → siglab_py-0.1.10}/pyproject.toml +1 -1
- {siglab_py-0.1.9 → siglab_py-0.1.10}/setup.cfg +1 -1
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/market_data_providers/aggregated_orderbook_provider.py +2 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/market_data_providers/deribit_options_expiry_provider.py +3 -1
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/ordergateway/client.py +45 -1
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/ordergateway/gateway.py +164 -43
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/ordergateway/test_ordergateway.py +3 -3
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py.egg-info/PKG-INFO +1 -1
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/__init__.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/constants.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/exchanges/__init__.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/exchanges/any_exchange.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/market_data_providers/__init__.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/market_data_providers/candles_provider.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/market_data_providers/candles_ta_provider.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/market_data_providers/orderbooks_provider.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/market_data_providers/test_provider.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/ordergateway/__init__.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/ordergateway/encrypt_keys_util.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/tests/__init__.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/tests/integration/__init__.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/tests/integration/market_data_util_tests.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/tests/unit/__init__.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/tests/unit/analytic_util_tests.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/util/__init__.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/util/analytic_util.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/util/aws_util.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/util/market_data_util.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py/util/retry_util.py +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py.egg-info/SOURCES.txt +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py.egg-info/dependency_links.txt +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/siglab_py.egg-info/requires.txt +0 -0
- {siglab_py-0.1.9 → siglab_py-0.1.10}/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.10"
|
|
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"}
|
|
@@ -12,6 +12,8 @@ import numpy as np
|
|
|
12
12
|
from redis import StrictRedis
|
|
13
13
|
|
|
14
14
|
'''
|
|
15
|
+
https://medium.com/@norman-lm-fung/aggregated-orderbooks-using-ccxt-and-rest-calls-to-cexes-7bfdc8400d05
|
|
16
|
+
|
|
15
17
|
From command prompt:
|
|
16
18
|
python aggregated_orderbook.py --normalized_symbol BTC/USDT:USDT --sliding_window_num_intervals 1200 --update_imabalce_csv_intervals 100 --dump_imbalance_to_disk Y --publish_imbalance_to_redis N
|
|
17
19
|
or
|
|
@@ -14,7 +14,9 @@ from redis import StrictRedis
|
|
|
14
14
|
import pandas as pd
|
|
15
15
|
|
|
16
16
|
from util.market_data_util import timestamp_to_datetime_cols, fetch_deribit_btc_option_expiries, fetch_ohlcv_one_candle
|
|
17
|
-
|
|
17
|
+
'''
|
|
18
|
+
https://medium.com/@norman-lm-fung/monitoring-incoming-deribit-open-interest-fd8c8d596ca0
|
|
19
|
+
'''
|
|
18
20
|
param : Dict = {
|
|
19
21
|
'market' : 'BTC',
|
|
20
22
|
|
|
@@ -123,7 +123,51 @@ class DivisiblePosition(Order):
|
|
|
123
123
|
return filled_amount
|
|
124
124
|
|
|
125
125
|
def get_average_cost(self) -> float:
|
|
126
|
-
|
|
126
|
+
'''
|
|
127
|
+
Example hyperliquid don't have 'average' in response JSON:
|
|
128
|
+
|
|
129
|
+
{
|
|
130
|
+
'info': {
|
|
131
|
+
'order': {
|
|
132
|
+
'coin': 'SUSHI',
|
|
133
|
+
'side': 'B',
|
|
134
|
+
'limitPx': '0.79252',
|
|
135
|
+
'sz': '0.0',
|
|
136
|
+
'oid': xxx,
|
|
137
|
+
'timestamp': xxx,
|
|
138
|
+
'origSz': '30.0'
|
|
139
|
+
},
|
|
140
|
+
'status': 'filled',
|
|
141
|
+
'statusTimestamp': xxx},
|
|
142
|
+
'id': 'xxx',
|
|
143
|
+
'clientOrderId': None,
|
|
144
|
+
'timestamp': xxx,
|
|
145
|
+
'datetime': '2025-02-26T01:00:00.522Z',
|
|
146
|
+
'lastTradeTimestamp': None,
|
|
147
|
+
'lastUpdateTimestamp': xxx,
|
|
148
|
+
'symbol': 'SUSHI/USDC:USDC',
|
|
149
|
+
'type': None,
|
|
150
|
+
'timeInForce': None,
|
|
151
|
+
'postOnly': None,
|
|
152
|
+
'reduceOnly': None,
|
|
153
|
+
'side': 'buy',
|
|
154
|
+
'price': 0.79252,
|
|
155
|
+
'triggerPrice': None,
|
|
156
|
+
'amount': 30.0,
|
|
157
|
+
'cost': 23.7756,
|
|
158
|
+
'average': None, <-- No average cost?
|
|
159
|
+
'filled': 30.0,
|
|
160
|
+
'remaining': 0.0,
|
|
161
|
+
'status': 'closed',
|
|
162
|
+
'fee': None,
|
|
163
|
+
'trades': [],
|
|
164
|
+
'fees': [],
|
|
165
|
+
'stopPrice': None,
|
|
166
|
+
'takeProfitPrice': None,
|
|
167
|
+
'stopLossPrice': None
|
|
168
|
+
}
|
|
169
|
+
'''
|
|
170
|
+
average_cost = sum([ (self.executions[order_id]['average'] if self.executions[order_id]['average'] else self.executions[order_id]['price']) * self.executions[order_id]['amount'] for order_id in self.executions ])
|
|
127
171
|
average_cost = average_cost / sum([ self.executions[order_id]['amount'] for order_id in self.executions ])
|
|
128
172
|
return average_cost
|
|
129
173
|
|
|
@@ -12,6 +12,7 @@ import hashlib
|
|
|
12
12
|
from collections import deque
|
|
13
13
|
import logging
|
|
14
14
|
import json
|
|
15
|
+
import uuid
|
|
15
16
|
from io import StringIO
|
|
16
17
|
import re
|
|
17
18
|
from re import Pattern
|
|
@@ -178,11 +179,12 @@ class LogLevel(Enum):
|
|
|
178
179
|
|
|
179
180
|
param : Dict = {
|
|
180
181
|
'gateway_id' : '---',
|
|
182
|
+
'dry_run' : False,
|
|
181
183
|
|
|
182
184
|
"incoming_orders_topic_regex" : r"ordergateway_pending_orders_$GATEWAY_ID$",
|
|
183
185
|
"executions_publish_topic" : r"ordergateway_executions_$GATEWAY_ID$",
|
|
184
186
|
|
|
185
|
-
"
|
|
187
|
+
"loop_freq_ms" : 500,
|
|
186
188
|
|
|
187
189
|
'mds' : {
|
|
188
190
|
'topics' : {
|
|
@@ -207,6 +209,39 @@ sh = logging.StreamHandler()
|
|
|
207
209
|
sh.setLevel(log_level)
|
|
208
210
|
sh.setFormatter(formatter)
|
|
209
211
|
logger.addHandler(sh)
|
|
212
|
+
fh = logging.FileHandler(f"ordergateway.log")
|
|
213
|
+
fh.setLevel(log_level)
|
|
214
|
+
fh.setFormatter(formatter)
|
|
215
|
+
logger.addHandler(fh)
|
|
216
|
+
|
|
217
|
+
DUMMY_EXECUTION : Dict[str, Any] = {
|
|
218
|
+
"clientOrderId": None,
|
|
219
|
+
"timestamp": None,
|
|
220
|
+
"datetime": None,
|
|
221
|
+
"symbol": None,
|
|
222
|
+
"type": None,
|
|
223
|
+
"side": None,
|
|
224
|
+
"price": None,
|
|
225
|
+
"average": None,
|
|
226
|
+
"cost": None,
|
|
227
|
+
"amount": None,
|
|
228
|
+
"filled": None,
|
|
229
|
+
"remaining": None,
|
|
230
|
+
"status": "closed",
|
|
231
|
+
"fee": {
|
|
232
|
+
"cost": None,
|
|
233
|
+
"currency": "USDT"
|
|
234
|
+
},
|
|
235
|
+
"trades": [],
|
|
236
|
+
"reduceOnly": False,
|
|
237
|
+
"fees": [
|
|
238
|
+
{
|
|
239
|
+
"cost": 0,
|
|
240
|
+
"currency": "USDT"
|
|
241
|
+
}
|
|
242
|
+
],
|
|
243
|
+
"multiplier": None
|
|
244
|
+
}
|
|
210
245
|
|
|
211
246
|
def log(message : str, log_level : LogLevel = LogLevel.INFO):
|
|
212
247
|
if log_level.value<LogLevel.WARNING.value:
|
|
@@ -222,6 +257,7 @@ def parse_args():
|
|
|
222
257
|
parser = argparse.ArgumentParser() # type: ignore
|
|
223
258
|
|
|
224
259
|
parser.add_argument("--gateway_id", help="gateway_id: Where are you sending your order?", default=None)
|
|
260
|
+
parser.add_argument("--dry_run", help="Y or N (default, for testing). If Y, orders won't be dispatched to exchange, gateway will fake reply.", default='N')
|
|
225
261
|
parser.add_argument("--default_type", help="default_type: spot, linear, inverse, futures ...etc", default='linear')
|
|
226
262
|
parser.add_argument("--rate_limit_ms", help="rate_limit_ms: Check your exchange rules", default=100)
|
|
227
263
|
|
|
@@ -233,6 +269,15 @@ def parse_args():
|
|
|
233
269
|
|
|
234
270
|
args = parser.parse_args()
|
|
235
271
|
param['gateway_id'] = args.gateway_id
|
|
272
|
+
|
|
273
|
+
if args.dry_run:
|
|
274
|
+
if args.dry_run=='Y':
|
|
275
|
+
param['dry_run'] = True
|
|
276
|
+
else:
|
|
277
|
+
param['dry_run'] = False
|
|
278
|
+
else:
|
|
279
|
+
param['dry_run'] = False
|
|
280
|
+
|
|
236
281
|
param['default_type'] = args.default_type
|
|
237
282
|
param['rate_limit_ms'] = int(args.rate_limit_ms)
|
|
238
283
|
|
|
@@ -264,7 +309,7 @@ def init_redis_client() -> StrictRedis:
|
|
|
264
309
|
|
|
265
310
|
return redis_client
|
|
266
311
|
|
|
267
|
-
def instantiate_exchange(
|
|
312
|
+
async def instantiate_exchange(
|
|
268
313
|
gateway_id : str,
|
|
269
314
|
api_key : str,
|
|
270
315
|
secret : str,
|
|
@@ -306,12 +351,58 @@ def instantiate_exchange(
|
|
|
306
351
|
# https://github.com/ccxt/ccxt/blob/master/python/ccxt/deribit.py#L360
|
|
307
352
|
exchange = ccxtpro.deribit(exchange_params) # type: ignore
|
|
308
353
|
elif exchange_name=='hyperliquid':
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
354
|
+
'''
|
|
355
|
+
https://app.hyperliquid.xyz/API
|
|
356
|
+
|
|
357
|
+
defaultType from ccxt: swap
|
|
358
|
+
https://github.com/ccxt/ccxt/blob/master/python/ccxt/hyperliquid.py#L225
|
|
359
|
+
|
|
360
|
+
How to integrate? You can skip first 6 min: https://www.youtube.com/watch?v=UuBr331wxr4&t=363s
|
|
361
|
+
|
|
362
|
+
Example,
|
|
363
|
+
API credentials created under "\ More \ API":
|
|
364
|
+
Ledger Arbitrum Wallet Address: 0xAAAAA <-- This is your Ledger Arbitrum wallet address with which you connect to Hyperliquid.
|
|
365
|
+
API Wallet Address 0xBBBBB <-- Generated
|
|
366
|
+
privateKey 0xCCCCC
|
|
367
|
+
|
|
368
|
+
Basic connection via CCXT:
|
|
369
|
+
import asyncio
|
|
370
|
+
import ccxt.pro as ccxtpro
|
|
371
|
+
|
|
372
|
+
async def main():
|
|
373
|
+
rate_limit_ms = 100
|
|
374
|
+
exchange_params = {
|
|
375
|
+
"walletAddress" : "0xAAAAA", # Ledger Arbitrum Wallet Address here! Not the generated address.
|
|
376
|
+
"privateKey" : "0xCCCCC"
|
|
377
|
+
}
|
|
378
|
+
exchange = ccxtpro.hyperliquid(exchange_params)
|
|
379
|
+
balances = await exchange.fetch_balance()
|
|
380
|
+
print(balances)
|
|
381
|
+
|
|
382
|
+
asyncio.run(main())
|
|
383
|
+
'''
|
|
384
|
+
exchange = ccxtpro.hyperliquid(
|
|
385
|
+
{
|
|
386
|
+
"walletAddress" : api_key,
|
|
387
|
+
"privateKey" : secret,
|
|
388
|
+
'enableRateLimit' : True,
|
|
389
|
+
'rateLimit' : rate_limit_ms
|
|
390
|
+
}
|
|
391
|
+
) # type: ignore
|
|
312
392
|
else:
|
|
313
393
|
raise ArgumentError(f"Unsupported exchange {exchange_name}, check gateway_id {gateway_id}.")
|
|
314
394
|
|
|
395
|
+
await exchange.load_markets() # type: ignore
|
|
396
|
+
|
|
397
|
+
'''
|
|
398
|
+
Is this necessary? The added trouble is for example bybit.authenticate requires arg 'url'. binance doesn't. And fetch_balance already test credentials.
|
|
399
|
+
|
|
400
|
+
try:
|
|
401
|
+
await exchange.authenticate() # type: ignore
|
|
402
|
+
except Exception as swallow_this_error:
|
|
403
|
+
pass
|
|
404
|
+
'''
|
|
405
|
+
|
|
315
406
|
return exchange
|
|
316
407
|
|
|
317
408
|
async def watch_orders_task(
|
|
@@ -329,7 +420,7 @@ async def watch_orders_task(
|
|
|
329
420
|
except Exception as loop_err:
|
|
330
421
|
print(f"watch_orders_task error: {loop_err}")
|
|
331
422
|
|
|
332
|
-
await asyncio.sleep(int(param['
|
|
423
|
+
await asyncio.sleep(int(param['loop_freq_ms']/1000))
|
|
333
424
|
|
|
334
425
|
async def execute_one_position(
|
|
335
426
|
exchange : AnyExchange,
|
|
@@ -337,17 +428,11 @@ async def execute_one_position(
|
|
|
337
428
|
param : Dict,
|
|
338
429
|
executions : Dict[str, Dict[str, Any]]
|
|
339
430
|
):
|
|
340
|
-
await exchange.load_markets() # type: ignore
|
|
341
|
-
try:
|
|
342
|
-
await exchange.authenticate() # type: ignore
|
|
343
|
-
except Exception as swallow_this_error:
|
|
344
|
-
pass # @todo, perhaps a better way for handling this?
|
|
345
|
-
|
|
346
431
|
market : Dict[str, Any] = exchange.markets[position.ticker] if position.ticker in exchange.markets else None # type: ignore
|
|
347
432
|
if not market:
|
|
348
433
|
raise ArgumentError(f"Market not found for {position.ticker} under {exchange.name}") # type: ignore
|
|
349
434
|
|
|
350
|
-
min_amount = float(market['limits']['amount']['min']) # type: ignore
|
|
435
|
+
min_amount = float(market['limits']['amount']['min']) if market['limits']['amount']['min'] else 0 # type: ignore
|
|
351
436
|
multiplier = market['contractSize'] if 'contractSize' in market and market['contractSize'] else 1
|
|
352
437
|
position.multiplier = multiplier
|
|
353
438
|
|
|
@@ -355,43 +440,77 @@ async def execute_one_position(
|
|
|
355
440
|
i = 0
|
|
356
441
|
for slice in slices:
|
|
357
442
|
try:
|
|
443
|
+
dt_now : datetime = datetime.now()
|
|
444
|
+
|
|
358
445
|
slice_amount_in_base_ccy : float = slice.amount
|
|
359
446
|
rounded_slice_amount_in_base_ccy = slice_amount_in_base_ccy / multiplier # After devided by multiplier, rounded_slice_amount_in_base_ccy in number of contracts actually (Not in base ccy).
|
|
360
447
|
rounded_slice_amount_in_base_ccy = exchange.amount_to_precision(position.ticker, rounded_slice_amount_in_base_ccy) # type: ignore
|
|
361
448
|
rounded_slice_amount_in_base_ccy = float(rounded_slice_amount_in_base_ccy)
|
|
362
449
|
rounded_slice_amount_in_base_ccy = rounded_slice_amount_in_base_ccy if rounded_slice_amount_in_base_ccy>min_amount else min_amount
|
|
363
450
|
|
|
364
|
-
|
|
365
|
-
|
|
451
|
+
orderbook = await exchange.fetch_order_book(symbol=position.ticker, limit=3) # type: ignore
|
|
452
|
+
if position.side=='buy':
|
|
453
|
+
asks = [ ask[0] for ask in orderbook['asks'] ]
|
|
454
|
+
best_asks = min(asks)
|
|
455
|
+
limit_price : float= best_asks * (1 + position.leg_room_bps/10000)
|
|
456
|
+
else:
|
|
457
|
+
bids = [ bid[0] for bid in orderbook['bids'] ]
|
|
458
|
+
best_bid = max(bids)
|
|
459
|
+
limit_price : float = best_bid * (1 - position.leg_room_bps/10000)
|
|
460
|
+
|
|
461
|
+
rounded_limit_price : float = exchange.price_to_precision(position.ticker, limit_price) # type: ignore
|
|
462
|
+
rounded_limit_price = float(rounded_limit_price)
|
|
463
|
+
|
|
366
464
|
if position.order_type=='limit':
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
465
|
+
if not param['dry_run']:
|
|
466
|
+
executed_order = await exchange.create_order( # type: ignore
|
|
467
|
+
symbol = position.ticker,
|
|
468
|
+
type = position.order_type,
|
|
469
|
+
amount = rounded_slice_amount_in_base_ccy,
|
|
470
|
+
price = rounded_limit_price,
|
|
471
|
+
side = position.side
|
|
472
|
+
)
|
|
372
473
|
else:
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
amount = rounded_slice_amount_in_base_ccy
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
474
|
+
executed_order = DUMMY_EXECUTION.copy()
|
|
475
|
+
executed_order['clientOrderId'] = str(uuid.uuid4())
|
|
476
|
+
executed_order['timestamp'] = dt_now.timestamp()
|
|
477
|
+
executed_order['datetime'] = dt_now
|
|
478
|
+
executed_order['symbol'] = position.ticker
|
|
479
|
+
executed_order['type'] = position.order_type
|
|
480
|
+
executed_order['side'] = position.side
|
|
481
|
+
executed_order['price'] = rounded_limit_price
|
|
482
|
+
executed_order['average'] = rounded_limit_price
|
|
483
|
+
executed_order['cost'] = 0
|
|
484
|
+
executed_order['amount'] = rounded_slice_amount_in_base_ccy
|
|
485
|
+
executed_order['filled'] = rounded_slice_amount_in_base_ccy
|
|
486
|
+
executed_order['remaining'] = 0
|
|
487
|
+
executed_order['status'] = 'closed'
|
|
488
|
+
executed_order['multiplier'] = position.multiplier
|
|
387
489
|
|
|
388
490
|
else:
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
491
|
+
if not param['dry_run']:
|
|
492
|
+
executed_order = await exchange.create_order( # type: ignore
|
|
493
|
+
symbol = position.ticker,
|
|
494
|
+
type = position.order_type,
|
|
495
|
+
amount = rounded_slice_amount_in_base_ccy,
|
|
496
|
+
side = position.side
|
|
497
|
+
)
|
|
498
|
+
else:
|
|
499
|
+
executed_order = DUMMY_EXECUTION.copy()
|
|
500
|
+
executed_order['clientOrderId'] = str(uuid.uuid4())
|
|
501
|
+
executed_order['timestamp'] = dt_now.timestamp()
|
|
502
|
+
executed_order['datetime'] = dt_now
|
|
503
|
+
executed_order['symbol'] = position.ticker
|
|
504
|
+
executed_order['type'] = position.order_type
|
|
505
|
+
executed_order['side'] = position.side
|
|
506
|
+
executed_order['price'] = rounded_limit_price
|
|
507
|
+
executed_order['average'] = rounded_limit_price
|
|
508
|
+
executed_order['cost'] = 0
|
|
509
|
+
executed_order['amount'] = rounded_slice_amount_in_base_ccy
|
|
510
|
+
executed_order['filled'] = rounded_slice_amount_in_base_ccy
|
|
511
|
+
executed_order['remaining'] = 0
|
|
512
|
+
executed_order['status'] = 'closed'
|
|
513
|
+
executed_order['multiplier'] = position.multiplier
|
|
395
514
|
|
|
396
515
|
executed_order['slice_id'] = i
|
|
397
516
|
|
|
@@ -459,7 +578,7 @@ async def execute_one_position(
|
|
|
459
578
|
log(f"Limit order fully filled: {order_id}", log_level=LogLevel.INFO)
|
|
460
579
|
break
|
|
461
580
|
|
|
462
|
-
await asyncio.sleep(int(param['
|
|
581
|
+
await asyncio.sleep(int(param['loop_freq_ms']/1000))
|
|
463
582
|
|
|
464
583
|
|
|
465
584
|
|
|
@@ -511,7 +630,7 @@ async def execute_one_position(
|
|
|
511
630
|
|
|
512
631
|
log(f"Waiting for resent market order to close {order_id} ...")
|
|
513
632
|
|
|
514
|
-
await asyncio.sleep(int(param['
|
|
633
|
+
await asyncio.sleep(int(param['loop_freq_ms']/1000))
|
|
515
634
|
|
|
516
635
|
log(f"Resent market order{order_id} filled. status: {order_status}, filled_amount: {filled_amount}, remaining_amount: {remaining_amount}")
|
|
517
636
|
|
|
@@ -618,6 +737,8 @@ async def work(
|
|
|
618
737
|
|
|
619
738
|
except Exception as loop_error:
|
|
620
739
|
log(f"Error: {loop_error} {str(sys.exc_info()[0])} {str(sys.exc_info()[1])} {traceback.format_exc()}")
|
|
740
|
+
finally:
|
|
741
|
+
await asyncio.sleep(int(param['loop_freq_ms']/1000))
|
|
621
742
|
|
|
622
743
|
async def main():
|
|
623
744
|
parse_args()
|
|
@@ -652,7 +773,7 @@ async def main():
|
|
|
652
773
|
|
|
653
774
|
redis_client : StrictRedis = init_redis_client()
|
|
654
775
|
|
|
655
|
-
exchange : Union[AnyExchange, None] = instantiate_exchange(
|
|
776
|
+
exchange : Union[AnyExchange, None] = await instantiate_exchange(
|
|
656
777
|
gateway_id=param['gateway_id'],
|
|
657
778
|
api_key=api_key,
|
|
658
779
|
secret=secret,
|
|
@@ -77,12 +77,12 @@ if __name__ == '__main__':
|
|
|
77
77
|
|
|
78
78
|
positions_2 : List[DivisiblePosition] = [
|
|
79
79
|
DivisiblePosition(
|
|
80
|
-
ticker = 'SUSHI/
|
|
80
|
+
ticker = 'SUSHI/USDC:USDC',
|
|
81
81
|
side = 'buy',
|
|
82
|
-
amount =
|
|
82
|
+
amount = 60,
|
|
83
83
|
leg_room_bps = 5,
|
|
84
84
|
order_type = 'limit',
|
|
85
|
-
slices=
|
|
85
|
+
slices=2,
|
|
86
86
|
wait_fill_threshold_ms=15000
|
|
87
87
|
),
|
|
88
88
|
]
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|