ccxt 4.4.86__py2.py3-none-any.whl → 4.4.87__py2.py3-none-any.whl

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 (56) hide show
  1. ccxt/__init__.py +5 -1
  2. ccxt/abstract/modetrade.py +119 -0
  3. ccxt/abstract/okxus.py +349 -0
  4. ccxt/async_support/__init__.py +5 -1
  5. ccxt/async_support/base/exchange.py +5 -5
  6. ccxt/async_support/binance.py +1 -1
  7. ccxt/async_support/bitteam.py +31 -0
  8. ccxt/async_support/coinmetro.py +3 -0
  9. ccxt/async_support/gate.py +91 -73
  10. ccxt/async_support/htx.py +10 -8
  11. ccxt/async_support/hyperliquid.py +32 -16
  12. ccxt/async_support/kraken.py +5 -8
  13. ccxt/async_support/modetrade.py +2727 -0
  14. ccxt/async_support/okx.py +90 -3
  15. ccxt/async_support/okxus.py +54 -0
  16. ccxt/async_support/paradex.py +4 -1
  17. ccxt/async_support/phemex.py +4 -6
  18. ccxt/async_support/poloniex.py +172 -159
  19. ccxt/async_support/probit.py +18 -47
  20. ccxt/async_support/timex.py +5 -10
  21. ccxt/async_support/vertex.py +3 -4
  22. ccxt/async_support/whitebit.py +41 -11
  23. ccxt/async_support/woo.py +101 -75
  24. ccxt/async_support/woofipro.py +25 -20
  25. ccxt/async_support/xt.py +31 -41
  26. ccxt/base/exchange.py +12 -9
  27. ccxt/binance.py +1 -1
  28. ccxt/bitteam.py +31 -0
  29. ccxt/coinmetro.py +3 -0
  30. ccxt/gate.py +91 -73
  31. ccxt/htx.py +10 -8
  32. ccxt/hyperliquid.py +32 -16
  33. ccxt/kraken.py +5 -8
  34. ccxt/modetrade.py +2727 -0
  35. ccxt/okx.py +90 -3
  36. ccxt/okxus.py +54 -0
  37. ccxt/paradex.py +4 -1
  38. ccxt/phemex.py +4 -6
  39. ccxt/poloniex.py +172 -159
  40. ccxt/pro/__init__.py +61 -1
  41. ccxt/pro/modetrade.py +1271 -0
  42. ccxt/pro/okxus.py +38 -0
  43. ccxt/probit.py +18 -47
  44. ccxt/test/tests_async.py +17 -1
  45. ccxt/test/tests_sync.py +17 -1
  46. ccxt/timex.py +5 -10
  47. ccxt/vertex.py +3 -4
  48. ccxt/whitebit.py +41 -11
  49. ccxt/woo.py +100 -75
  50. ccxt/woofipro.py +24 -20
  51. ccxt/xt.py +31 -41
  52. {ccxt-4.4.86.dist-info → ccxt-4.4.87.dist-info}/METADATA +18 -6
  53. {ccxt-4.4.86.dist-info → ccxt-4.4.87.dist-info}/RECORD +56 -48
  54. {ccxt-4.4.86.dist-info → ccxt-4.4.87.dist-info}/LICENSE.txt +0 -0
  55. {ccxt-4.4.86.dist-info → ccxt-4.4.87.dist-info}/WHEEL +0 -0
  56. {ccxt-4.4.86.dist-info → ccxt-4.4.87.dist-info}/top_level.txt +0 -0
ccxt/async_support/okx.py CHANGED
@@ -7,7 +7,7 @@ from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.okx import ImplicitAPI
8
8
  import asyncio
9
9
  import hashlib
10
- from ccxt.base.types import Account, Any, Balances, BorrowInterest, Conversion, CrossBorrowRate, CrossBorrowRates, Currencies, Currency, DepositAddress, Greeks, Int, LedgerEntry, Leverage, LeverageTier, LongShortRatio, MarginModification, Market, Num, Option, OptionChain, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, Trade, TradingFeeInterface, Transaction, MarketInterface, TransferEntry
10
+ from ccxt.base.types import Account, Any, Balances, BorrowInterest, Conversion, CrossBorrowRate, CrossBorrowRates, Currencies, Currency, DepositAddress, Greeks, Int, LedgerEntry, Leverage, LeverageTier, LongShortRatio, MarginModification, Market, Num, Option, OptionChain, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, OpenInterests, Trade, TradingFeeInterface, Transaction, MarketInterface, TransferEntry
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import AuthenticationError
@@ -109,7 +109,7 @@ class okx(Exchange, ImplicitAPI):
109
109
  'fetchFundingIntervals': False,
