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.
Files changed (32) hide show
  1. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/PKG-INFO +1 -1
  2. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/__init__.py +1 -1
  3. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/bybit_parser.py +1 -1
  4. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/client.py +34 -23
  5. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/exch_srv.py +10 -12
  6. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/exch_srv_cfg.toml.template +9 -1
  7. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/web_sockets.py +12 -6
  8. exchanges-wrapper-1.4.7/.deepsource.toml +0 -12
  9. exchanges-wrapper-1.4.7/.dockerignore +0 -3
  10. exchanges-wrapper-1.4.7/.github/FUNDING.yml +0 -1
  11. exchanges-wrapper-1.4.7/.github/dependabot.yml +0 -11
  12. exchanges-wrapper-1.4.7/.github/workflows/docker-image.yml +0 -32
  13. exchanges-wrapper-1.4.7/.github/workflows/python-publish.yml +0 -40
  14. exchanges-wrapper-1.4.7/CHANGELOG.md +0 -398
  15. exchanges-wrapper-1.4.7/Dockerfile +0 -23
  16. exchanges-wrapper-1.4.7/example/exch_client.py +0 -422
  17. exchanges-wrapper-1.4.7/example/ms_cfg.toml +0 -5
  18. exchanges-wrapper-1.4.7/requirements.txt +0 -12
  19. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/LICENSE.md +0 -0
  20. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/README.md +0 -0
  21. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/api_pb2.py +0 -0
  22. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/api_pb2_grpc.py +0 -0
  23. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/bitfinex_parser.py +0 -0
  24. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/c_structures.py +0 -0
  25. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/definitions.py +0 -0
  26. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/errors.py +0 -0
  27. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/events.py +0 -0
  28. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/http_client.py +0 -0
  29. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/huobi_parser.py +0 -0
  30. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/okx_parser.py +0 -0
  31. {exchanges-wrapper-1.4.7 → exchanges_wrapper-1.4.8}/exchanges_wrapper/proto/exchanges_wrapper/api.proto +0 -0
  32. {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.7
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.7"
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*2)
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 last_event is None:
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, # trade_event: list
229
+ 'lastEvent': last_event if last_event else [],
230
+ 'eventIds': [],
234
231
  'cancelled': False
235
232
  }
236
- if last_event:
237
- self.active_orders[order_id].update({'lastEvent': last_event})
233
+ elif last_event is not None:
234
+ self.active_orders[order_id]['lastEvent'] = last_event
238
235
 
239
- def active_orders_clear(self, active_orders: list = None):
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 = {key: val for key, val in self.active_orders.items() if val['lifeTime'] > ts}
242
- for order_id in active_orders:
243
- self.active_orders[order_id]['lifeTime'] = ts + 60 * STATUS_TIMEOUT
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], quote=False):
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 quote else (amount - amount % step_size), precision))
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
- binance_res = await self.http.send_api_call(
1596
- "/sapi/v1/sub-account/transfer/subToMaster",
1597
- "POST",
1598
- params=params,
1599
- signed=True
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
- if order_id in client.active_orders:
296
- client.active_orders[order_id]['executedQty'] = Decimal(order['executedQty'])
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(active_orders)
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') != '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(self, request: api_pb2.MarketRequest,
890
- _context: grpc.aio.ServicerContext) -> api_pb2.SimpleResponse:
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:
@@ -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.0"
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] > self.client.active_orders[order_id]["lastEvent"][0]:
408
- self.client.active_orders[order_id].update({'lastEvent': event})
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
- if event_type == 'tu':
411
- self.client.active_orders[order_id].update({'lastEvent': event})
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.get(order_id, {}).update({'cancelled': True})
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,12 +0,0 @@
1
- version = 1
2
-
3
- exclude_patterns = ["*/api*.*",
4
- ]
5
-
6
- [[analyzers]]
7
- name = "python"
8
- enabled = true
9
-
10
- [analyzers.meta]
11
- runtime_version = "3.x.x"
12
- max_line_length = 120
@@ -1,3 +0,0 @@
1
- **/__pycache__/
2
- exchanges_wrapper/exchanges_wrapper/
3
- exchanges_wrapper/proto/
@@ -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))
@@ -1,5 +0,0 @@
1
- # Example parameters for exchanges_wrapper/exch_client.py
2
- # Accounts name wold be identically accounts.name from exch_srv_cfg.toml
3
- # exchange = "Demo - Binance"
4
- exchange = "Demo - Bitfinex"
5
- # exchange = "Demo - OKX"
@@ -1,12 +0,0 @@
1
- crypto-ws-api==2.0.6
2
- grpcio==1.48.2
3
- grpcio-tools==1.48.2
4
- idna==3.4
5
- pyotp==2.9.0
6
- simplejson==3.19.2
7
- toml~=0.10.2
8
- aiohttp==3.9.0
9
- Pympler~=1.0.1
10
- websockets==12.0
11
- expiringdict~=1.2.2
12
- ujson~=5.9.0