exchanges-wrapper 2.1.13__tar.gz → 2.1.15__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/PKG-INFO +1 -2
  2. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/__init__.py +1 -1
  3. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/client.py +46 -36
  4. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/exch_srv.py +18 -0
  5. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/martin/__init__.py +36 -0
  6. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/bybit_parser.py +0 -3
  7. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/proto/martin.proto +2 -0
  8. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/pyproject.toml +0 -1
  9. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/LICENSE.md +0 -0
  10. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/README.md +0 -0
  11. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/definitions.py +0 -0
  12. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/errors.py +0 -0
  13. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/events.py +0 -0
  14. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/exch_srv_cfg.toml.template +0 -0
  15. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/http_client.py +0 -0
  16. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/lib.py +0 -0
  17. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/bitfinex_parser.py +0 -0
  18. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/huobi_parser.py +0 -0
  19. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/okx_parser.py +0 -0
  20. {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/web_sockets.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: exchanges-wrapper
3
- Version: 2.1.13
3
+ Version: 2.1.15
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
@@ -16,7 +16,6 @@ Requires-Dist: grpcio==1.62.0
16
16
  Requires-Dist: pyotp~=2.9.0
17
17
  Requires-Dist: simplejson==3.19.2
18
18
  Requires-Dist: aiohttp==3.9.5
19
- Requires-Dist: Pympler~=1.0.1
20
19
  Requires-Dist: websockets~=12.0
21
20
  Requires-Dist: expiringdict~=1.2.2
22
21
  Requires-Dist: ujson~=5.10.0
@@ -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__ = "2.1.13"
15
+ __version__ = "2.1.15"
16
16
 
17
17
  from pathlib import Path
18
18
  import shutil
@@ -493,24 +493,24 @@ class Client:
493
493
  uid=self.account_uid
494
494
  )
495
495
 
496
- params.pop('status')
497
- params['accountType'] = 'UNIFIED'
498
- params['category'] = 'spot'
499
- params['type'] = 'TRANSFER_IN'
500
-
501
- # Get Transaction Log
502
- res, ts = await self.http.send_api_call(
503
- "/v5/account/transaction-log",
504
- signed=True,
505
- **params
506
- )
507
-
508
- _res += bbt.on_balance_update(
509
- res['list'],
510
- ts,
511
- symbol,
512
- 'log'
513
- )
496
+ if not _res:
497
+ # Get Transaction Log
498
+ params.pop('status')
499
+ params['accountType'] = 'UNIFIED'
500
+ params['category'] = 'spot'
501
+ params['type'] = 'TRANSFER_IN'
502
+
503
+ res, ts = await self.http.send_api_call(
504
+ "/v5/account/transaction-log",
505
+ signed=True,
506
+ **params
507
+ )
508
+ _res += bbt.on_balance_update(
509
+ res['list'],
510
+ ts,
511
+ symbol,
512
+ 'log'
513
+ )
514
514
 
515
515
  for i in _res:
516
516
  _id = next(iter(i))
@@ -703,7 +703,8 @@ class Client:
703
703
  # https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#symbol-price-ticker
704
704
  async def fetch_symbol_price_ticker(self, symbol=None):
705
705
  if symbol:
706
- self.assert_symbol_exists(symbol)
706
+ if not (self.exchange == 'binance' and symbol == 'BNBUSDT'):
707
+ self.assert_symbol_exists(symbol)
707
708
  binance_res = {}
708
709
  elif self.exchange in ('bitfinex', 'huobi'):
709
710
  raise ValueError('For fetch_symbol_price_ticker() symbol parameter required')
@@ -1603,25 +1604,34 @@ class Client:
1603
1604
  binance_res = bbt.funding_wallet(res["balance"])
1604
1605
  return binance_res
1605
1606
 
1607
+ # https://developers.binance.com/docs/sub_account/asset-management/Transfer-to-Sub-account-of-Same-Master
1608
+ async def transfer_to_sub(self, email, symbol, quantity, receive_window=None):
1609
+ if self.exchange == 'binance':
1610
+ quantity = any2str(Decimal(quantity).quantize(Decimal('0.01234567'), rounding=ROUND_HALF_DOWN))
1611
+ params = {"toEmail": email, "asset": symbol, "amount": quantity}
1612
+ if receive_window:
1613
+ params["recvWindow"] = receive_window
1614
+ return await self.http.send_api_call(
1615
+ "/sapi/v1/sub-account/transfer/subToSub",
1616
+ "POST",
1617
+ signed=True,
1618
+ params=params
1619
+ )
1620
+ else:
1621
+ raise ValueError(f"Can't implemented for {self.exchange}")
1622
+
1606
1623
  # https://binance-docs.github.io/apidocs/spot/en/#transfer-to-master-for-sub-account