110
110
  'fetchFundingRate': True,
111
111
  'fetchFundingRateHistory': True,
112
- 'fetchFundingRates': False,
112
+ 'fetchFundingRates': True,
113
113
  'fetchGreeks': True,
114
114
  'fetchIndexOHLCV': True,
115
115
  'fetchIsolatedBorrowRate': False,
@@ -132,6 +132,7 @@ class okx(Exchange, ImplicitAPI):
132
132
  'fetchOHLCV': True,
133
133
  'fetchOpenInterest': True,
134
134
  'fetchOpenInterestHistory': True,
135
+ 'fetchOpenInterests': True,
135
136
  'fetchOpenOrder': None,
136
137
  'fetchOpenOrders': True,
137
138
  'fetchOption': True,
@@ -5985,7 +5986,7 @@ class okx(Exchange, ImplicitAPI):
5985
5986
  nextFundingRate = self.safe_number(contract, 'nextFundingRate')
5986
5987
  fundingTime = self.safe_integer(contract, 'fundingTime')
5987
5988
  fundingTimeString = self.safe_string(contract, 'fundingTime')
5988
- nextFundingTimeString = self.safe_string(contract, 'nextFundingRate')
5989
+ nextFundingTimeString = self.safe_string(contract, 'nextFundingTime')
5989
5990
  millisecondsInterval = Precise.string_sub(nextFundingTimeString, fundingTimeString)
5990
5991
  # https://www.okx.com/support/hc/en-us/articles/360053909272-Ⅸ-Introduction-to-perpetual-swap-funding-fee
5991
5992
  # > The current interest is 0.
@@ -6070,6 +6071,39 @@ class okx(Exchange, ImplicitAPI):
6070
6071
  entry = self.safe_dict(data, 0, {})
6071
6072
  return self.parse_funding_rate(entry, market)
6072
6073
 
6074
+ async def fetch_funding_rates(self, symbols: Strings = None, params={}) -> FundingRates:
6075
+ """
6076
+ fetches the current funding rates for multiple symbols
6077
+
6078
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-funding-rate
6079
+
6080
+ :param str[] symbols: unified market symbols
6081
+ :param dict [params]: extra parameters specific to the exchange API endpoint
6082
+ :returns dict: a dictionary of `funding rates structure <https://docs.ccxt.com/#/?id=funding-rates-structure>`
6083
+ """
6084
+ await self.load_markets()
6085
+ symbols = self.market_symbols(symbols, 'swap', True)
6086
+ request: dict = {'instId': 'ANY'}
6087
+ response = await self.publicGetPublicFundingRate(self.extend(request, params))
6088
+ #
6089
+ # {
6090
+ # "code": "0",
6091
+ # "data": [
6092
+ # {
6093
+ # "fundingRate": "0.00027815",
6094
+ # "fundingTime": "1634256000000",
6095
+ # "instId": "BTC-USD-SWAP",
6096
+ # "instType": "SWAP",
6097
+ # "nextFundingRate": "0.00017",
6098
+ # "nextFundingTime": "1634284800000"
6099
+ # }
6100
+ # ],
6101
+ # "msg": ""
6102
+ # }
6103
+ #
6104
+ data = self.safe_list(response, 'data', [])
6105
+ return self.parse_funding_rates(data, symbols)
6106
+
6073
6107
  async def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
