ccxt 4.4.61__py2.py3-none-any.whl → 4.4.63__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.
ccxt/bybit.py CHANGED
@@ -73,7 +73,9 @@ class bybit(Exchange, ImplicitAPI):
73
73
  'createTrailingAmountOrder': True,
74
74
  'createTriggerOrder': True,
75
75
  'editOrder': True,
76
+ 'editOrders': True,
76
77
  'fetchBalance': True,
78
+ 'fetchBidsAsks': 'emulated',
77
79
  'fetchBorrowInterest': False, # temporarily disabled, doesn't work
78
80
  'fetchBorrowRateHistories': False,
79
81
  'fetchBorrowRateHistory': False,
@@ -254,6 +256,7 @@ class bybit(Exchange, ImplicitAPI):
254
256
  'v5/spot-lever-token/reference': 5,
255
257
  # spot margin trade
256
258
  'v5/spot-margin-trade/data': 5,
259
+ 'v5/spot-margin-trade/collateral': 5,
257
260
  'v5/spot-cross-margin-trade/data': 5,
258
261
  'v5/spot-cross-margin-trade/pledge-token': 5,
259
262
  'v5/spot-cross-margin-trade/borrow-token': 5,
@@ -1239,6 +1242,9 @@ class bybit(Exchange, ImplicitAPI):
1239
1242
  'fetchOHLCV': {
1240
1243
  'limit': 1000,
1241
1244
  },
1245
+ 'editOrders': {
1246
+ 'max': 10,
1247
+ },
1242
1248
  },
1243
1249
  'spot': {
1244
1250
  'extends': 'default',
@@ -1339,7 +1345,7 @@ class bybit(Exchange, ImplicitAPI):
1339
1345
  # so we're assuming UTA is enabled
1340
1346
  self.options['enableUnifiedMargin'] = False
1341
1347
  self.options['enableUnifiedAccount'] = True
1342
- self.options['unifiedMarginStatus'] = 3
1348
+ self.options['unifiedMarginStatus'] = 6
1343
1349
  return [self.options['enableUnifiedMargin'], self.options['enableUnifiedAccount']]
1344
1350
  rawPromises = [self.privateGetV5UserQueryApi(params), self.privateGetV5AccountInfo(params)]
1345
1351
  promises = rawPromises
@@ -1404,7 +1410,7 @@ class bybit(Exchange, ImplicitAPI):
1404
1410
  accountResult = self.safe_dict(accountInfo, 'result', {})
1405
1411
  self.options['enableUnifiedMargin'] = self.safe_integer(result, 'unified') == 1
1406
1412
  self.options['enableUnifiedAccount'] = self.safe_integer(result, 'uta') == 1
1407
- self.options['unifiedMarginStatus'] = self.safe_integer(accountResult, 'unifiedMarginStatus', 3) # default to uta.1 if not found
1413
+ self.options['unifiedMarginStatus'] = self.safe_integer(accountResult, 'unifiedMarginStatus', 6) # default to uta 2.0 pro if not found
1408
1414
  return [self.options['enableUnifiedMargin'], self.options['enableUnifiedAccount']]
1409
1415
 
1410
1416
  def upgrade_unified_trade_account(self, params={}):
@@ -2462,6 +2468,20 @@ class bybit(Exchange, ImplicitAPI):
2462
2468
  tickerList = self.safe_list(result, 'list', [])
2463
2469
  return self.parse_tickers(tickerList, parsedSymbols)
2464
2470
 
2471
+ def fetch_bids_asks(self, symbols: Strings = None, params={}):
2472
+ """
2473
+ fetches the bid and ask price and volume for multiple markets
2474
+
2475
+ https://bybit-exchange.github.io/docs/v5/market/tickers
2476
+
2477
+ :param str[]|None symbols: unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
2478
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2479
+ :param str [params.subType]: *contract only* 'linear', 'inverse'
2480
+ :param str [params.baseCoin]: *option only* base coin, default is 'BTC'
2481
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
2482
+ """
2483
+ return self.fetch_tickers(symbols, params)
2484
+
2465
2485
  def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
2466
2486
  #
2467
2487
  # [
@@ -3283,7 +3303,7 @@ class bybit(Exchange, ImplicitAPI):
3283
3303
  isInverse = (type == 'inverse')
3284
3304
  isFunding = (lowercaseRawType == 'fund') or (lowercaseRawType == 'funding')
3285
3305
  if isUnifiedAccount:
3286
- unifiedMarginStatus = self.safe_integer(self.options, 'unifiedMarginStatus', 3)
3306
+ unifiedMarginStatus = self.safe_integer(self.options, 'unifiedMarginStatus', 6)
3287
3307
  if unifiedMarginStatus < 5:
3288
3308
  # it's not uta.20 where inverse are unified
3289
3309
  if isInverse:
@@ -3984,13 +4004,15 @@ class bybit(Exchange, ImplicitAPI):
3984
4004
  price = self.safe_value(rawOrder, 'price')
3985
4005
  orderParams = self.safe_dict(rawOrder, 'params', {})
3986
4006
  orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams, isUta)