1607
1624
  async def transfer_to_master(self, symbol, quantity, receive_window=None):
1608
- quantity = any2str(Decimal(quantity).quantize(Decimal('0.01234567'), rounding=ROUND_HALF_DOWN))
1609
-
1625
+ _quantity = any2str(Decimal(quantity).quantize(Decimal('0.01234567'), rounding=ROUND_HALF_DOWN))
1610
1626
  binance_res = {}
1611
1627
  if self.exchange == 'binance':
1612
- params = {"asset": symbol, "amount": quantity}
1613
- if receive_window:
1614
- params["recvWindow"] = receive_window
1615
1628
  if self.master_email:
1616
- logger.info(f"Collect {quantity}{symbol} to {self.master_email} sub-account")
1617
- params["toEmail"] = self.master_email
1618
- binance_res = await self.http.send_api_call(
1619
- "/sapi/v1/sub-account/transfer/subToSub",
1620
- "POST",
1621
- signed=True,
1622
- params=params
1623
- )
1629
+ logger.info(f"Collect {_quantity}{symbol} to {self.master_email} sub-account")
1630
+ binance_res = await self.transfer_to_sub(self.master_email, symbol, quantity, receive_window)
1624
1631
  else:
1632
+ params = {"asset": symbol, "amount": _quantity}
1633
+ if receive_window:
1634
+ params["recvWindow"] = receive_window
1625
1635
  binance_res = await self.http.send_api_call(
1626
1636
  "/sapi/v1/sub-account/transfer/subToMaster",
1627
1637
  "POST",
@@ -1636,7 +1646,7 @@ class Client:
1636
1646
  "from": "exchange",
1637
1647
  "to": "exchange",
1638
1648
  "currency": symbol,
1639
- "amount": quantity,
1649
+ "amount": _quantity,
1640
1650
  "email_dst": self.master_email,
1641
1651
  "tfaToken": {"method": "otp", "token": totp.now()}
1642
1652
  }
@@ -1658,7 +1668,7 @@ class Client:
1658
1668
  'to-account-type': "spot",
1659
1669
  'to-account': self.main_account_id,
1660
1670
  'currency': symbol.lower(),
1661
- 'amount': quantity
1671
+ 'amount': _quantity
1662
1672
  }