6074
6108
  """
6075
6109
  fetch the history of funding payments paid and received on self account
@@ -7027,6 +7061,59 @@ class okx(Exchange, ImplicitAPI):
7027
7061
  data = self.safe_list(response, 'data', [])
7028
7062
  return self.parse_open_interest(data[0], market)
7029
7063
 
7064
+ async def fetch_open_interests(self, symbols: Strings = None, params={}) -> OpenInterests:
7065
+ """
7066
+ Retrieves the open interests of some currencies
7067
+
7068
+ https://www.okx.com/docs-v5/en/#rest-api-public-data-get-open-interest
7069
+
7070
+ :param str[] symbols: Unified CCXT market symbols
7071
+ :param dict [params]: exchange specific parameters
7072
+ :param str params['instType']: Instrument type, options: 'SWAP', 'FUTURES', 'OPTION', default to 'SWAP'
7073
+ :param str params['uly']: Underlying, Applicable to FUTURES/SWAP/OPTION, if instType is 'OPTION', either uly or instFamily is required
7074
+ :param str params['instFamily']: Instrument family, Applicable to FUTURES/SWAP/OPTION, if instType is 'OPTION', either uly or instFamily is required
7075
+ :returns dict: an dictionary of `open interest structures <https://docs.ccxt.com/#/?id=open-interest-structure>`
7076
+ """
7077
+ await self.load_markets()
7078
+ symbols = self.market_symbols(symbols, None, True, True)
7079
+ market = None
7080
+ if symbols is not None:
7081
+ market = self.market(symbols[0])
7082
+ marketType = None
7083
+ marketType, params = self.handle_sub_type_and_params('fetchOpenInterests', market, params, 'swap')
7084
+ instType = 'SWAP'
7085
+ if marketType == 'future':
7086
+ instType = 'FUTURES'
7087
+ elif instType == 'option':
7088
+ instType = 'OPTION'
7089
+ request: dict = {'instType': instType}
7090
+ uly = self.safe_string(params, 'uly')
7091
+ if uly is not None:
7092
+ request['uly'] = uly
7093
+ instFamily = self.safe_string(params, 'instFamily')
7094
+ if instFamily is not None:
7095
+ request['instFamily'] = instFamily
7096
+ if instType == 'OPTION' and uly is None and instFamily is None:
7097
+ raise BadRequest(self.id + ' fetchOpenInterests() requires either uly or instFamily parameter for OPTION markets')
7098
+ response = await self.publicGetPublicOpenInterest(self.extend(request, params))
7099
+ #
7100
+ # {
7101
+ # "code": "0",
7102
+ # "data": [
7103
+ # {
7104
+ # "instId": "BTC-USDT-SWAP",
7105
+ # "instType": "SWAP",
7106
+ # "oi": "2125419",
7107
+ # "oiCcy": "21254.19",
7108
+ # "ts": "1664005108969"
7109
+ # }
7110
+ # ],
7111
+ # "msg": ""
7112
+ # }
7113
+ #
7114
+ data = self.safe_list(response, 'data', [])
7115
+ return self.parse_open_interests(data, symbols)
7116
+
7030
7117
  async def fetch_open_interest_history(self, symbol: str, timeframe='1d', since: Int = None, limit: Int = None, params={}):
7031
7118
  """
7032
7119
  Retrieves the open interest history of a currency
@@ -0,0 +1,54 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.async_support.okx import okx
7
+ from ccxt.abstract.okxus import ImplicitAPI
8
+ from ccxt.base.types import Any
9
+
10
+
11
+ class okxus(okx, ImplicitAPI):
12
+
13
+ def describe(self) -> Any:
14
+ return self.deep_extend(super(okxus, self).describe(), {
15
+ 'id': 'okxus',
16
+ 'name': 'OKX(US)',
17
+ 'certified': False,
18
+ 'pro': True,
19
+ 'hostname': 'us.okx.com',
20
+ 'urls': {
21
+ 'logo': 'https://user-images.githubusercontent.com/1294454/152485636-38b19e4a-bece-4dec-979a-5982859ffc04.jpg',
22
+ 'api': {
23
+ 'rest': 'https://{hostname}',
24
+ },
25
+ 'www': 'https://app.okx.com',
26
+ 'doc': 'https://app.okx.com/docs-v5/en/#overview',
27
+ 'fees': 'https://app.okx.com/pages/products/fees.html',
28
+ 'referral': {
29
+ 'url': 'https://www.app.okx.com/join/CCXT2023',
30
+ 'discount': 0.2,
31
+ },
32
+ 'test': {
33
+ 'rest': 'https://{hostname}',
34
+ },
35
+ },
36
+ 'has': {
37
+ 'CORS': None,
38
+ 'spot': True,
39
+ 'margin': None,
40
+ 'swap': False,
41
+ 'future': False,
42
+ 'option': False,
43
+ },
44
+ 'features': {
45
+ 'swap': {
46
+ 'linear': None,
47
+ 'inverse': None,
48
+ },
49
+ 'future': {
50
+ 'linear': None,
51
+ 'inverse': None,
52
+ },
53
+ },
54
+ })
@@ -1248,7 +1248,10 @@ class paradex(Exchange, ImplicitAPI):
1248
1248
  cancelReason = self.safe_string(order, 'cancel_reason')
