exchanges-wrapper 1.4.7__tar.gz → 1.4.8__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.
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/PKG-INFO +1 -1
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/__init__.py +1 -1
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/bybit_parser.py +1 -1
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/client.py +34 -23
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/exch_srv.py +10 -12
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/exch_srv_cfg.toml.template +9 -1
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/web_sockets.py +12 -6
- exchanges-wrapper-1.4.7/.deepsource.toml +0 -12
- exchanges-wrapper-1.4.7/.dockerignore +0 -3
- exchanges-wrapper-1.4.7/.github/FUNDING.yml +0 -1
- exchanges-wrapper-1.4.7/.github/dependabot.yml +0 -11
- exchanges-wrapper-1.4.7/.github/workflows/docker-image.yml +0 -32
- exchanges-wrapper-1.4.7/.github/workflows/python-publish.yml +0 -40
- exchanges-wrapper-1.4.7/CHANGELOG.md +0 -398
- exchanges-wrapper-1.4.7/Dockerfile +0 -23
- exchanges-wrapper-1.4.7/example/exch_client.py +0 -422
- exchanges-wrapper-1.4.7/example/ms_cfg.toml +0 -5
- exchanges-wrapper-1.4.7/requirements.txt +0 -12
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/LICENSE.md +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/README.md +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/api_pb2.py +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/api_pb2_grpc.py +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/bitfinex_parser.py +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/c_structures.py +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/definitions.py +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/errors.py +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/events.py +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/http_client.py +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/huobi_parser.py +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/okx_parser.py +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/proto/exchanges_wrapper/api.proto +0 -0
- {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: exchanges-wrapper
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.8
|
|
4
4
|
Summary: REST API and WebSocket asyncio wrapper with grpc powered multiplexer server
|
|
5
5
|
Author-email: Thomas Marchand <thomas.marchand@tuta.io>, Jerry Fedorenko <jerry.fedorenko@yahoo.com>
|
|
6
6
|
Requires-Python: >=3.9
|
|
@@ -12,7 +12,7 @@ __maintainer__ = "Jerry Fedorenko"
|
|
|
12
12
|
__contact__ = "https://github.com/DogsTailFarmer"
|
|
13
13
|
__email__ = "jerry.fedorenko@yahoo.com"
|
|
14
14
|
__credits__ = ["https://github.com/DanyaSWorlD"]
|
|
15
|
-
__version__ = "1.4.
|
|
15
|
+
__version__ = "1.4.8"
|
|
16
16
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
import shutil
|
|
@@ -403,7 +403,7 @@ def on_trade_update(res: dict) -> dict:
|
|
|
403
403
|
"t": int(res.get("execId", -1)),
|
|
404
404
|
"I": 123456789,
|
|
405
405
|
"w": True,
|
|
406
|
-
"m": False,
|
|
406
|
+
"m": res.get("isMaker", False),
|
|
407
407
|
"M": False,
|
|
408
408
|
"O": int(res.get("execTime", res.get("createdTime"))),
|
|
409
409
|
"Z": cumulative_quote_asset,
|
|
@@ -11,6 +11,7 @@ import pyotp
|
|
|
11
11
|
from expiringdict import ExpiringDict
|
|
12
12
|
import uuid
|
|
13
13
|
from decimal import Decimal
|
|
14
|
+
from urllib.parse import quote
|
|
14
15
|
|
|
15
16
|
from exchanges_wrapper.http_client import ClientBinance, ClientBFX, ClientHBP, ClientOKX, ClientBybit
|
|
16
17
|
from exchanges_wrapper.errors import ExchangePyError
|
|
@@ -95,7 +96,7 @@ class Client:
|
|
|
95
96
|
self.rate_limits = None
|
|
96
97
|
self.data_streams = defaultdict(set)
|
|
97
98
|
self.active_orders = {}
|
|
98
|
-
self.wss_buffer = ExpiringDict(max_len=50, max_age_seconds=STATUS_TIMEOUT*
|
|
99
|
+
self.wss_buffer = ExpiringDict(max_len=50, max_age_seconds=STATUS_TIMEOUT*20)
|
|
99
100
|
self.stream_queue = defaultdict(set)
|
|
100
101
|
self.on_order_update_queues = {}
|
|
101
102
|
self.account_id = None
|
|
@@ -221,28 +222,29 @@ class Client:
|
|
|
221
222
|
return f"{symbol_info.get('baseAsset')}-{symbol_info.get('quoteAsset')}"
|
|
222
223
|
|
|
223
224
|
def active_order(self, order_id: int, quantity="0", executed_qty="0", last_event=None):
|
|
224
|
-
if
|
|
225
|
-
last_event = []
|
|
226
|
-
if order_id in self.active_orders and not self.active_orders[order_id]["origQty"]:
|
|
227
|
-
self.active_orders[order_id].update({'origQty': Decimal(quantity)})
|
|
228
|
-
elif order_id not in self.active_orders:
|
|
225
|
+
if order_id not in self.active_orders:
|
|
229
226
|
self.active_orders[order_id] = {
|
|
230
|
-
'lifeTime': int(time.time()) + 60 * STATUS_TIMEOUT,
|
|
231
227
|
'origQty': Decimal(quantity),
|
|
232
228
|
'executedQty': Decimal(executed_qty),
|
|
233
|
-
'lastEvent': last_event
|
|
229
|
+
'lastEvent': last_event if last_event else [],
|
|
230
|
+
'eventIds': [],
|
|
234
231
|
'cancelled': False
|
|
235
232
|
}
|
|
236
|
-
|
|
237
|
-
self.active_orders[order_id]
|
|
233
|
+
elif last_event is not None:
|
|
234
|
+
self.active_orders[order_id]['lastEvent'] = last_event
|
|
238
235
|
|
|
239
|
-
|
|
236
|
+
self.active_orders[order_id]['lifeTime'] = int(time.time()) + 60 * STATUS_TIMEOUT
|
|
237
|
+
|
|
238
|
+
if not self.active_orders[order_id]["origQty"]:
|
|
239
|
+
self.active_orders[order_id]["origQty"] = Decimal(quantity)
|
|
240
|
+
|
|
241
|
+
def active_orders_clear(self):
|
|
240
242
|
ts = int(time.time())
|
|
241
|
-
self.active_orders = {
|
|
242
|
-
|
|
243
|
-
|
|
243
|
+
self.active_orders = {
|
|
244
|
+
key: val for key, val in self.active_orders.items() if val['lifeTime'] > ts
|
|
245
|
+
}
|
|
244
246
|
|
|
245
|
-
def refine_amount(self, symbol, amount: Union[str, Decimal],
|
|
247
|
+
def refine_amount(self, symbol, amount: Union[str, Decimal], _quote=False):
|
|
246
248
|
if type(amount) is str: # to save time for developers
|
|
247
249
|
amount = Decimal(amount)
|
|
248
250
|
if self.loaded:
|
|
@@ -251,7 +253,7 @@ class Client:
|
|
|
251
253
|
step_size = Decimal(lot_size_filter["stepSize"])
|
|
252
254
|
# noinspection PyStringFormat
|
|
253
255
|
amount = (
|
|
254
|
-
(f"%.{precision}f" % truncate(amount if
|
|
256
|
+
(f"%.{precision}f" % truncate(amount if _quote else (amount - amount % step_size), precision))
|
|
255
257
|
.rstrip("0")
|
|
256
258
|
.rstrip(".")
|
|
257
259
|
)
|
|
@@ -868,7 +870,6 @@ class Client:
|
|
|
868
870
|
**params,
|
|
869
871
|
)
|
|
870
872
|
)
|
|
871
|
-
logger.info(f"create_order.res: {res}")
|
|
872
873
|
if res and isinstance(res, list) and res[6] == 'SUCCESS':
|
|
873
874
|
self.active_order(res[4][0][0], quantity)
|
|
874
875
|
binance_res = bfx.order(res[4][0], response_type=False)
|
|
@@ -1592,12 +1593,22 @@ class Client:
|
|
|
1592
1593
|
params = {"asset": symbol, "amount": quantity}
|
|
1593
1594
|
if receive_window:
|
|
1594
1595
|
params["recvWindow"] = receive_window
|
|
1595
|
-
|
|
1596
|
-
"
|
|
1597
|
-
"
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1596
|
+
if self.master_email:
|
|
1597
|
+
logger.info(f"Collect {quantity}{symbol} to {self.master_email} sub-account")
|
|
1598
|
+
params["toEmail"] = quote(self.master_email)
|
|
1599
|
+
binance_res = await self.http.send_api_call(
|
|
1600
|
+
"/sapi/v1/sub-account/transfer/subToSub",
|
|
1601
|
+
"POST",
|
|
1602
|
+
params=params,
|
|
1603
|
+
signed=True
|
|
1604
|
+
)
|
|
1605
|
+
else:
|
|
1606
|
+
binance_res = await self.http.send_api_call(
|
|
1607
|
+
"/sapi/v1/sub-account/transfer/subToMaster",
|
|
1608
|
+
"POST",
|
|
1609
|
+
params=params,
|
|
1610
|
+
signed=True
|
|
1611
|
+
)
|
|
1601
1612
|
elif self.exchange == 'bitfinex':
|
|
1602
1613
|
if self.master_email is None or self.two_fa is None:
|
|
1603
1614
|
raise ValueError("This query requires master_email and 2FA")
|
|
@@ -282,22 +282,19 @@ class Martin(api_pb2_grpc.MartinServicer):
|
|
|
282
282
|
_context.set_details(f"{ex}")
|
|
283
283
|
_context.set_code(grpc.StatusCode.UNKNOWN)
|
|
284
284
|
else:
|
|
285
|
-
# logger.info(f"FetchOpenOrders.res: {res}")
|
|
286
285
|
open_client.ts_rlc = time.time()
|
|
287
286
|
active_orders = []
|
|
288
287
|
for order in res:
|
|
289
288
|
order_id = order['orderId']
|
|
290
289
|
active_orders.append(order_id)
|
|
291
290
|
new_order = json_format.ParseDict(order, response_order, ignore_unknown_fields=True)
|
|
292
|
-
# logger.debug(f"FetchOpenOrders.new_order: {new_order}")
|
|
293
291
|
response.items.append(new_order)
|
|
294
292
|
if client.exchange == 'bitfinex':
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
else:
|
|
298
|
-
client.active_order(order_id, order['origQty'], order['executedQty'])
|
|
293
|
+
client.active_order(order_id, order['origQty'], order['executedQty'])
|
|
294
|
+
|
|
299
295
|
if client.exchange == 'bitfinex':
|
|
300
|
-
client.active_orders_clear(
|
|
296
|
+
client.active_orders_clear()
|
|
297
|
+
|
|
301
298
|
response.rate_limiter = Martin.rate_limiter
|
|
302
299
|
return response
|
|
303
300
|
|
|
@@ -806,7 +803,6 @@ class Martin(api_pb2_grpc.MartinServicer):
|
|
|
806
803
|
else:
|
|
807
804
|
event = vars(_event)
|
|
808
805
|
event.pop('handlers', None)
|
|
809
|
-
# logger.info(f"OnOrderUpdate: {event}")
|
|
810
806
|
response.success = True
|
|
811
807
|
response.result = json.dumps(str(event))
|
|
812
808
|
yield response
|
|
@@ -881,13 +877,16 @@ class Martin(api_pb2_grpc.MartinServicer):
|
|
|
881
877
|
_context.set_details(f"{ex}")
|
|
882
878
|
_context.set_code(grpc.StatusCode.UNKNOWN)
|
|
883
879
|
else:
|
|
884
|
-
if not res or res.get('executedQty', '0')
|
|
880
|
+
if not res or Decimal(res.get('executedQty', '0')):
|
|
885
881
|
await self.create_trade_stream_event(_queue, client, open_client, request)
|
|
886
882
|
json_format.ParseDict(res, response, ignore_unknown_fields=True)
|
|
887
883
|
return response
|
|
888
884
|
|
|
889
|
-
async def TransferToMaster(
|
|
890
|
-
|
|
885
|
+
async def TransferToMaster(
|
|
886
|
+
self,
|
|
887
|
+
request: api_pb2.MarketRequest,
|
|
888
|
+
_context: grpc.aio.ServicerContext
|
|
889
|
+
) -> api_pb2.SimpleResponse:
|
|
891
890
|
response = api_pb2.SimpleResponse()
|
|
892
891
|
response.success = False
|
|
893
892
|
open_client = OpenClient.get_client(request.client_id)
|
|
@@ -901,7 +900,6 @@ class Martin(api_pb2_grpc.MartinServicer):
|
|
|
901
900
|
_context.set_code(grpc.StatusCode.RESOURCE_EXHAUSTED)
|
|
902
901
|
except Exception as ex:
|
|
903
902
|
logger.error(f"TransferToMaster for {open_client.name}: {request.symbol} exception: {ex}")
|
|
904
|
-
# logger.debug(f"TransferToMaster for {open_client.name}: {request.symbol} error: {traceback.format_exc()}")
|
|
905
903
|
_context.set_details(f"{ex}")
|
|
906
904
|
_context.set_code(grpc.StatusCode.UNKNOWN)
|
|
907
905
|
else:
|
{exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/exch_srv_cfg.toml.template
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Parameters for exchanges-wrapper REST API Server exch_srv.py
|
|
2
2
|
# Copyright © 2021 Jerry Fedorenko aka VM
|
|
3
|
-
# __version__ = "1.4.
|
|
3
|
+
# __version__ = "1.4.8"
|
|
4
4
|
|
|
5
5
|
# region endpoint
|
|
6
6
|
[endpoint]
|
|
@@ -78,6 +78,14 @@
|
|
|
78
78
|
api_secret = '*********** Place secret API key there ************'
|
|
79
79
|
test_net = false
|
|
80
80
|
|
|
81
|
+
[[accounts]]
|
|
82
|
+
exchange = 'binance'
|
|
83
|
+
name = 'BinanceSub2'
|
|
84
|
+
api_key = '*********** Place API key there ************'
|
|
85
|
+
api_secret = '*********** Place secret API key there ************'
|
|
86
|
+
master_email = 'sub1@mail.com' # If set, 'BinanceSub1' use for collecting assets instead of Main
|
|
87
|
+
test_net = false
|
|
88
|
+
|
|
81
89
|
# Binance.us accounts
|
|
82
90
|
[[accounts]]
|
|
83
91
|
exchange = 'binance_us'
|
|
@@ -392,6 +392,9 @@ class BfxPrivateEventsDataStream(EventsDataStream):
|
|
|
392
392
|
event_type = msg_data[1]
|
|
393
393
|
event = msg_data[2]
|
|
394
394
|
|
|
395
|
+
# if event_type in ('os', 'on', 'ou', 'oc', 'te', 'tu'):
|
|
396
|
+
# logger.info(f"BitfinexPrivate: {event_type}: {event}")
|
|
397
|
+
|
|
395
398
|
content = None
|
|
396
399
|
if event_type in ('wu', 'ws'):
|
|
397
400
|
content = bfx.on_funds_update(event)
|
|
@@ -404,29 +407,32 @@ class BfxPrivateEventsDataStream(EventsDataStream):
|
|
|
404
407
|
order_id = event[3]
|
|
405
408
|
|
|
406
409
|
if order_id in self.client.active_orders and self.client.active_orders[order_id]["lastEvent"]:
|
|
407
|
-
if event[0]
|
|
408
|
-
self.client.
|
|
410
|
+
if event[0] not in self.client.active_orders[order_id]["eventIds"]:
|
|
411
|
+
self.client.active_order(order_id, last_event=event)
|
|
409
412
|
self.client.active_orders[order_id]['executedQty'] += Decimal(str(abs(event[4])))
|
|
410
|
-
|
|
411
|
-
self.client.
|
|
413
|
+
elif event_type == 'tu':
|
|
414
|
+
self.client.active_order(order_id, last_event=event)
|
|
412
415
|
else:
|
|
413
416
|
self.client.active_order(order_id, last_event=event)
|
|
414
417
|
self.client.active_orders[order_id]['executedQty'] += Decimal(str(abs(event[4])))
|
|
415
418
|
|
|
416
419
|
orig_qty = self.client.active_orders[order_id]['origQty']
|
|
417
420
|
executed_qty = self.client.active_orders[order_id]['executedQty']
|
|
418
|
-
if orig_qty and executed_qty < orig_qty:
|
|
421
|
+
if orig_qty and executed_qty < orig_qty and event[0] not in self.client.active_orders[order_id]["eventIds"]:
|
|
422
|
+
self.client.active_orders[order_id]["eventIds"].append(event[0])
|
|
419
423
|
content = bfx.on_order_trade(event, str(orig_qty), str(executed_qty))
|
|
420
424
|
elif oc_event := self.wss_event_buffer.pop(order_id, None):
|
|
421
425
|
content = bfx.on_order_update(oc_event, self.client.active_orders[order_id])
|
|
422
426
|
|
|
427
|
+
# logger.info(f"Active order: {order_id}: {self.client.active_orders[order_id]}")
|
|
428
|
+
|
|
423
429
|
elif event_type == 'oc':
|
|
424
430
|
order_id = event[0]
|
|
425
431
|
orig_qty = str(abs(event[7]))
|
|
426
432
|
self.client.active_order(order_id, quantity=orig_qty)
|
|
427
433
|
executed_qty = self.client.active_orders[order_id]['executedQty']
|
|
428
434
|
if 'CANCELED' in event[13] or executed_qty >= Decimal(orig_qty):
|
|
429
|
-
self.client.active_orders
|
|
435
|
+
self.client.active_orders[order_id]['cancelled'] = True
|
|
430
436
|
content = bfx.on_order_update(event, self.client.active_orders[order_id])
|
|
431
437
|
else:
|
|
432
438
|
self.wss_event_buffer[order_id] = event
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
custom: ['https://github.com/DogsTailFarmer/exchanges-wrapper#donate']
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
-
# package ecosystems to update and where the package manifests are located.
|
|
3
|
-
# Please see the documentation for all configuration options:
|
|
4
|
-
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
5
|
-
|
|
6
|
-
version: 2
|
|
7
|
-
updates:
|
|
8
|
-
- package-ecosystem: "pip" # See documentation for possible values
|
|
9
|
-
directory: "/" # Location of package manifests
|
|
10
|
-
schedule:
|
|
11
|
-
interval: "weekly"
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
name: Docker Image CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_dispatch:
|
|
5
|
-
release:
|
|
6
|
-
types: [published]
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
build:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
steps:
|
|
12
|
-
- name: Checkout
|
|
13
|
-
uses: actions/checkout@v3
|
|
14
|
-
|
|
15
|
-
- name: PrepareReg Names
|
|
16
|
-
run: |
|
|
17
|
-
echo IMAGE_REPOSITORY=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV
|
|
18
|
-
echo IMAGE_TAG=$(echo ${{ github.ref }} | tr '[:upper:]' '[:lower:]' | awk '{split($0,a,"/"); print a[3]}') >> $GITHUB_ENV
|
|
19
|
-
|
|
20
|
-
- name: Login to GHCR
|
|
21
|
-
uses: docker/login-action@v2
|
|
22
|
-
with:
|
|
23
|
-
registry: ghcr.io
|
|
24
|
-
username: ${{ github.repository_owner }}
|
|
25
|
-
password: ${{ secrets.GITHUB_TOKEN }}
|
|
26
|
-
|
|
27
|
-
- name: Build and push
|
|
28
|
-
run: |
|
|
29
|
-
docker build . --tag ghcr.io/$IMAGE_REPOSITORY:$IMAGE_TAG
|
|
30
|
-
docker push ghcr.io/$IMAGE_REPOSITORY:$IMAGE_TAG
|
|
31
|
-
docker build . --tag ghcr.io/$IMAGE_REPOSITORY:latest
|
|
32
|
-
docker push ghcr.io/$IMAGE_REPOSITORY:latest
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# This workflow will upload a Python Package using Twine when a release is created
|
|
2
|
-
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
|
|
3
|
-
|
|
4
|
-
# This workflow uses actions that are not certified by GitHub.
|
|
5
|
-
# They are provided by a third-party and are governed by
|
|
6
|
-
# separate terms of service, privacy policy, and support
|
|
7
|
-
# documentation.
|
|
8
|
-
|
|
9
|
-
name: Upload Python Package
|
|
10
|
-
|
|
11
|
-
on:
|
|
12
|
-
workflow_dispatch:
|
|
13
|
-
release:
|
|
14
|
-
types: [published]
|
|
15
|
-
|
|
16
|
-
permissions:
|
|
17
|
-
contents: read
|
|
18
|
-
|
|
19
|
-
jobs:
|
|
20
|
-
deploy:
|
|
21
|
-
|
|
22
|
-
runs-on: ubuntu-latest
|
|
23
|
-
|
|
24
|
-
steps:
|
|
25
|
-
- uses: actions/checkout@v3
|
|
26
|
-
- name: Set up Python
|
|
27
|
-
uses: actions/setup-python@v3
|
|
28
|
-
with:
|
|
29
|
-
python-version: '3.x'
|
|
30
|
-
- name: Install dependencies
|
|
31
|
-
run: |
|
|
32
|
-
python -m pip install --upgrade pip
|
|
33
|
-
pip install build
|
|
34
|
-
- name: Build package
|
|
35
|
-
run: python -m build
|
|
36
|
-
- name: Publish package
|
|
37
|
-
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
|
|
38
|
-
with:
|
|
39
|
-
user: __token__
|
|
40
|
-
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -1,398 +0,0 @@
|
|
|
1
|
-
## 1.4.7 2024-01-25
|
|
2
|
-
### Fix
|
|
3
|
-
* Bybit: filter LOT_SIZE.stepSize
|
|
4
|
-
* Bitfinex: filter LOT_SIZE.stepSize
|
|
5
|
-
|
|
6
|
-
### Added for new features
|
|
7
|
-
* Binance: new method [`OneClickArrivalDeposit`](https://binance-docs.github.io/apidocs/spot/en/#one-click-arrival-deposit-apply-for-expired-address-deposit-user_data)
|
|
8
|
-
|
|
9
|
-
### Update
|
|
10
|
-
* Bitfinex: refine the order processing
|
|
11
|
-
* Dependency: Up requirements for Python>=3.9
|
|
12
|
-
|
|
13
|
-
## v1.4.6 2024-01-06
|
|
14
|
-
### Update
|
|
15
|
-
* FetchOrder: Bitfinex: generate trades events for orders older than the last two weeks
|
|
16
|
-
|
|
17
|
-
## v1.4.5 2024-01-05
|
|
18
|
-
### Fix
|
|
19
|
-
* `exch_client.py` init error
|
|
20
|
-
|
|
21
|
-
### Update
|
|
22
|
-
* replacing json with ujson to improve performance
|
|
23
|
-
* Dependency: Up requirements for crypto-ws-api==2.0.6
|
|
24
|
-
|
|
25
|
-
## v1.4.4 2023-12-13
|
|
26
|
-
### Update
|
|
27
|
-
* Before send cancel order result checking if it was be executed and generating trade event
|
|
28
|
-
* Rollback 1.4.3
|
|
29
|
-
- Binance: in create Limit order parameters adding parameter "selfTradePreventionMode": "NONE"
|
|
30
|
-
|
|
31
|
-
## v1.4.3 2023-12-12
|
|
32
|
-
### Fix
|
|
33
|
-
* For limit order get status EXPIRED_IN_MATCH on Binance testnet #42
|
|
34
|
-
+ Binance: in create Limit order parameters adding parameter "selfTradePreventionMode": "NONE"
|
|
35
|
-
+ For method json_format.ParseDict(..., ignore_unknown_fields=True) parameter added
|
|
36
|
-
|
|
37
|
-
## v1.4.2 2023-12-11
|
|
38
|
-
### Update
|
|
39
|
-
* Some minor improvements
|
|
40
|
-
|
|
41
|
-
## v1.4.1 2023-12-01
|
|
42
|
-
### Update
|
|
43
|
-
* Bybit: fetch_ledgers(): get transfer event from Sub account to Main account on Main account
|
|
44
|
-
|
|
45
|
-
## v1.4.0 2023-11-23
|
|
46
|
-
### Update
|
|
47
|
-
* Some minor improvements
|
|
48
|
-
|
|
49
|
-
## v1.4.0rc6 2023-11-11
|
|
50
|
-
### Fix
|
|
51
|
-
* FetchOrder for Demo - ByBitSub01: BTCUSDT: 0 exception: list index out of range
|
|
52
|
-
* OKX: get ws_api endpoint from config
|
|
53
|
-
* ByBit: send and handling WSS keepalive message
|
|
54
|
-
|
|
55
|
-
## v1.4.0rc3 2023-11-01
|
|
56
|
-
### Fix
|
|
57
|
-
* websockets v12.0 raised `ConnectionClosed` exception
|
|
58
|
-
* Dependency: Up requirements for crypto-ws-api==2.0.5.post3
|
|
59
|
-
|
|
60
|
-
## v1.4.0rc1 2023-10-31
|
|
61
|
-
### Fix
|
|
62
|
-
* Bitfinex: WSS Information message processing logic adjusted
|
|
63
|
-
|
|
64
|
-
### Update
|
|
65
|
-
* Dependency: Up requirements for crypto-ws-api==2.0.5
|
|
66
|
-
* Other dependency
|
|
67
|
-
* protobuf format for:
|
|
68
|
-
+ OpenClientConnectionRequest
|
|
69
|
-
+ FetchOrderRequest
|
|
70
|
-
|
|
71
|
-
### Added for new features
|
|
72
|
-
* Bybit exchange V5 API support implemented. Supported account type is
|
|
73
|
-
[Unified Trading Account](https://testnet.bybit.com/en/help-center/article/Introduction-to-Bybit-Unified-Trading-Account),
|
|
74
|
-
for main and sub-accounts. Spot Trading only.
|
|
75
|
-
|
|
76
|
-
## v1.3.7.post4 2023-10-09
|
|
77
|
-
### Update
|
|
78
|
-
* Dependency: Up requirements for crypto-ws-api==2.0.4
|
|
79
|
-
|
|
80
|
-
## v1.3.7.post3 2023-10-05
|
|
81
|
-
### Update
|
|
82
|
-
* Dependency: Up requirements for crypto-ws-api==2.0.3.post1
|
|
83
|
-
|
|
84
|
-
## v1.3.7.post2 2023-09-30
|
|
85
|
-
### Update
|
|
86
|
-
* Dependency: Up requirements for crypto-ws-api==2.0.3
|
|
87
|
-
|
|
88
|
-
## v1.3.7.post1 2023-09-24
|
|
89
|
-
### Fix
|
|
90
|
-
* [2023-09-24 07:10:21,076: ERROR] Fetch order trades for HuobiSub2: HTUSDT exception: Client.fetch_order_trade_list()
|
|
91
|
-
missing 1 required positional argument: 'trade_id'
|
|
92
|
-
* exchanges_wrapper.huobi_parser.account_trade_list: incorrect key for `orderId`
|
|
93
|
-
|
|
94
|
-
### Update
|
|
95
|
-
* Dependency: Up requirements for crypto-ws-api==2.0.2.post1
|
|
96
|
-
|
|
97
|
-
## v1.3.7 2023-09-19
|
|
98
|
-
### Fix
|
|
99
|
-
* Bitfinex: fix 500 `Internal server error`, caused by a Nonce value sequence failure
|
|
100
|
-
|
|
101
|
-
### Update
|
|
102
|
-
* For web socket connection migrated from aiohttp.ws_connection to websockets.client
|
|
103
|
-
* Bitfinex: Implemented rate limit control for the Bitfinex REST API.
|
|
104
|
-
* Bitfinex: Refine handling of active orders
|
|
105
|
-
* OnOrderBookUpdate: change queue to LifoQueue, for get last actual order book row
|
|
106
|
-
|
|
107
|
-
### Don't fix
|
|
108
|
-
* gRPC [(grpcio + grpcio-tools)](https://github.com/grpc/grpc): massive memory leak for version later than 1.48.2
|
|
109
|
-
|
|
110
|
-
## v1.3.6b7 2023-08-20
|
|
111
|
-
### Fix
|
|
112
|
-
* The `exch_srv_cfg.toml` wants to be updated from `exch_srv_cfg.toml.template`:
|
|
113
|
-
```toml
|
|
114
|
-
[endpoint.okx]
|
|
115
|
-
api_public = 'https://aws.okx.com'
|
|
116
|
-
api_auth = 'https://aws.okx.com'
|
|
117
|
-
ws_public = 'wss://wsaws.okx.com:8443/ws/v5/public'
|
|
118
|
-
ws_auth = 'wss://wsaws.okx.com:8443/ws/v5/private'
|
|
119
|
-
ws_business = 'wss://ws.okx.com:8443/ws/v5/business'
|
|
120
|
-
api_test = 'https://aws.okx.com'
|
|
121
|
-
ws_test = 'wss://wspap.okx.com:8443/ws/v5/private?brokerId=9999'
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## v1.3.6b4 2023-08-18
|
|
125
|
-
### Fix
|
|
126
|
-
* [ Can't resolve missed PARTIALLY_FILLED event #29 ](https://github.com/DogsTailFarmer/exchanges-wrapper/issues/29#issue-1857179139)
|
|
127
|
-
* [ OKX changed WSS endpoint for Candlesticks channel #27 ](https://github.com/DogsTailFarmer/exchanges-wrapper/issues/27#issue-1852639540)
|
|
128
|
-
|
|
129
|
-
The `exch_srv_cfg.toml` wants to be updated from `exch_srv_cfg.toml.template`:
|
|
130
|
-
```toml
|
|
131
|
-
[endpoint.okx]
|
|
132
|
-
api_public = 'https://aws.okx.com'
|
|
133
|
-
api_auth = 'https://aws.okx.com'
|
|
134
|
-
ws_public = 'wss://wsaws.okx.com:8443/ws/v5/public'
|
|
135
|
-
ws_business = 'wss://ws.okx.com:8443/ws/v5/business'
|
|
136
|
-
api_test = 'https://aws.okx.com'
|
|
137
|
-
ws_test = 'wss://wspap.okx.com:8443/ws/v5/private?brokerId=9999'
|
|
138
|
-
```
|
|
139
|
-
## v1.3.5rc1 2023-08-08
|
|
140
|
-
### Update
|
|
141
|
-
* Dependency: Up requirements for crypto-ws-api~=2.0.0rc3
|
|
142
|
-
* Optimise code by [Sourcery AI](https://docs.sourcery.ai/Guides/Getting-Started/PyCharm/) refactoring engine
|
|
143
|
-
* Some minor improvements
|
|
144
|
-
|
|
145
|
-
## v1.3.5b0 - 2023-07-26
|
|
146
|
-
### Added for new features
|
|
147
|
-
* Binance, OKX: Most requests use WSS first, REST API is used as a backup and in the case of single rare requests
|
|
148
|
-
|
|
149
|
-
## v1.3.4-1 2023-07-19
|
|
150
|
-
### Fix
|
|
151
|
-
```
|
|
152
|
-
ERROR: Cannot install crypto_ws_api and grpcio==1.56.0 because these package versions have conflicting dependencies.
|
|
153
|
-
|
|
154
|
-
The conflict is caused by:
|
|
155
|
-
The user requested grpcio==1.56.0
|
|
156
|
-
exchanges-wrapper 1.3.3 depends on grpcio==1.48.1
|
|
157
|
-
The user requested grpcio==1.56.0
|
|
158
|
-
exchanges-wrapper 1.3.2 depends on grpcio==1.48.1
|
|
159
|
-
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
## v1.3.4 2023-07-17
|
|
163
|
-
### Update
|
|
164
|
-
* Up requirements for grpcio to 1.56.0
|
|
165
|
-
```bazaar
|
|
166
|
-
Known security vulnerabilities detected
|
|
167
|
-
Dependency grpcio Version < 1.53.0 Upgrade to ~> 1.53.0
|
|
168
|
-
```
|
|
169
|
-
* Bitfinex: `exchanges_wrapper.client.Client.cancel_all_orders()`: removed unnecessary status check after cancel request
|
|
170
|
-
|
|
171
|
-
## v1.3.3 2023-07-04
|
|
172
|
-
### Update
|
|
173
|
-
* UserWSSession moved to crypto-ws-api pkg
|
|
174
|
-
* Refactoring logging
|
|
175
|
-
* CheckStream(): fix log spamming on passed check
|
|
176
|
-
* Up requirements for crypto-ws-api to 1.0.1
|
|
177
|
-
|
|
178
|
-
## v1.3.2 - 2023-06-29
|
|
179
|
-
### Added for new features
|
|
180
|
-
* Binance: ws_api package implemented, last version
|
|
181
|
-
[Websocket API](https://developers.binance.com/docs/binance-trading-api/websocket_api#general-api-information)
|
|
182
|
-
used for the most commonly used methods
|
|
183
|
-
|
|
184
|
-
In `exch_srv_cfg.toml` added:
|
|
185
|
-
|
|
186
|
-
```bazaar
|
|
187
|
-
[endpoint]
|
|
188
|
-
[endpoint.binance]
|
|
189
|
-
...
|
|
190
|
-
ws_api = 'wss://ws-api.binance.com:443/ws-api/v3'
|
|
191
|
-
ws_api_test = 'wss://testnet.binance.vision/ws-api/v3'
|
|
192
|
-
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
## v1.3.1 - 2023-06-20
|
|
196
|
-
### Update
|
|
197
|
-
* Optimizing installation and initial settings
|
|
198
|
-
|
|
199
|
-
## v1.3.0-2 - 2023-06-19
|
|
200
|
-
### Update
|
|
201
|
-
* Binance: keepalive WSS
|
|
202
|
-
|
|
203
|
-
## v1.3.0 - 2023-06-01
|
|
204
|
-
### Fix
|
|
205
|
-
* exchanges_wrapper.client.Client.cancel_all_orders() set correct 'status' for cancelled orders
|
|
206
|
-
|
|
207
|
-
### Update
|
|
208
|
-
* protobuf format for CancelAllOrders() and OnOrderUpdate(). Now simple use ```result = eval(json.loads(res.result))```
|
|
209
|
-
for unpack incoming message. **Not compatible with earlier versions**
|
|
210
|
-
* dependencies
|
|
211
|
-
|
|
212
|
-
## v1.2.10-6-HotFix - 2023-04-12
|
|
213
|
-
### Fix
|
|
214
|
-
* Binance: REST API update for endpoint: GET /api/v3/exchangeInfo was changed MIN_NOTIONAL filter
|
|
215
|
-
|
|
216
|
-
## v1.2.10-5 - 2023-04-05
|
|
217
|
-
### Update
|
|
218
|
-
* Minor improvements
|
|
219
|
-
|
|
220
|
-
## v1.2.10-4 - 2023-03-04
|
|
221
|
-
### Fix
|
|
222
|
-
* OKX: intersection wss streams for several trades on one client (same account). WSS buffer moved from
|
|
223
|
-
client instance to EventsDataStream instance
|
|
224
|
-
|
|
225
|
-
## v1.2.10-3 - 2023-03-01
|
|
226
|
-
### Fix
|
|
227
|
-
* OKX: FetchOpenOrders(): getting orders list for all pair per account instead specific one pair
|
|
228
|
-
|
|
229
|
-
## v1.2.10-2 - 2023-02-26
|
|
230
|
-
### Added for new features
|
|
231
|
-
* CheckStream() method which request active WSS for trade_id
|
|
232
|
-
|
|
233
|
-
## v1.2.10 - 2023-02-22
|
|
234
|
-
### Added for new features
|
|
235
|
-
* Add method TransferToMaster():
|
|
236
|
-
|
|
237
|
-
>Send request to transfer asset from subaccount to main account
|
|
238
|
-
Binance, OKX: not additional settings needed
|
|
239
|
-
Bitfinex: for subaccount setting 2FA method, set WITHDRAWAL permission for API key,
|
|
240
|
-
in config for subaccount set 2FA key and master account EMail
|
|
241
|
-
Huobi: in config for subaccount set master_name for Main account
|
|
242
|
-
|
|
243
|
-
### Update
|
|
244
|
-
* Up requirements aiohttp to 3.8.4
|
|
245
|
-
* Some minor improvements
|
|
246
|
-
|
|
247
|
-
## v1.2.9-2 - 2023-02-04
|
|
248
|
-
### Fixed
|
|
249
|
-
* Fix DogsTailFarmer/martin-binance#50
|
|
250
|
-
|
|
251
|
-
### Update
|
|
252
|
-
* Remove unnecessary shebang
|
|
253
|
-
|
|
254
|
-
## v1.2.9-1 - 2023-01-23
|
|
255
|
-
### Update
|
|
256
|
-
* Additional check for order status if its can't place during timeout period for avoid place duplicate order
|
|
257
|
-
|
|
258
|
-
## v1.2.9 - 2023-01-08
|
|
259
|
-
### Update
|
|
260
|
-
* Removing FTX smell
|
|
261
|
-
|
|
262
|
-
## v1.2.8 - 2023-01-01
|
|
263
|
-
### Added for new features
|
|
264
|
-
* Add connection to binance.us
|
|
265
|
-
|
|
266
|
-
## v1.2.7-7 2022-12-15
|
|
267
|
-
### Fixed
|
|
268
|
-
* DogsTailFarmer/martin-binance#42
|
|
269
|
-
|
|
270
|
-
## v1.2.7-6 2022-12-08
|
|
271
|
-
### Fixed
|
|
272
|
-
* Bitfinex: handling canceled TP order after it partially filled
|
|
273
|
-
|
|
274
|
-
### Update
|
|
275
|
-
* Binance: REST API: filter type "PERCENT_PRICE" to "PERCENT_PRICE_BY_SIDE"
|
|
276
|
-
|
|
277
|
-
## v1.2.7-5 2022-12-04
|
|
278
|
-
### Update
|
|
279
|
-
* FetchOpenOrders() add handler for errors.QueryCanceled, in case RateLimitReached was raised elsewhere
|
|
280
|
-
* Some minor improvements
|
|
281
|
-
|
|
282
|
-
## v1.2.7-4 2022-11-25
|
|
283
|
-
### Fixed
|
|
284
|
-
* Clearing cancel previous wss start() before restart from 1.2.7-3 was a bad idea. It's kill himself. Rollback.
|
|
285
|
-
|
|
286
|
-
## v1.2.7-3 2022-11-24
|
|
287
|
-
### Fixed
|
|
288
|
-
* Huobi: incorrect handling for incoming ping for private channel
|
|
289
|
-
* OKX: refactoring wss heartbeat
|
|
290
|
-
* Clearing cancel previous wss start() before restart
|
|
291
|
-
|
|
292
|
-
## v1.2.7-2 2022-11-23
|
|
293
|
-
### Update
|
|
294
|
-
* Bitfinex: add "receive_timeout=30" parameter in ws_connect(), this is a reliable solution for monitoring the presence
|
|
295
|
-
of a connection
|
|
296
|
-
|
|
297
|
-
## v1.2.7-1 2022-11-21
|
|
298
|
-
### Update
|
|
299
|
-
* Add OKX section in config file
|
|
300
|
-
|
|
301
|
-
## v1.2.7 2022-11-21
|
|
302
|
-
### Added for new features
|
|
303
|
-
* OKX exchange
|
|
304
|
-
|
|
305
|
-
## v1.2.6-1 2022-11-11
|
|
306
|
-
### Fixed
|
|
307
|
-
* FTX: OnFundsUpdate() did not return a result
|
|
308
|
-
|
|
309
|
-
### Added for new features
|
|
310
|
-
* OnBalanceUpdate() for autocorrect depo and initial balance
|
|
311
|
-
|
|
312
|
-
### Update
|
|
313
|
-
* refactoring http_client module for multi exchanges purposes
|
|
314
|
-
* added _percent_price filter dummy for all parsers
|
|
315
|
-
|
|
316
|
-
## v1.2.6 2022-10-13
|
|
317
|
-
### Fixed
|
|
318
|
-
* Huobi Restart WSS for PING timeout, 20s for market and 60s for user streams
|
|
319
|
-
* Removed unnecessary refine amount/price in create_order() for Bitfinex, FTX and Huobi
|
|
320
|
-
|
|
321
|
-
## v1.2.6b1 2022-10-12
|
|
322
|
-
### Added for new features
|
|
323
|
-
* Huobi exchange
|
|
324
|
-
|
|
325
|
-
## v1.2.5-3 2022-09-26
|
|
326
|
-
### Fixed
|
|
327
|
-
* #2 FTX WS market stream lies down quietly
|
|
328
|
-
|
|
329
|
-
### Update
|
|
330
|
-
* Slightly optimized process of docker container setup and start-up
|
|
331
|
-
|
|
332
|
-
## v1.2.5-2 2022-09-23
|
|
333
|
-
### Added for new features
|
|
334
|
-
* Published as Docker image
|
|
335
|
-
|
|
336
|
-
### Update
|
|
337
|
-
* README.md add info about Docker image use
|
|
338
|
-
|
|
339
|
-
## v1.2.5-1 2022-09-21
|
|
340
|
-
### Update
|
|
341
|
-
* Restoring the closed WSS for any reason other than forced explicit shutdown
|
|
342
|
-
|
|
343
|
-
## v1.2.5 2022-09-20
|
|
344
|
-
### Update
|
|
345
|
-
* Correct max size on queue() for book WSS
|
|
346
|
-
|
|
347
|
-
## v1.2.5b0 2022-09-18
|
|
348
|
-
### Fixed
|
|
349
|
-
* [Doesn't work on bitfinex: trading rules, step_size restriction not applicable, check](https://github.com/DogsTailFarmer/martin-binance/issues/28#issue-1366945816)
|
|
350
|
-
* [FTX WS market stream lies down quietly](https://github.com/DogsTailFarmer/exchanges-wrapper/issues/2#issue-1362214342) Refactoring WSS control
|
|
351
|
-
* Keep alive Binance combined market WSS, correct restart after stop pair
|
|
352
|
-
|
|
353
|
-
### Update
|
|
354
|
-
* FetchOrder for 'PARTIALLY_FILLED' event on 'binance' and 'ftx'
|
|
355
|
-
* User data and settings config are moved outside the package to simplify the upgrade
|
|
356
|
-
* Version accounting of the configuration file is given to the package
|
|
357
|
-
|
|
358
|
-
### Added for new features
|
|
359
|
-
* Published as Docker image
|
|
360
|
-
* On first run create catalog structure for user files at ```/home/user/.MartinBinance/```
|
|
361
|
-
|
|
362
|
-
## v1.2.4 2022-08-27
|
|
363
|
-
### Fixed
|
|
364
|
-
* [Incomplete account setup](DogsTailFarmer/martin-binance#17)
|
|
365
|
-
* 1.2.3-2 Fix wss market handler, was stopped after get int type message instead of dict
|
|
366
|
-
* 1.2.3-5 clear console output
|
|
367
|
-
* 1.2.3-6 Bitfinex WSServerHandshakeError handling
|
|
368
|
-
* refactoring web_socket.py for correct handling and restart wss
|
|
369
|
-
|
|
370
|
-
### Update
|
|
371
|
-
* up to Python 3.10.6 compatible
|
|
372
|
-
* reuse aiohttp.ClientSession().ws_connect() for client session
|
|
373
|
-
|
|
374
|
-
## v1.2.3 - 2022-08-14
|
|
375
|
-
### Fixed
|
|
376
|
-
* Bitfinex: restore active orders list after restart
|
|
377
|
-
* [exch_server not exiting if it can't obtain port](https://github.com/DogsTailFarmer/martin-binance/issues/12#issue-1328603498)
|
|
378
|
-
|
|
379
|
-
## v1.2.2 - 2022-08-06
|
|
380
|
-
### Fixed
|
|
381
|
-
* Incorrect handling fetch_open_orders response after reinit connection
|
|
382
|
-
|
|
383
|
-
## v1.2.1 - 2022-08-04
|
|
384
|
-
### Added for new features
|
|
385
|
-
* FTX: WSS 'orderbook' check status by provided checksum value
|
|
386
|
-
|
|
387
|
-
### Fixed
|
|
388
|
-
* FTX: WSS 'ticker' incorrect init
|
|
389
|
-
* Bitfinex: changed priority for order status, CANCELED priority raised
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
## v1.2.0 - 2022-06-30
|
|
393
|
-
### Added for new features
|
|
394
|
-
* Bitfinex REST API / WSS implemented
|
|
395
|
-
|
|
396
|
-
### Updated
|
|
397
|
-
* Optimized WSS processing methods to improve performance and fault tolerance
|
|
398
|
-
* Updated configuration file format for multi-exchange use
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# syntax=docker/dockerfile:1
|
|
2
|
-
FROM python:3.10.6-slim
|
|
3
|
-
|
|
4
|
-
RUN useradd -ms /bin/bash appuser
|
|
5
|
-
USER appuser
|
|
6
|
-
|
|
7
|
-
ENV PATH="/home/appuser/.local/bin:${PATH}"
|
|
8
|
-
ENV PATH="/home/appuser/.local/lib/python3.10/site-packages:${PATH}"
|
|
9
|
-
ENV PYTHONUNBUFFERED=1
|
|
10
|
-
|
|
11
|
-
COPY requirements.txt requirements.txt
|
|
12
|
-
|
|
13
|
-
RUN pip3 install -r requirements.txt
|
|
14
|
-
|
|
15
|
-
COPY ./exchanges_wrapper/* /home/appuser/.local/lib/python3.10/site-packages/exchanges_wrapper/
|
|
16
|
-
|
|
17
|
-
WORKDIR "/home/appuser/.local/lib/python3.10/site-packages"
|
|
18
|
-
|
|
19
|
-
LABEL org.opencontainers.image.description="See README.md 'Get started' for setup and run package"
|
|
20
|
-
|
|
21
|
-
EXPOSE 50051
|
|
22
|
-
|
|
23
|
-
CMD ["python3","exchanges_wrapper/exch_srv.py"]
|
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
Client example for exchanges-wrapper, examples of use of server methods are given
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import asyncio
|
|
8
|
-
import toml
|
|
9
|
-
import uuid
|
|
10
|
-
import simplejson as json
|
|
11
|
-
# noinspection PyPackageRequirements
|
|
12
|
-
import grpc
|
|
13
|
-
# noinspection PyPackageRequirements
|
|
14
|
-
from google.protobuf import json_format
|
|
15
|
-
from exchanges_wrapper import api_pb2, api_pb2_grpc
|
|
16
|
-
|
|
17
|
-
# For more channel options, please see https://grpc.io/grpc/core/group__grpc__arg__keys.html
|
|
18
|
-
CHANNEL_OPTIONS = [('grpc.lb_policy_name', 'pick_first'),
|
|
19
|
-
('grpc.enable_retries', 0),
|
|
20
|
-
('grpc.keepalive_timeout_ms', 10000)]
|
|
21
|
-
RATE_LIMITER = 5
|
|
22
|
-
FILE_CONFIG = 'ms_cfg.toml'
|
|
23
|
-
config = toml.load(FILE_CONFIG)
|
|
24
|
-
EXCHANGE = config.get('exchange')
|
|
25
|
-
SYMBOL = 'BTCUSDT'
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
async def main(_exchange, _symbol):
|
|
29
|
-
print(f"main.account_name: {_exchange}")
|
|
30
|
-
# Create connection to the grpc powered server
|
|
31
|
-
channel = grpc.aio.insecure_channel(target='localhost:50051', options=CHANNEL_OPTIONS)
|
|
32
|
-
stub = api_pb2_grpc.MartinStub(channel)
|
|
33
|
-
trade_id = str(uuid.uuid4().hex)
|
|
34
|
-
client_id = None
|
|
35
|
-
# Register client and get client_id for reuse connection
|
|
36
|
-
# Example of exception handling by grpc connection
|
|
37
|
-
try:
|
|
38
|
-
client_id_msg = await stub.OpenClientConnection(api_pb2.OpenClientConnectionRequest(
|
|
39
|
-
trade_id=trade_id,
|
|
40
|
-
account_name=_exchange,
|
|
41
|
-
symbol=SYMBOL,
|
|
42
|
-
rate_limiter=RATE_LIMITER))
|
|
43
|
-
except asyncio.CancelledError:
|
|
44
|
-
pass # Task cancellation should not be logged as an error.
|
|
45
|
-
except grpc.RpcError as ex:
|
|
46
|
-
# noinspection PyUnresolvedReferences
|
|
47
|
-
status_code = ex.code()
|
|
48
|
-
# noinspection PyUnresolvedReferences
|
|
49
|
-
print(f"Exception on register client: {status_code.name}, {ex.details()}")
|
|
50
|
-
return
|
|
51
|
-
else:
|
|
52
|
-
client_id = client_id_msg.client_id
|
|
53
|
-
exchange = client_id_msg.exchange
|
|
54
|
-
print(f"main.exchange: {exchange}")
|
|
55
|
-
print(f"main.client_id: {client_id}")
|
|
56
|
-
print(f"main.srv_version: {client_id_msg.srv_version}")
|
|
57
|
-
|
|
58
|
-
# _res = await stub.OneClickArrivalDeposit(api_pb2.MarketRequest(
|
|
59
|
-
# trade_id=trade_id,
|
|
60
|
-
# client_id=client_id,
|
|
61
|
-
# symbol="place txId here"))
|
|
62
|
-
# print(json_format.MessageToDict(_res))
|
|
63
|
-
|
|
64
|
-
# Sample async call server method
|
|
65
|
-
_exchange_info_symbol = await stub.FetchExchangeInfoSymbol(api_pb2.MarketRequest(
|
|
66
|
-
trade_id=trade_id,
|
|
67
|
-
client_id=client_id,
|
|
68
|
-
symbol=_symbol))
|
|
69
|
-
# Unpack result
|
|
70
|
-
exchange_info_symbol = json_format.MessageToDict(_exchange_info_symbol)
|
|
71
|
-
print("\n".join(f"{k}\t{v}" for k, v in exchange_info_symbol.items()))
|
|
72
|
-
|
|
73
|
-
# Sample async functon call
|
|
74
|
-
open_orders = await fetch_open_orders(stub, client_id, _symbol)
|
|
75
|
-
print(f"open_orders: {open_orders}")
|
|
76
|
-
|
|
77
|
-
# Subscribe to WSS
|
|
78
|
-
# First you want to create all WSS task
|
|
79
|
-
# Market stream
|
|
80
|
-
asyncio.create_task(on_ticker_update(stub, client_id, _symbol, trade_id))
|
|
81
|
-
# User Stream
|
|
82
|
-
asyncio.create_task(on_order_update(stub, client_id, _symbol, trade_id))
|
|
83
|
-
# Other market and user methods are used similarly: OnKlinesUpdate, OnFundsUpdate, OnOrderBookUpdate
|
|
84
|
-
# Start WSS
|
|
85
|
-
# The values of market_stream_count directly depend on the number of market
|
|
86
|
-
# ws streams used in the strategy and declared above
|
|
87
|
-
await stub.StartStream(api_pb2.StartStreamRequest(
|
|
88
|
-
trade_id=trade_id,
|
|
89
|
-
client_id=client_id,
|
|
90
|
-
symbol=_symbol,
|
|
91
|
-
market_stream_count=1))
|
|
92
|
-
await asyncio.sleep(RATE_LIMITER)
|
|
93
|
-
# Before stop program call StopStream() method
|
|
94
|
-
await stub.StopStream(api_pb2.MarketRequest(trade_id=trade_id, client_id=client_id, symbol=_symbol))
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
async def on_ticker_update(_stub, _client_id, _symbol, trade_id):
|
|
98
|
-
"""
|
|
99
|
-
24hr rolling window mini-ticker statistics. Truncated sample.
|
|
100
|
-
:param trade_id:
|
|
101
|
-
:param _stub:
|
|
102
|
-
:param _client_id:
|
|
103
|
-
:param _symbol:
|
|
104
|
-
:return: {}
|
|
105
|
-
"""
|
|
106
|
-
async for ticker in _stub.OnTickerUpdate(api_pb2.MarketRequest(
|
|
107
|
-
trade_id=trade_id,
|
|
108
|
-
client_id=_client_id,
|
|
109
|
-
symbol=_symbol)):
|
|
110
|
-
ticker_24h = {'openPrice': ticker.open_price,
|
|
111
|
-
'lastPrice': ticker.close_price,
|
|
112
|
-
'closeTime': ticker.event_time}
|
|
113
|
-
print(f"on_ticker_update: {ticker.symbol} {ticker_24h}")
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
async def on_order_update(_stub, _client_id, _symbol, trade_id):
|
|
117
|
-
"""
|
|
118
|
-
Orders are updated with the executionReport event.
|
|
119
|
-
:param trade_id:
|
|
120
|
-
:param _stub:
|
|
121
|
-
:param _client_id:
|
|
122
|
-
:param _symbol:
|
|
123
|
-
:return: https://github.com/binance/binance-spot-api-docs/blob/master/user-data-stream.md#order-update
|
|
124
|
-
"""
|
|
125
|
-
async for event in _stub.OnOrderUpdate(api_pb2.MarketRequest(
|
|
126
|
-
trade_id=trade_id,
|
|
127
|
-
client_id=_client_id,
|
|
128
|
-
symbol=_symbol)):
|
|
129
|
-
print(eval(json.loads(event.result)))
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
async def on_balance_update(_stub, _client_id, _symbol, trade_id):
|
|
133
|
-
"""
|
|
134
|
-
Get data when asset transferred or withdrawal from account
|
|
135
|
-
:param _stub:
|
|
136
|
-
:param _client_id:
|
|
137
|
-
:param _symbol:
|
|
138
|
-
:param trade_id:
|
|
139
|
-
:return:
|
|
140
|
-
"""
|
|
141
|
-
async for res in _stub.OnBalanceUpdate(api_pb2.MarketRequest(
|
|
142
|
-
trade_id=trade_id,
|
|
143
|
-
client_id=_client_id,
|
|
144
|
-
symbol=_symbol)):
|
|
145
|
-
print(res.balance)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
async def fetch_open_orders(_stub, _client_id, _symbol):
|
|
149
|
-
"""
|
|
150
|
-
Get all open orders on a symbol.
|
|
151
|
-
:param _stub:
|
|
152
|
-
:param _client_id:
|
|
153
|
-
:param _symbol:
|
|
154
|
-
:return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#current-open-orders-user_data
|
|
155
|
-
"""
|
|
156
|
-
_active_orders = await _stub.FetchOpenOrders(api_pb2.MarketRequest(client_id=_client_id, symbol=_symbol))
|
|
157
|
-
active_orders = json_format.MessageToDict(_active_orders).get('items', [])
|
|
158
|
-
print(f"active_orders: {active_orders}")
|
|
159
|
-
return active_orders
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
async def fetch_order(_stub, _client_id, _symbol, _id: int, _filled_update_call: bool = False):
|
|
163
|
-
"""
|
|
164
|
-
Check an order's status.
|
|
165
|
-
:param _stub:
|
|
166
|
-
:param _client_id:
|
|
167
|
-
:param _symbol:
|
|
168
|
-
:param _id: order id
|
|
169
|
-
:param _filled_update_call: if True and order's status is 'FILLED' generated event for OnOrderUpdate user stream
|
|
170
|
-
:return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#query-order-user_data
|
|
171
|
-
"""
|
|
172
|
-
try:
|
|
173
|
-
res = await _stub.FetchOrder(api_pb2.FetchOrderRequest(
|
|
174
|
-
client_id=_client_id,
|
|
175
|
-
symbol=_symbol,
|
|
176
|
-
order_id=_id,
|
|
177
|
-
filled_update_call=_filled_update_call))
|
|
178
|
-
result = json_format.MessageToDict(res)
|
|
179
|
-
except asyncio.CancelledError:
|
|
180
|
-
pass # Task cancellation should not be logged as an error.
|
|
181
|
-
except Exception as _ex:
|
|
182
|
-
print(f"Exception in fetch_order: {_ex}")
|
|
183
|
-
return {}
|
|
184
|
-
else:
|
|
185
|
-
print(f"For order {result.get('orderId')} fetched status is {result.get('status')}")
|
|
186
|
-
return result
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
async def cancel_all_orders(_stub, _client_id, _symbol):
|
|
190
|
-
"""
|
|
191
|
-
Cancel All Open Orders on a Symbol
|
|
192
|
-
:param _stub:
|
|
193
|
-
:param _client_id:
|
|
194
|
-
:param _symbol:
|
|
195
|
-
:return:
|
|
196
|
-
https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#cancel-all-open-orders-on-a-symbol-trade
|
|
197
|
-
"""
|
|
198
|
-
res = await _stub.CancelAllOrders(api_pb2.MarketRequest(
|
|
199
|
-
client_id=_client_id,
|
|
200
|
-
symbol=_symbol))
|
|
201
|
-
result = eval(json.loads(res.result))
|
|
202
|
-
print(f"cancel_all_orders.result: {result}")
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
async def fetch_account_information(_stub, _client_id):
|
|
206
|
-
"""
|
|
207
|
-
Account information (USER_DATA)
|
|
208
|
-
:param _stub:
|
|
209
|
-
:param _client_id:
|
|
210
|
-
:return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#account-information-user_data
|
|
211
|
-
"""
|
|
212
|
-
try:
|
|
213
|
-
res = await _stub.FetchAccountInformation(api_pb2.OpenClientConnectionId(client_id=_client_id))
|
|
214
|
-
except asyncio.CancelledError:
|
|
215
|
-
pass
|
|
216
|
-
except Exception as _ex:
|
|
217
|
-
print(f"Exception fetch_account_information: {_ex}")
|
|
218
|
-
else:
|
|
219
|
-
balances = json_format.MessageToDict(res).get('balances', [])
|
|
220
|
-
print(f"fetch_account_information.balances: {balances}")
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
async def fetch_funding_wallet(_stub, _client_id):
|
|
224
|
-
"""
|
|
225
|
-
Get balances from Funding wallet for Binance and assets from 'main' account for FTX
|
|
226
|
-
:param _stub:
|
|
227
|
-
:param _client_id:
|
|
228
|
-
:return: https://binance-docs.github.io/apidocs/spot/en/#funding-wallet-user_data
|
|
229
|
-
"""
|
|
230
|
-
try:
|
|
231
|
-
res = await _stub.FetchFundingWallet(api_pb2.FetchFundingWalletRequest(
|
|
232
|
-
client_id=_client_id))
|
|
233
|
-
except asyncio.CancelledError:
|
|
234
|
-
pass
|
|
235
|
-
except Exception as _ex:
|
|
236
|
-
print(f"fetch_funding_wallet: {_ex}")
|
|
237
|
-
else:
|
|
238
|
-
funding_wallet = json_format.MessageToDict(res).get('balances', [])
|
|
239
|
-
print(f"fetch_funding_wallet.funding_wallet: {funding_wallet}")
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
async def fetch_order_book(_stub, _client_id, _symbol):
|
|
243
|
-
"""
|
|
244
|
-
Get order book, limit=5
|
|
245
|
-
:param _stub:
|
|
246
|
-
:param _client_id:
|
|
247
|
-
:param _symbol:
|
|
248
|
-
:return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#order-book
|
|
249
|
-
"""
|
|
250
|
-
_order_book = await _stub.FetchOrderBook(api_pb2.MarketRequest(
|
|
251
|
-
client_id=_client_id,
|
|
252
|
-
symbol=_symbol))
|
|
253
|
-
order_book = json_format.MessageToDict(_order_book)
|
|
254
|
-
print(f"fetch_order_book.order_book: {order_book}")
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
async def fetch_symbol_price_ticker(_stub, _client_id, _symbol):
|
|
258
|
-
"""
|
|
259
|
-
Get symbol price ticker
|
|
260
|
-
:param _stub:
|
|
261
|
-
:param _client_id:
|
|
262
|
-
:param _symbol:
|
|
263
|
-
:return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#symbol-price-ticker
|
|
264
|
-
"""
|
|
265
|
-
_price = await _stub.FetchSymbolPriceTicker(api_pb2.MarketRequest(
|
|
266
|
-
client_id=_client_id,
|
|
267
|
-
symbol=_symbol))
|
|
268
|
-
price = json_format.MessageToDict(_price)
|
|
269
|
-
print(f"fetch_symbol_price_ticker.price: {price}")
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
async def fetch_ticker_price_change_statistics(_stub, _client_id, _symbol):
|
|
273
|
-
"""
|
|
274
|
-
24hr ticker price change statistics
|
|
275
|
-
:param _stub:
|
|
276
|
-
:param _client_id:
|
|
277
|
-
:param _symbol:
|
|
278
|
-
:return:
|
|
279
|
-
https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#24hr-ticker-price-change-statistics
|
|
280
|
-
"""
|
|
281
|
-
_ticker = await _stub.FetchTickerPriceChangeStatistics(api_pb2.MarketRequest(
|
|
282
|
-
client_id=_client_id,
|
|
283
|
-
symbol=_symbol))
|
|
284
|
-
ticker = json_format.MessageToDict(_ticker)
|
|
285
|
-
print(f"fetch_ticker_price_change_statistics.ticker: {ticker}")
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
async def fetch_klines(_stub, _client_id, _symbol, _interval, _limit):
|
|
289
|
-
"""
|
|
290
|
-
Kline/candlestick bars for a symbol. Klines are uniquely identified by their open time.
|
|
291
|
-
:param _stub:
|
|
292
|
-
:param _client_id:
|
|
293
|
-
:param _symbol:
|
|
294
|
-
:param _interval: ENUM https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#enum-definitions
|
|
295
|
-
:param _limit: Default 500; max 1000.
|
|
296
|
-
:return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#klinecandlestick-data
|
|
297
|
-
"""
|
|
298
|
-
res = await _stub.FetchKlines(api_pb2.FetchKlinesRequest(
|
|
299
|
-
client_id=_client_id,
|
|
300
|
-
symbol=_symbol,
|
|
301
|
-
interval=_interval,
|
|
302
|
-
limit=_limit))
|
|
303
|
-
kline = json_format.MessageToDict(res)
|
|
304
|
-
print(f"fetch_klines.kline: {kline}")
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
async def fetch_account_trade_list(_stub, _client_id, _symbol, _limit, _start_time_ms):
|
|
308
|
-
"""
|
|
309
|
-
Get trades for a specific account and symbol.
|
|
310
|
-
:param _stub:
|
|
311
|
-
:param _client_id:
|
|
312
|
-
:param _symbol:
|
|
313
|
-
:param _limit: int: Default 500; max 1000
|
|
314
|
-
:param _start_time_ms: int: optional, minimum time of fills to return, in Unix time (ms since 1970-01-01)
|
|
315
|
-
:return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#account-trade-list-user_data
|
|
316
|
-
"""
|
|
317
|
-
_trades = await _stub.FetchAccountTradeList(api_pb2.AccountTradeListRequest(
|
|
318
|
-
client_id=_client_id,
|
|
319
|
-
symbol=_symbol,
|
|
320
|
-
limit=_limit,
|
|
321
|
-
start_time=_start_time_ms)
|
|
322
|
-
)
|
|
323
|
-
trades = json_format.MessageToDict(_trades).get('items', [])
|
|
324
|
-
print(f"fetch_account_trade_list.trades: {trades}")
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
# noinspection PyUnresolvedReferences
|
|
328
|
-
async def transfer2master(_stub, symbol: str, amount: str):
|
|
329
|
-
"""
|
|
330
|
-
Send request to transfer asset from subaccount to main account
|
|
331
|
-
Binance, OKX: not additional settings needed
|
|
332
|
-
Bitfinex: for subaccount setting 2FA method, set WITHDRAWAL permission for API key,
|
|
333
|
-
in config for subaccount set 2FA key and master account EMail
|
|
334
|
-
Huobi: in config for subaccount set master_name for Main account
|
|
335
|
-
:param _stub:
|
|
336
|
-
:param symbol:
|
|
337
|
-
:param amount:
|
|
338
|
-
:return:
|
|
339
|
-
"""
|
|
340
|
-
try:
|
|
341
|
-
res = await _stub.TransferToMaster(api_pb2.MarketRequest, symbol=symbol, amount=amount)
|
|
342
|
-
except asyncio.CancelledError:
|
|
343
|
-
pass # Task cancellation should not be logged as an error
|
|
344
|
-
except grpc.RpcError as ex:
|
|
345
|
-
status_code = ex.code()
|
|
346
|
-
print(f"Exception transfer {symbol} to main account: {status_code.name}, {ex.details()}")
|
|
347
|
-
except Exception as _ex:
|
|
348
|
-
print(f"Exception transfer {symbol} to main account: {_ex}")
|
|
349
|
-
else:
|
|
350
|
-
if res.success:
|
|
351
|
-
print(f"Sent {amount} {symbol} to main account")
|
|
352
|
-
else:
|
|
353
|
-
print(f"Not sent {amount} {symbol} to main account\n,{res.result}")
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
# Server exception handling example for methods where it's realized
|
|
357
|
-
# noinspection PyUnresolvedReferences
|
|
358
|
-
async def create_limit_order(_stub, _client_id, _symbol, _id: int, buy: bool, amount: str, price: str):
|
|
359
|
-
"""
|
|
360
|
-
Send in a new Limit order.
|
|
361
|
-
:param _stub:
|
|
362
|
-
:param _client_id:
|
|
363
|
-
:param _symbol:
|
|
364
|
-
:param _id: A unique id among open orders. Automatically generated if not sent
|
|
365
|
-
:param buy: True id BUY_side else False
|
|
366
|
-
:param amount: Base asset quantity
|
|
367
|
-
:param price:
|
|
368
|
-
:return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#new-order--trade
|
|
369
|
-
"""
|
|
370
|
-
try:
|
|
371
|
-
res = await _stub.CreateLimitOrder(api_pb2.CreateLimitOrderRequest(
|
|
372
|
-
client_id=_client_id,
|
|
373
|
-
symbol=_symbol,
|
|
374
|
-
buy_side=buy,
|
|
375
|
-
quantity=amount,
|
|
376
|
-
price=price,
|
|
377
|
-
new_client_order_id=_id
|
|
378
|
-
))
|
|
379
|
-
result = json_format.MessageToDict(res)
|
|
380
|
-
except asyncio.CancelledError:
|
|
381
|
-
pass # Task cancellation should not be logged as an error
|
|
382
|
-
except grpc.RpcError as ex:
|
|
383
|
-
status_code = ex.code()
|
|
384
|
-
print(f"Exception creating order {_id}: {status_code.name}, {ex.details()}")
|
|
385
|
-
if status_code == grpc.StatusCode.FAILED_PRECONDITION:
|
|
386
|
-
print("Do something. See except declare in exch_srv.CreateLimitOrder()")
|
|
387
|
-
except Exception as _ex:
|
|
388
|
-
print(f"Exception creating order {_id}: {_ex}")
|
|
389
|
-
else:
|
|
390
|
-
print(f"create_limit_order.result: {result}")
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
# Server exception handling example for methods where it's realized
|
|
394
|
-
# noinspection PyUnresolvedReferences
|
|
395
|
-
async def cancel_order(_stub, _client_id, _symbol, _id: int):
|
|
396
|
-
"""
|
|
397
|
-
Cancel an active order.
|
|
398
|
-
:param _stub:
|
|
399
|
-
:param _client_id:
|
|
400
|
-
:param _symbol:
|
|
401
|
-
:param _id: exchange order id
|
|
402
|
-
:return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#cancel-order-trade
|
|
403
|
-
"""
|
|
404
|
-
try:
|
|
405
|
-
res = await _stub.CancelOrder(api_pb2.CancelOrderRequest(
|
|
406
|
-
client_id=_client_id,
|
|
407
|
-
symbol=_symbol,
|
|
408
|
-
order_id=_id))
|
|
409
|
-
result = json_format.MessageToDict(res)
|
|
410
|
-
except asyncio.CancelledError:
|
|
411
|
-
pass # Task cancellation should not be logged as an error.
|
|
412
|
-
except grpc.RpcError as ex:
|
|
413
|
-
status_code = ex.code()
|
|
414
|
-
print(f"Exception on cancel order for {_id}: {status_code.name}, {ex.details()}")
|
|
415
|
-
except Exception as _ex:
|
|
416
|
-
print(f"Exception on cancel order call for {_id}:\n{_ex}")
|
|
417
|
-
else:
|
|
418
|
-
print(f"Cancel order {_id} success: {result}")
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
if __name__ == "__main__":
|
|
422
|
-
asyncio.run(main(EXCHANGE, SYMBOL))
|
|
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
|