1663
1673
  res = await self.http.send_api_call(
1664
1674
  "v1/account/transfer",
@@ -1670,7 +1680,7 @@ class Client:
1670
1680
  elif self.exchange == 'okx':
1671
1681
  params = {
1672
1682
  "ccy": symbol,
1673
- "amt": quantity,
1683
+ "amt": _quantity,
1674
1684
  "from": '18',
1675
1685
  "to": '18',
1676
1686
  "type": '3'
@@ -1692,7 +1702,7 @@ class Client:
1692
1702
  params = {
1693
1703
  'transferId': str(uuid.uuid4()),
1694
1704
  'coin': symbol,
1695
- 'amount': str(math.floor(float(quantity) * 10 ** n) / 10 ** n),
1705
+ 'amount': str(math.floor(float(_quantity) * 10 ** n) / 10 ** n),
1696
1706
  'fromMemberId': self.account_uid,
1697
1707
  'toMemberId': self.main_account_uid,
1698
1708
  'fromAccountType': 'UNIFIED',
@@ -767,6 +767,24 @@ class Martin(mr.MartinBase):
767
767
  response.from_pydict(res)
768
768
  return response
769
769
 
770
+ async def transfer_to_sub(self, request: mr.MarketRequest) -> mr.SimpleResponse:
771
+ response = mr.SimpleResponse()
772
+ response.success = False
773
+
774
+ res, _, _ = await self.send_request(
775
+ 'transfer_to_sub',
776
+ request,
777
+ rate_limit=True,
778
+ email=request.data,
779
+ symbol=request.symbol,
780
+ quantity=request.amount
781
+ )
782
+
783
+ if res and res.get("txnId"):
784
+ response.success = True
785
+ response.result = json.dumps(res)
786
+ return response
787
+
770
788
  async def transfer_to_master(self, request: mr.MarketRequest) -> mr.SimpleResponse:
771
789
  response = mr.SimpleResponse()
772
790
  response.success = False
@@ -407,6 +407,7 @@ class MarketRequest(betterproto.Message):
407
407
  trade_id: str = betterproto.string_field(2)
408
408
  symbol: str = betterproto.string_field(3)
409
409
  amount: str = betterproto.string_field(4)
410
+ data: str = betterproto.string_field(5)
410
411
 
411
412
 
412
413
  @dataclass(eq=False, repr=False)
@@ -916,6 +917,23 @@ class MartinStub(betterproto.ServiceStub):
916
917
  metadata=metadata,
917
918
  )
918
919
 
920
+ async def transfer_to_sub(
921
+ self,
922
+ market_request: "MarketRequest",
923
+ *,
924
+ timeout: Optional[float] = None,
925
+ deadline: Optional["Deadline"] = None,
926
+ metadata: Optional["MetadataLike"] = None
927
+ ) -> "SimpleResponse":
928
+ return await self._unary_unary(
929
+ "/martin.Martin/TransferToSub",
930
+ market_request,
931
+ SimpleResponse,
932
+ timeout=timeout,
933
+ deadline=deadline,
934
+ metadata=metadata,
935
+ )
936
+
919
937
 
920
938
  class MartinBase(ServiceBase):
921
939
 
@@ -1056,6 +1074,11 @@ class MartinBase(ServiceBase):
1056
1074
  ) -> "SimpleResponse":
1057
1075
  raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
1058
1076
 
1077
+ async def transfer_to_sub(
1078
+ self, market_request: "MarketRequest"
1079
+ ) -> "SimpleResponse":
1080
+ raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
1081
+
1059
1082
  async def __rpc_cancel_all_orders(
1060
1083
  self, stream: "grpclib.server.Stream[MarketRequest, SimpleResponse]"
1061
1084
  ) -> None:
@@ -1270,6 +1293,13 @@ class MartinBase(ServiceBase):
1270
1293
  response = await self.transfer_to_master(request)
1271
1294
  await stream.send_message(response)
1272
1295
 
1296
+ async def __rpc_transfer_to_sub(
1297
+ self, stream: "grpclib.server.Stream[MarketRequest, SimpleResponse]"
1298
+ ) -> None:
1299
+ request = await stream.recv_message()
1300
+ response = await self.transfer_to_sub(request)
1301
+ await stream.send_message(response)
1302
+
1273
1303
  def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
1274
1304
  return {
1275
1305
  "/martin.Martin/CancelAllOrders": grpclib.const.Handler(
@@ -1434,4 +1464,10 @@ class MartinBase(ServiceBase):
1434
1464
  MarketRequest,
1435
1465
  SimpleResponse,
1436
1466
  ),
1467
+ "/martin.Martin/TransferToSub": grpclib.const.Handler(
1468
+ self.__rpc_transfer_to_sub,
1469
+ grpclib.const.Cardinality.UNARY_UNARY,
1470
+ MarketRequest,
1471
+ SimpleResponse,
1472
+ ),
1437
1473
  }
@@ -452,7 +452,6 @@ def on_balance_update(data_in: list, ts: str, symbol: str, mode: str, uid=None)
452
452
  }
453
453
  }
454
454
  )
455
-
456
455
  elif mode == 'universal':
457
456
  for i in data_in:
458
457
  if i['coin'] in symbol and \
@@ -469,7 +468,6 @@ def on_balance_update(data_in: list, ts: str, symbol: str, mode: str, uid=None)
469
468
  }
470
469
  }
471
470
  )
472
-
473
471
  elif mode == 'log':
474
472
  for i in data_in:
475
473
  if i['currency'] in symbol:
@@ -484,7 +482,6 @@ def on_balance_update(data_in: list, ts: str, symbol: str, mode: str, uid=None)
484
482
  }
485
483
  }
486
484
  )
487
-
488
485
  return data_out
489
486
 
490
487
 
@@ -38,6 +38,7 @@ service Martin {
38
38
  rpc StartStream (StartStreamRequest) returns (SimpleResponse) {}
39
39
  rpc StopStream (MarketRequest) returns (SimpleResponse) {}
40
40
  rpc TransferToMaster(MarketRequest) returns (SimpleResponse) {}
41
+ rpc TransferToSub(MarketRequest) returns (SimpleResponse) {}
41
42
  }
42
43
 
43
44
  message JSONResponse {
@@ -368,6 +369,7 @@ message MarketRequest {
368
369
  string trade_id = 2;
369
370
  string symbol = 3;
370
371
  string amount = 4;
372
+ string data = 5;
371
373
  }
372
374
 
373
375
  message StartStreamRequest {
@@ -22,7 +22,6 @@ dependencies = [
22
22
  "pyotp~=2.9.0",
23
23
  "simplejson==3.19.2",
24
24
  "aiohttp==3.9.5",
25
- "Pympler~=1.0.1",
26
25
  "websockets~=12.0",
27
26
  "expiringdict~=1.2.2",
28
27
  "ujson~=5.10.0",