1249
1249
  status = self.safe_string(order, 'status')
1250
1250
  if cancelReason is not None:
1251
- status = 'canceled'
1251
+ if cancelReason == 'NOT_ENOUGH_MARGIN':
1252
+ status = 'rejected'
1253
+ else:
1254
+ status = 'canceled'
1252
1255
  side = self.safe_string_lower(order, 'side')
1253
1256
  average = self.omit_zero(self.safe_string(order, 'avg_fill_price'))
1254
1257
  remaining = self.omit_zero(self.safe_string(order, 'remaining_size'))
@@ -1131,9 +1131,7 @@ class phemex(Exchange, ImplicitAPI):
1131
1131
  for i in range(0, len(currencies)):
1132
1132
  currency = currencies[i]
1133
1133
  id = self.safe_string(currency, 'currency')
1134
- name = self.safe_string(currency, 'name')
1135
1134
  code = self.safe_currency_code(id)
1136
- status = self.safe_string(currency, 'status')
1137
1135
  valueScaleString = self.safe_string(currency, 'valueScale')
1138
1136
  valueScale = int(valueScaleString)
1139
1137
  minValueEv = self.safe_string(currency, 'minValueEv')
@@ -1146,12 +1144,12 @@ class phemex(Exchange, ImplicitAPI):
1146
1144
  precision = self.parse_number(precisionString)
1147
1145
  minAmount = self.parse_number(Precise.string_mul(minValueEv, precisionString))
1148
1146
  maxAmount = self.parse_number(Precise.string_mul(maxValueEv, precisionString))
1149
- result[code] = {
1147
+ result[code] = self.safe_currency_structure({
1150
1148
  'id': id,
1151
1149
  'info': currency,
1152
1150
  'code': code,
1153
- 'name': name,
1154
- 'active': status == 'Listed',
1151
+ 'name': self.safe_string(currency, 'name'),
1152
+ 'active': self.safe_string(currency, 'status') == 'Listed',
1155
1153
  'deposit': None,
1156
1154
  'withdraw': None,
1157
1155
  'fee': None,
@@ -1169,7 +1167,7 @@ class phemex(Exchange, ImplicitAPI):
1169
1167
  'valueScale': valueScale,
1170
1168
  'networks': None,
1171
1169
  'type': 'crypto',
1172
- }
1170
+ })
1173
1171
  return result
1174
1172
 
1175
1173
  def custom_parse_bid_ask(self, bidask, priceKey=0, amountKey=1, market: Market = None):
@@ -322,6 +322,11 @@ class poloniex(Exchange, ImplicitAPI):
322
322
  'BEP20': 'BSC',
323
323
  'ERC20': 'ETH',
324
324
  'TRC20': 'TRON',
325
+ 'TRX': 'TRON',
326
+ },
327
+ 'networksById': {
328
+ 'TRX': 'TRC20',
329
+ 'TRON': 'TRC20',
325
330
  },