4007
+ del orderRequest['category']
3987
4008
  ordersRequests.append(orderRequest)
3988
4009
  symbols = self.market_symbols(orderSymbols, None, False, True, True)
3989
4010
  market = self.market(symbols[0])
4011
+ unifiedMarginStatus = self.safe_integer(self.options, 'unifiedMarginStatus', 6)
3990
4012
  category = None
3991
4013
  category, params = self.get_bybit_type('createOrders', market, params)
3992
- if category == 'inverse':
3993
- raise NotSupported(self.id + ' createOrders does not allow inverse orders')
4014
+ if (category == 'inverse') and (unifiedMarginStatus < 5):
4015
+ raise NotSupported(self.id + ' createOrders does not allow inverse orders for non UTA2.0 account')
3994
4016
  request: dict = {
3995
4017
  'category': category,
3996
4018
  'request': ordersRequests,
@@ -4157,6 +4179,91 @@ class bybit(Exchange, ImplicitAPI):
4157
4179
  'id': self.safe_string(result, 'orderId'),
4158
4180
  })
4159
4181
 
4182
+ def edit_orders(self, orders: List[OrderRequest], params={}):
4183
+ """
4184
+ edit a list of trade orders
4185
+
4186
+ https://bybit-exchange.github.io/docs/v5/order/batch-amend
4187
+
4188
+ :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
4189
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4190
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4191
+ """
4192
+ self.load_markets()
4193
+ ordersRequests = []
4194
+ orderSymbols = []
4195
+ for i in range(0, len(orders)):
4196
+ rawOrder = orders[i]
4197
+ symbol = self.safe_string(rawOrder, 'symbol')
4198
+ orderSymbols.append(symbol)
4199
+ id = self.safe_string(rawOrder, 'id')
4200
+ type = self.safe_string(rawOrder, 'type')
4201
+ side = self.safe_string(rawOrder, 'side')
4202
+ amount = self.safe_value(rawOrder, 'amount')
4203
+ price = self.safe_value(rawOrder, 'price')
4204
+ orderParams = self.safe_dict(rawOrder, 'params', {})
4205
+ orderRequest = self.edit_order_request(id, symbol, type, side, amount, price, orderParams)
4206
+ del orderRequest['category']
4207
+ ordersRequests.append(orderRequest)
4208
+ orderSymbols = self.market_symbols(orderSymbols, None, False, True, True)
4209
+ market = self.market(orderSymbols[0])
4210
+ unifiedMarginStatus = self.safe_integer(self.options, 'unifiedMarginStatus', 6)
4211
+ category = None
4212
+ category, params = self.get_bybit_type('editOrders', market, params)
4213
+ if (category == 'inverse') and (unifiedMarginStatus < 5):
4214
+ raise NotSupported(self.id + ' editOrders does not allow inverse orders for non UTA2.0 account')
4215
+ request: dict = {
4216
+ 'category': category,
4217
+ 'request': ordersRequests,
4218
+ }
4219
+ response = self.privatePostV5OrderAmendBatch(self.extend(request, params))
4220
+ result = self.safe_dict(response, 'result', {})
4221
+ data = self.safe_list(result, 'list', [])
4222
+ retInfo = self.safe_dict(response, 'retExtInfo', {})
4223
+ codes = self.safe_list(retInfo, 'list', [])
4224
+ # self.extend the error with the unsuccessful orders
4225
+ for i in range(0, len(codes)):
4226
+ code = codes[i]
4227
+ retCode = self.safe_integer(code, 'code')
4228
+ if retCode != 0:
4229
+ data[i] = self.extend(data[i], code)
4230
+ #
4231
+ # {
4232
+ # "retCode": 0,
4233
+ # "retMsg": "OK",
4234
+ # "result": {
4235
+ # "list": [
4236
+ # {
4237
+ # "category": "option",
4238
+ # "symbol": "ETH-30DEC22-500-C",
4239
+ # "orderId": "b551f227-7059-4fb5-a6a6-699c04dbd2f2",
4240
+ # "orderLinkId": ""
4241
+ # },
4242
+ # {
4243
+ # "category": "option",
4244
+ # "symbol": "ETH-30DEC22-700-C",
4245
+ # "orderId": "fa6a595f-1a57-483f-b9d3-30e9c8235a52",
4246
+ # "orderLinkId": ""
4247
+ # }
4248
+ # ]
4249
+ # },
4250
+ # "retExtInfo": {
4251
+ # "list": [
4252
+ # {
4253
+ # "code": 0,
4254
+ # "msg": "OK"
4255
+ # },
4256
+ # {
4257
+ # "code": 0,
4258
+ # "msg": "OK"
4259
+ # }
4260
+ # ]
4261
+ # },
4262
+ # "time": 1672222808060
4263
+ # }
4264
+ #
4265
+ return self.parse_orders(data)
4266
+
4160
4267
  def cancel_order_request(self, id: str, symbol: Str = None, params={}):