326
331
  'limits': {
327
332
  'cost': {
@@ -1149,102 +1154,103 @@ class poloniex(Exchange, ImplicitAPI):
1149
1154
  response = await self.publicGetCurrencies(self.extend(params, {'includeMultiChainCurrencies': True}))
1150
1155
  #
1151
1156
  # [
1152
- # {
1153
- # "1CR": {
1154
- # "id": 1,
1155
- # "name": "1CRedit",
1156
- # "description": "BTC Clone",
1157
- # "type": "address",
1158
- # "withdrawalFee": "0.01000000",
1159
- # "minConf": 10000,
1160
- # "depositAddress": null,
1161
- # "blockchain": "1CR",
1162
- # "delisted": False,
1163
- # "tradingState": "NORMAL",
1164
- # "walletState": "DISABLED",
1165
- # "walletDepositState": "DISABLED",
1166
- # "walletWithdrawalState": "DISABLED",
1167
- # "parentChain": null,
1168
- # "isMultiChain": False,
1169
- # "isChildChain": False,
1170
- # "childChains": []
1171
- # }
1172
- # }
1157
+ # {
1158
+ # "USDT": {
1159
+ # "id": 214,
1160
+ # "name": "Tether USD",
1161
+ # "description": "Sweep to Main Account",
1162
+ # "type": "address",
1163
+ # "withdrawalFee": "0.00000000",
1164
+ # "minConf": 2,
1165
+ # "depositAddress": null,
1166
+ # "blockchain": "OMNI",
1167
+ # "delisted": False,
1168
+ # "tradingState": "NORMAL",
1169
+ # "walletState": "DISABLED",
1170
+ # "walletDepositState": "DISABLED",
1171
+ # "walletWithdrawalState": "DISABLED",
1172
+ # "supportCollateral": True,
1173
+ # "supportBorrow": True,
1174
+ # "parentChain": null,
1175
+ # "isMultiChain": True,
1176
+ # "isChildChain": False,
1177
+ # "childChains": [
1178
+ # "USDTBSC",
1179
+ # "USDTETH",
1180
+ # "USDTSOL",
1181
+ # "USDTTRON"
1182
+ # ]
1183
+ # }
1184
+ # },
1185
+ # ...
1186
+ # {
1187
+ # "USDTBSC": {
1188
+ # "id": 582,
1189
+ # "name": "Binance-Peg BSC-USD",
1190
+ # "description": "Sweep to Main Account",
1191
+ # "type": "address",
1192
+ # "withdrawalFee": "0.00000000",
1193
+ # "minConf": 15,
1194
+ # "depositAddress": null,
1195
+ # "blockchain": "BSC",
1196
+ # "delisted": False,
1197
+ # "tradingState": "OFFLINE",
1198
+ # "walletState": "ENABLED",
1199
+ # "walletDepositState": "ENABLED",
1200
+ # "walletWithdrawalState": "DISABLED",
1201
+ # "supportCollateral": False,
1202
+ # "supportBorrow": False,
1203
+ # "parentChain": "USDT",
1204
+ # "isMultiChain": True,
1205
+ # "isChildChain": True,
1206
+ # "childChains": []
1207
+ # }
1208
+ # },
1209
+ # ...
1173
1210
  # ]
1174
1211
  #
1175
1212
  result: dict = {}
1213
+ # poloniex has a complicated structure of currencies, so we handle them differently
1214
+ # at first, turn the response into a normal dictionary
1215
+ currenciesDict = {}
1176
1216
  for i in range(0, len(response)):
1177
- item = self.safe_value(response, i)
1217
+ item = self.safe_dict(response, i)
1178
1218
  ids = list(item.keys())
1179
- id = self.safe_value(ids, 0)
1180
- currency = self.safe_value(item, id)
1219
+ id = self.safe_string(ids, 0)
1220
+ currenciesDict[id] = item[id]
1221
+ keys = list(currenciesDict.keys())
1222
+ for i in range(0, len(keys)):
1223
+ id = keys[i]
1224
+ entry = currenciesDict[id]
1181
1225
  code = self.safe_currency_code(id)
1182
- name = self.safe_string(currency, 'name')
1183
- networkId = self.safe_string(currency, 'blockchain')
1184
- networkCode = None
1185
- if networkId is not None:
1186
- networkCode = self.network_id_to_code(networkId, code)
1187
- delisted = self.safe_value(currency, 'delisted')
1188
- walletEnabled = self.safe_string(currency, 'walletState') == 'ENABLED'
1189
- depositEnabled = self.safe_string(currency, 'walletDepositState') == 'ENABLED'
1190
- withdrawEnabled = self.safe_string(currency, 'walletWithdrawalState') == 'ENABLED'
1191
- active = not delisted and walletEnabled and depositEnabled and withdrawEnabled
1192
- numericId = self.safe_integer(currency, 'id')
1193
- feeString = self.safe_string(currency, 'withdrawalFee')
1194
- parentChain = self.safe_value(currency, 'parentChain')
1195
- noParentChain = parentChain is None
1196
- if self.safe_value(result, code) is None:
1197
- result[code] = {
1198
- 'id': id,
1199
- 'code': code,
1200
- 'info': None,
1201
- 'name': name,
1202
- 'active': active,
1203
- 'deposit': depositEnabled,
1204
- 'withdraw': withdrawEnabled,
1205
- 'fee': self.parse_number(feeString),
1206
- 'precision': None,
1207
- 'type': 'crypto',
1208
- 'limits': {
1209
- 'amount': {
1210
- 'min': None,
1211
- 'max': None,
1212
- },
1213
- 'deposit': {
1214
- 'min': None,
1215
- 'max': None,
1216
- },
1217
- 'withdraw': {
1218
- 'min': None,
1219
- 'max': None,
1220
- },
1221
- },
1222
- }
1223
- minFeeString = self.safe_string(result[code], 'fee')
1224
- if feeString is not None:
1225
- minFeeString = feeString if (minFeeString is None) else Precise.string_min(feeString, minFeeString)
1226
- depositAvailable = self.safe_value(result[code], 'deposit')
1227
- depositAvailable = depositEnabled if (depositEnabled) else depositAvailable
1228
- withdrawAvailable = self.safe_value(result[code], 'withdraw')
1229
- withdrawAvailable = withdrawEnabled if (withdrawEnabled) else withdrawAvailable
1230
- networks = self.safe_value(result[code], 'networks', {})
1231
- if networkCode is not None:
1226
+ # skip childChains, are collected in parentChain loop
1227
+ if self.safe_bool(entry, 'isChildChain'):
1228
+ continue
1229
+ allChainEntries = []
1230
+ childChains = self.safe_list(entry, 'childChains', [])
1231
+ if childChains is not None:
1232
+ for j in range(0, len(childChains)):
1233
+ childChainId = childChains[j]
1234
+ childNetworkEntry = self.safe_dict(currenciesDict, childChainId)
1235
+ allChainEntries.append(childNetworkEntry)
1236
+ allChainEntries.append(entry)
1237
+ networks: dict = {}
1238
+ for j in range(0, len(allChainEntries)):
1239
+ chainEntry = allChainEntries[j]
1240
+ networkName = self.safe_string(chainEntry, 'blockchain')
1241
+ networkCode = self.network_id_to_code(networkName, code)
1242
+ specialNetworkId = self.safe_string(childChains, j, id) # in case it's primary chain, defeault to ID
1232
1243
  networks[networkCode] = {
1233
- 'info': currency,
1234
- 'id': networkId,
1244
+ 'info': chainEntry,
1245
+ 'id': specialNetworkId, # we need self for deposit/withdrawal, instead of friendly name
1246
+ 'numericId': self.safe_integer(chainEntry, 'id'),
1235
1247
  'network': networkCode,
1236
- 'currencyId': id,
1237
- 'numericId': numericId,
1238
- 'deposit': depositEnabled,
1239
- 'withdraw': withdrawEnabled,
1240
- 'active': active,
1241
- 'fee': self.parse_number(feeString),
1248
+ 'active': self.safe_bool(chainEntry, 'walletState'),
1249
+ 'deposit': self.safe_string(chainEntry, 'walletDepositState') == 'ENABLED',
1250
+ 'withdraw': self.safe_string(chainEntry, 'walletWithdrawalState') == 'ENABLED',
1251
+ 'fee': self.safe_number(chainEntry, 'withdrawalFee'),
1242
1252
  'precision': None,
1243
1253
  'limits': {
1244
- 'amount': {
1245
- 'min': None,
1246
- 'max': None,
1247
- },
1248
1254
  'withdraw': {
1249
1255
  'min': None,
1250
1256
  'max': None,
@@ -1255,19 +1261,34 @@ class poloniex(Exchange, ImplicitAPI):
1255
1261
  },
1256
1262
  },
1257
1263
  }
1258
- result[code]['networks'] = networks
1259
- info = self.safe_value(result[code], 'info', [])
1260
- rawInfo: dict = {}
1261
- rawInfo[id] = currency
1262
- info.append(rawInfo)
1263
- result[code]['info'] = info
1264
- if noParentChain:
1265
- result[code]['id'] = id
1266
- result[code]['name'] = name
1267
- result[code]['active'] = depositAvailable and withdrawAvailable
1268
- result[code]['deposit'] = depositAvailable
1269
- result[code]['withdraw'] = withdrawAvailable
1270
- result[code]['fee'] = self.parse_number(minFeeString)
1264
+ result[code] = self.safe_currency_structure({
1265
+ 'info': entry,
1266
+ 'code': code,
1267
+ 'id': id,
1268
+ 'numericId': self.safe_integer(entry, 'id'),
1269
+ 'type': 'crypto',
1270
+ 'name': self.safe_string(entry, 'name'),
1271
+ 'active': None,
1272
+ 'deposit': None,
1273
+ 'withdraw': None,
1274
+ 'fee': None,
1275
+ 'precision': None,
1276
+ 'limits': {
1277
+ 'amount': {
1278
+ 'min': None,
1279
+ 'max': None,
1280
+ },
1281
+ 'withdraw': {
1282
+ 'min': None,
1283
+ 'max': None,
1284
+ },
1285
+ 'deposit': {
1286
+ 'min': None,
1287
+ 'max': None,
1288
+ },
1289
+ },
1290
+ 'networks': networks,
1291
+ })
1271
1292
  return result
1272
1293
 
1273
1294
  async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
@@ -2585,40 +2606,15 @@ class poloniex(Exchange, ImplicitAPI):
2585
2606
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
2586
2607
  """
2587
2608
  await self.load_markets()
2588
- currency = self.currency(code)
2589
- request: dict = {
2590
- 'currency': currency['id'],
2591
- }
2592
- networks = self.safe_value(self.options, 'networks', {})
2593
- network = self.safe_string_upper(params, 'network') # self line allows the user to specify either ERC20 or ETH
2594
- network = self.safe_string(networks, network, network) # handle ERC20>ETH alias
2595
- if network is not None:
2596
- request['currency'] = request['currency'] + network # when network the currency need to be changed to currency+network https://docs.poloniex.com/#withdraw on MultiChain Currencies section
2597
- params = self.omit(params, 'network')
2598
- else:
2599
- if currency['id'] == 'USDT':
2600
- raise ArgumentsRequired(self.id + ' createDepositAddress requires a network parameter for ' + code + '.')
2609
+ request, extraParams, currency, networkEntry = self.prepare_request_for_deposit_address(code, params)
2610
+ params = extraParams
2601
2611
  response = await self.privatePostWalletsAddress(self.extend(request, params))
2602
2612
  #
2603
2613
  # {
2604
2614
  # "address" : "0xfxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxf"
2605
2615
  # }
2606
2616
  #
2607
- address = self.safe_string(response, 'address')
2608
- tag: Str = None
2609
- self.check_address(address)
2610
- if currency is not None:
2611
- depositAddress = self.safe_string(currency['info'], 'depositAddress')
2612
- if depositAddress is not None:
2613
- tag = address
2614
- address = depositAddress
2615
- return {
2616
- 'currency': code,
2617
- 'address': address,
2618
- 'tag': tag,
2619
- 'network': network,
2620
- 'info': response,
2621
- }
2617
+ return self.parse_deposit_address_special(response, currency, networkEntry)
2622
2618
 
2623
2619
  async def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
2624
2620
  """
@@ -2631,37 +2627,56 @@ class poloniex(Exchange, ImplicitAPI):
2631
2627
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
2632
2628
  """
2633
2629
  await self.load_markets()
2634
- currency = self.currency(code)
2635
- request: dict = {
2636
- 'currency': currency['id'],
2637
- }
2638
- networks = self.safe_value(self.options, 'networks', {})
2639
- network = self.safe_string_upper(params, 'network') # self line allows the user to specify either ERC20 or ETH
2640
- network = self.safe_string(networks, network, network) # handle ERC20>ETH alias
2641
- if network is not None:
2642
- request['currency'] = request['currency'] + network # when network the currency need to be changed to currency+network https://docs.poloniex.com/#withdraw on MultiChain Currencies section
2643
- params = self.omit(params, 'network')
2644
- else:
2645
- if currency['id'] == 'USDT':
2646
- raise ArgumentsRequired(self.id + ' fetchDepositAddress requires a network parameter for ' + code + '.')
2630
+ request, extraParams, currency, networkEntry = self.prepare_request_for_deposit_address(code, params)
2631
+ params = extraParams
2647
2632
  response = await self.privateGetWalletsAddresses(self.extend(request, params))
2648
2633
  #
2649
2634
  # {
2650
2635
  # "USDTTRON" : "Txxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxp"
2651
2636
  # }
2652
2637
  #
2653
- address = self.safe_string(response, request['currency'])
2638
+ keys = list(response.keys())
2639
+ length = len(keys)
2640
+ if length < 1:
2641
+ raise ExchangeError(self.id + ' fetchDepositAddress() returned an empty response, you might need to try "createDepositAddress" at first and then use "fetchDepositAddress"')
2642
+ return self.parse_deposit_address_special(response, currency, networkEntry)
2643
+
2644
+ def prepare_request_for_deposit_address(self, code: str, params: dict = {}) -> Any:
2645
+ if not (code in self.currencies):
2646
+ raise BadSymbol(self.id + ' fetchDepositAddress(): can not recognize ' + code + ' currency, you might try using unified currency-code and add provide specific "network" parameter, like: fetchDepositAddress("USDT", {"network": "TRC20"})')
2647
+ currency = self.currency(code)
2648
+ networkCode = None
2649
+ networkCode, params = self.handle_network_code_and_params(params)
2650
+ if networkCode is None:
2651
+ # we need to know the network to find out the currency-junction
2652
+ raise ArgumentsRequired(self.id + ' fetchDepositAddress requires a network parameter for ' + code + '.')
2653
+ exchangeNetworkId = None
2654
+ networkCode = self.network_id_to_code(networkCode, code)
2655
+ networkEntry = self.safe_dict(currency['networks'], networkCode)
2656
+ if networkEntry is not None:
2657
+ exchangeNetworkId = networkEntry['id']
2658
+ else:
2659
+ exchangeNetworkId = networkCode
2660
+ request = {
2661
+ 'currency': exchangeNetworkId,
2662
+ }
2663
+ return [request, params, currency, networkEntry]
2664
+
2665
+ def parse_deposit_address_special(self, response, currency, networkEntry) -> DepositAddress:
2666
+ address = self.safe_string(response, 'address')
2667
+ if address is None:
2668
+ address = self.safe_string(response, networkEntry['id'])
2654
2669
  tag: Str = None
2655
2670
  self.check_address(address)
2656
- if currency is not None:
2657
- depositAddress = self.safe_string(currency['info'], 'depositAddress')
2671
+ if networkEntry is not None:
2672
+ depositAddress = self.safe_string(networkEntry['info'], 'depositAddress')
2658
2673
  if depositAddress is not None:
2659
2674
  tag = address
2660
2675
  address = depositAddress
2661
2676
  return {
2662
2677
  'info': response,
2663
- 'currency': code,
2664
- 'network': network,
2678
+ 'currency': currency['code'],
2679
+ 'network': self.safe_string(networkEntry, 'network'),
2665
2680
  'address': address,
2666
2681
  'tag': tag,
2667
2682
  }
@@ -2731,21 +2746,12 @@ class poloniex(Exchange, ImplicitAPI):
2731
2746
  """
2732
2747
  tag, params = self.handle_withdraw_tag_and_params(tag, params)
2733
2748
  self.check_address(address)
2734
- await self.load_markets()
2735
- currency = self.currency(code)
2736
- request: dict = {
2737
- 'currency': currency['id'],
2738
- 'amount': amount,
2739
- 'address': address,
2740
- }
2749
+ request, extraParams, currency, networkEntry = self.prepare_request_for_deposit_address(code, params)
2750
+ params = extraParams
2751
+ request['amount'] = self.currency_to_precision(code, amount)
2752
+ request['address'] = address
2741
2753
  if tag is not None:
2742
2754
  request['paymentId'] = tag
2743
- networks = self.safe_value(self.options, 'networks', {})
2744
- network = self.safe_string_upper(params, 'network') # self line allows the user to specify either ERC20 or ETH
2745
- network = self.safe_string(networks, network, network) # handle ERC20>ETH alias
2746
- if network is not None:
2747
- request['currency'] = request['currency'] + network # when network the currency need to be changed to currency+network https://docs.poloniex.com/#withdraw on MultiChain Currencies section
2748
- params = self.omit(params, 'network')
2749
2755
  response = await self.privatePostWalletsWithdraw(self.extend(request, params))
2750
2756
  #
2751
2757
  # {
@@ -2754,7 +2760,11 @@ class poloniex(Exchange, ImplicitAPI):
2754
2760
  # "withdrawalNumber": 13449869
2755
2761
  # }
2756
2762
  #
2757
- return self.parse_transaction(response, currency)
2763
+ withdrawResponse = {
2764
+ 'response': response,
2765
+ 'withdrawNetworkEntry': networkEntry,
2766
+ }
2767
+ return self.parse_transaction(withdrawResponse, currency)
2758
2768
 
2759
2769
  async def fetch_transactions_helper(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
2760
2770
  await self.load_markets()
@@ -3072,6 +3082,9 @@ class poloniex(Exchange, ImplicitAPI):
3072
3082
  # "withdrawalRequestsId": 33485231
3073
3083
  # }
3074
3084
  #
3085
+ # if it's being parsed from "withdraw()" method, get the original response
3086
+ if 'withdrawNetworkEntry' in transaction:
3087
+ transaction = transaction['response']
3075
3088
  timestamp = self.safe_timestamp(transaction, 'timestamp')
3076
3089
  currencyId = self.safe_string(transaction, 'currency')
3077
3090
  code = self.safe_currency_code(currencyId)