4161
4268
  market = self.market(symbol)
4162
4269
  request: dict = {
ccxt/gate.py CHANGED
@@ -23,7 +23,6 @@ from ccxt.base.errors import OrderImmediatelyFillable
23
23
  from ccxt.base.errors import NotSupported
24
24
  from ccxt.base.errors import RateLimitExceeded
25
25
  from ccxt.base.errors import ExchangeNotAvailable
26
- from ccxt.base.errors import BadResponse
27
26
  from ccxt.base.decimal_to_precision import TICK_SIZE
28
27
  from ccxt.base.precise import Precise
29
28
 
@@ -1797,100 +1796,80 @@ class gate(Exchange, ImplicitAPI):
1797
1796
  self.load_unified_status()
1798
1797
  response = self.publicSpotGetCurrencies(params)
1799
1798
  #
1800
- # {
1801
- # "currency": "BCN",
1802
- # "delisted": False,
1803
- # "withdraw_disabled": True,
1804
- # "withdraw_delayed": False,
1805
- # "deposit_disabled": True,
1806
- # "trade_disabled": False
1807
- # }
1808
- #
1809
- # {
1810
- # "currency":"USDT_ETH",
1811
- # "delisted":false,
1812
- # "withdraw_disabled":false,
1813
- # "withdraw_delayed":false,
1814
- # "deposit_disabled":false,
1815
- # "trade_disabled":false,
1816
- # "chain":"ETH"
1817
- # }
1818
- #
1799
+ # [
1800
+ # {
1801
+ # "currency": "USDT_ETH",
1802
+ # "name": "Tether",
1803
+ # "delisted": False,
1804
+ # "withdraw_disabled": False,
1805
+ # "withdraw_delayed": False,
1806
+ # "deposit_disabled": False,
1807
+ # "trade_disabled": True,
1808
+ # "chain": "ETH"
1809
+ # },
1810
+ # ]
1811
+ #
1812
+ indexedCurrencies = self.index_by(response, 'currency')
1819
1813
  result: dict = {}
1820
1814
  for i in range(0, len(response)):
1821
1815
  entry = response[i]
1822
1816
  currencyId = self.safe_string(entry, 'currency')
1823
- currencyIdLower = self.safe_string_lower(entry, 'currency')
1824
1817
  parts = currencyId.split('_')
1825
- currency = parts[0]
1826
- code = self.safe_currency_code(currency)
1827
- networkId = self.safe_string(entry, 'chain')
1828
- networkCode = None
1829
- if networkId is not None:
1830
- networkCode = self.network_id_to_code(networkId, code)
1831
- delisted = self.safe_value(entry, 'delisted')
1832
- withdrawDisabled = self.safe_bool(entry, 'withdraw_disabled', False)
1833
- depositDisabled = self.safe_bool(entry, 'deposit_disabled', False)
1834
- tradeDisabled = self.safe_bool(entry, 'trade_disabled', False)
1835
- withdrawEnabled = not withdrawDisabled
1836
- depositEnabled = not depositDisabled
1837
- tradeEnabled = not tradeDisabled
1838
- listed = not delisted
1839
- active = listed and tradeEnabled and withdrawEnabled and depositEnabled
1840
- if self.safe_value(result, code) is None:
1818
+ partFirst = self.safe_string(parts, 0)
1819
+ # if there's an underscore then the second part is always the chain name(except the _OLD suffix)
1820
+ currencyName = currencyId if currencyId.endswith('_OLD') else partFirst
1821
+ withdrawEnabled = not self.safe_bool(entry, 'withdraw_disabled')
1822
+ depositEnabled = not self.safe_bool(entry, 'deposit_disabled')
1823
+ tradeDisabled = not self.safe_bool(entry, 'trade_disabled')
1824
+ precision = self.parse_number('0.0001') # temporary safe default, because no value provided from API
1825
+ code = self.safe_currency_code(currencyName)
1826
+ # check leveraged tokens(e.g. BTC3S, ETH5L)
1827
+ isLeveragedToken = False
1828
+ if currencyId.endswith('3S') or currencyId.endswith('3L') or currencyId.endswith('5S') or currencyId.endswith('5L'):
1829
+ realCurrencyId = currencyId[0:-2]
1830
+ if realCurrencyId in indexedCurrencies:
1831
+ isLeveragedToken = True
1832
+ type = 'leveraged' if isLeveragedToken else 'crypto'
1833
+ # some networks are null, they are mostly obsolete & unsupported dead tokens, so we can default their networkId to their tokenname
1834
+ networkId = self.safe_string(entry, 'chain', currencyId)
1835
+ networkCode = self.network_id_to_code(networkId, code)
1836
+ networkEntry = {
1837
+ 'info': entry,
1838
+ 'id': networkId,
1839
+ 'network': networkCode,
1840
+ 'limits': {
1841
+ 'deposit': {
1842
+ 'min': None,
1843
+ 'max': None,
1844
+ },
1845
+ 'withdraw': {
1846
+ 'min': None,
1847
+ 'max': None,
1848
+ },
1849
+ },
1850
+ 'active': not tradeDisabled,
1851
+ 'deposit': depositEnabled,
1852
+ 'withdraw': withdrawEnabled,
1853
+ 'fee': None,
1854
+ 'precision': precision,
1855
+ }
1856
+ # check if first entry for the specific currency
1857
+ if not (code in result):
1841
1858
  result[code] = {
1842
- 'id': currency,
1859
+ 'id': currencyName,
1860
+ 'lowerCaseId': currencyName.lower(),
1843
1861
  'code': code,
1844
- 'info': None,
1845
- 'name': None,
1846
- 'active': active,
1847
- 'deposit': depositEnabled,
1848
- 'withdraw': withdrawEnabled,
1849
- 'fee': None,
1850
- 'fees': [],
1851
- 'precision': self.parse_number('1e-4'),
1862
+ 'type': type,
1863
+ 'precision': precision,
1852
1864
  'limits': self.limits,
1853
1865
  'networks': {},
1866
+ 'info': [], # will be filled below
1854
1867
  }
1855
- depositAvailable = self.safe_value(result[code], 'deposit')
1856
- depositAvailable = depositEnabled if (depositEnabled) else depositAvailable
1857
- withdrawAvailable = self.safe_value(result[code], 'withdraw')
1858
- withdrawAvailable = withdrawEnabled if (withdrawEnabled) else withdrawAvailable
1859
- networks = self.safe_value(result[code], 'networks', {})
1860
- if networkCode is not None:
1861
- networks[networkCode] = {
1862
- 'info': entry,
1863
- 'id': networkId,
1864
- 'network': networkCode,
1865
- 'currencyId': currencyId,
1866
- 'lowerCaseCurrencyId': currencyIdLower,
1867
- 'deposit': depositEnabled,
1868
- 'withdraw': withdrawEnabled,
1869
- 'active': active,
1870
- 'fee': None,
1871
- 'precision': self.parse_number('1e-4'),
1872
- 'limits': {
1873
- 'amount': {
1874
- 'min': None,
1875
- 'max': None,
1876
- },
1877
- 'withdraw': {
1878
- 'min': None,
1879
- 'max': None,
1880
- },
1881
- 'deposit': {
1882
- 'min': None,
1883
- 'max': None,
1884
- },
1885
- },
1886
- }
1887
- result[code]['networks'] = networks
1888
- info = self.safe_value(result[code], 'info', [])
1868
+ result[code]['networks'][networkCode] = networkEntry
1869
+ info = self.safe_list(result[code], 'info', [])
1889
1870
  info.append(entry)
1890
1871
  result[code]['info'] = info
1891
- result[code]['active'] = depositAvailable and withdrawAvailable
1892
- result[code]['deposit'] = depositAvailable
1893
- result[code]['withdraw'] = withdrawAvailable
1872
+ result[code] = self.safe_currency_structure(result[code]) # self is needed after adding network entry
1894
1873
  return result
1895
1874
 
1896
1875
  def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
@@ -2135,6 +2114,27 @@ class gate(Exchange, ImplicitAPI):
2135
2114
  }
2136
2115
  return result
2137
2116
 
2117
+ def fetch_deposit_addresses_by_network(self, code: str, params={}) -> List[DepositAddress]:
2118
+ """
2119
+ fetch a dictionary of addresses for a currency, indexed by network
2120
+ :param str code: unified currency code of the currency for the deposit address
2121
+ :param dict [params]: extra parameters specific to the api endpoint
2122
+ :returns dict: a dictionary of `address structures <https://docs.ccxt.com/#/?id=address-structure>` indexed by the network
2123
+ """
2124
+ self.load_markets()
2125
+ currency = self.currency(code)
2126
+ request = {
2127
+ 'currency': currency['id'],
2128
+ }
2129
+ response = self.privateWalletGetDepositAddress(self.extend(request, params))
2130
+ chains = self.safe_value(response, 'multichain_addresses', [])
2131
+ currencyId = self.safe_string(response, 'currency')
2132
+ currency = self.safe_currency(currencyId, currency)
2133
+ parsed = self.parse_deposit_addresses(chains, [currency['code']], False, {
2134
+ 'currency': currency['id'],
2135
+ })
2136
+ return self.index_by(parsed, 'network')
2137
+
2138
2138
  def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
2139
2139
  """
2140
2140
  fetch the deposit address for a currency associated with self account
@@ -2147,65 +2147,30 @@ class gate(Exchange, ImplicitAPI):
2147
2147
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
2148
2148
  """
2149
2149
  self.load_markets()
2150
- currency = self.currency(code)
2151
- rawNetwork = self.safe_string_upper(params, 'network')
2152
- params = self.omit(params, 'network')
2153
- request: dict = {
2154
- 'currency': currency['id'], # todo: currencies have network-junctions
2155
- }
2156
- response = self.privateWalletGetDepositAddress(self.extend(request, params))
2150
+ networkCode = None
2151
+ networkCode, params = self.handle_network_code_and_params(params)
2152
+ chainsIndexedById = self.fetch_deposit_addresses_by_network(code, params)
2153
+ selectedNetworkId = self.select_network_code_from_unified_networks(code, networkCode, chainsIndexedById)
2154
+ return chainsIndexedById[selectedNetworkId]
2155
+
2156
+ def parse_deposit_address(self, depositAddress, currency=None):
2157
2157
  #
2158
- # {
2159
- # "currency": "XRP",
2160
- # "address": "rHcFoo6a9qT5NHiVn1THQRhsEGcxtYCV4d 391331007",
2161
- # "multichain_addresses": [
2162
- # {
2163
- # "chain": "XRP",
2164
- # "address": "rHcFoo6a9qT5NHiVn1THQRhsEGcxtYCV4d",
2165
- # "payment_id": "391331007",
2166
- # "payment_name": "Tag",
2167
- # "obtain_failed": 0
2168
- # }
2169
- # ]
2170
- # }
2158
+ # {
2159
+ # chain: "BTC",
2160
+ # address: "1Nxu.......Ys",
2161
+ # payment_id: "",
2162
+ # payment_name: "",
2163
+ # obtain_failed: "0",
2164
+ # }
2171
2165
  #
2172
- currencyId = self.safe_string(response, 'currency')
2173
- code = self.safe_currency_code(currencyId)
2174
- networkId = self.network_code_to_id(rawNetwork, code)
2175
- network = None
2176
- tag = None
2177
- address = None
2178
- if networkId is not None:
2179
- addresses = self.safe_value(response, 'multichain_addresses')
2180
- for i in range(0, len(addresses)):
2181
- entry = addresses[i]
2182
- entryNetwork = self.safe_string(entry, 'chain')
2183
- if networkId == entryNetwork:
2184
- obtainFailed = self.safe_integer(entry, 'obtain_failed')
2185
- if obtainFailed:
2186
- break
2187
- address = self.safe_string(entry, 'address')
2188
- tag = self.safe_string(entry, 'payment_id')
2189
- network = self.network_id_to_code(networkId, code)
2190
- break
2191
- else:
2192
- addressField = self.safe_string(response, 'address')
2193
- if addressField is not None:
2194
- if addressField.find('New address is being generated for you, please wait') >= 0:
2195
- raise BadResponse(self.id + ' ' + 'New address is being generated for you, please wait a few seconds and try again to get the address.')
2196
- if addressField.find(' ') >= 0:
2197
- splitted = addressField.split(' ')
2198
- address = splitted[0]
2199
- tag = splitted[1]
2200
- else:
2201
- address = addressField
2166
+ address = self.safe_string(depositAddress, 'address')
2202
2167
  self.check_address(address)
2203
2168
  return {
2204
- 'info': response,
2205
- 'currency': code,
2206
- 'network': network,
2169
+ 'info': depositAddress,
2170
+ 'currency': self.safe_string(currency, 'code'),
2207
2171
  'address': address,
2208
- 'tag': tag,
2172
+ 'tag': self.safe_string(depositAddress, 'payment_id'),
2173
+ 'network': self.network_id_to_code(self.safe_string(depositAddress, 'chain')),
2209
2174
  }
2210
2175
 
2211
2176
  def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
@@ -3818,14 +3783,10 @@ class gate(Exchange, ImplicitAPI):
3818
3783
  }
3819
3784
  if tag is not None:
3820
3785
  request['memo'] = tag
3821
- networks = self.safe_value(self.options, 'networks', {})
3822
- network = self.safe_string_upper(params, 'network') # self line allows the user to specify either ERC20 or ETH
3823
- network = self.safe_string_lower(networks, network, network) # handle ETH>ERC20 alias
3824
- if network is not None:
3825
- request['chain'] = network
3826
- params = self.omit(params, 'network')
3827
- else:
3828
- request['chain'] = currency['id'] # todo: currencies have network-junctions
3786
+ networkCode = None
3787
+ networkCode, params = self.handle_network_code_and_params(params)
3788
+ if networkCode is not None:
3789
+ request['chain'] = self.network_code_to_id(networkCode)
3829
3790
  response = self.privateWithdrawalsPostWithdrawals(self.extend(request, params))
3830
3791
  #
3831
3792
  # {
ccxt/kraken.py CHANGED
@@ -981,9 +981,9 @@ class kraken(Exchange, ImplicitAPI):
981
981
  'high': self.safe_string(high, 1),
982
982
  'low': self.safe_string(low, 1),
983
983
  'bid': self.safe_string(bid, 0),
984
- 'bidVolume': None,
984
+ 'bidVolume': self.safe_string(bid, 2),
985
985
  'ask': self.safe_string(ask, 0),
986
- 'askVolume': None,
986
+ 'askVolume': self.safe_string(ask, 2),
987
987
  'vwap': vwap,
988
988
  'open': self.safe_string(ticker, 'o'),
989
989
  'close': last,