ccxt 4.3.21__py2.py3-none-any.whl → 4.3.23__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.

Potentially problematic release.


This version of ccxt might be problematic. Click here for more details.

ccxt/coinex.py CHANGED
@@ -10,6 +10,7 @@ from typing import List
10
10
  from ccxt.base.errors import ExchangeError
11
11
  from ccxt.base.errors import AuthenticationError
12
12
  from ccxt.base.errors import PermissionDenied
13
+ from ccxt.base.errors import AccountSuspended
13
14
  from ccxt.base.errors import ArgumentsRequired
14
15
  from ccxt.base.errors import BadRequest
15
16
  from ccxt.base.errors import BadSymbol
@@ -480,10 +481,53 @@ class coinex(Exchange, ImplicitAPI):
480
481
  '36': RequestTimeout, # Service timeout
481
482
  '213': RateLimitExceeded, # Too many requests
482
483
  '107': InsufficientFunds,
484
+ '158': PermissionDenied, # {"code":158,"data":{},"message":"API permission is not allowed"}
483
485
  '600': OrderNotFound,
484
486
  '601': InvalidOrder,
485
487
  '602': InvalidOrder,
486
488
  '606': InvalidOrder,
489
+ '3008': RequestTimeout, # Service busy, please try again later.
490
+ '3109': InsufficientFunds, # {"code":3109,"data":{},"message":"balance not enough"}
491
+ '3127': InvalidOrder, # The order quantity is below the minimum requirement. Please adjust the order quantity.
492
+ '3606': InvalidOrder, # The price difference between the order price and the latest price is too large. Please adjust the order amount accordingly.
493
+ '3610': ExchangeError, # Order cancellation prohibited during the Call Auction period.
494
+ '3612': InvalidOrder, # The est. ask price is lower than the current bottom ask price. Please reduce the amount.
495
+ '3613': InvalidOrder, # The est. bid price is higher than the current top bid price. Please reduce the amount.
496
+ '3614': InvalidOrder, # The deviation between your est. filled price and the index price. Please reduce the amount.
497
+ '3615': InvalidOrder, # The deviation between your order price and the index price is too high. Please adjust your order price and try again.
498
+ '3616': InvalidOrder, # The order price exceeds the current top bid price. Please adjust the order price and try again.
499
+ '3617': InvalidOrder, # The order price exceeds the current bottom ask price. Please adjust the order price and try again.
500
+ '3618': InvalidOrder, # The deviation between your order price and the index price is too high. Please adjust your order price and try again.
501
+ '3619': InvalidOrder, # The deviation between your order price and the trigger price is too high. Please adjust your order price and try again.
502
+ '3620': InvalidOrder, # Market order submission is temporarily unavailable due to insufficient depth in the current market
503
+ '3621': InvalidOrder, # This order can't be completely executed and has been canceled.
504
+ '3622': InvalidOrder, # This order can't be set Only and has been canceled.
505
+ '3627': InvalidOrder, # The current market depth is low, please reduce your order amount and try again.
506
+ '3628': InvalidOrder, # The current market depth is low, please reduce your order amount and try again.
507
+ '3629': InvalidOrder, # The current market depth is low, please reduce your order amount and try again.
508
+ '3632': InvalidOrder, # The order price exceeds the current top bid price. Please adjust the order price and try again.
509
+ '3633': InvalidOrder, # The order price exceeds the current bottom ask price. Please adjust the order price and try again.
510
+ '3634': InvalidOrder, # The deviation between your est. filled price and the index price is too high. Please reduce the amount and try again.
511
+ '3635': InvalidOrder, # The deviation between your est. filled price and the index price is too high. Please reduce the amount and try again.
512
+ '4001': ExchangeNotAvailable, # Service unavailable, please try again later.
513
+ '4002': RequestTimeout, # Service request timed out, please try again later.
514
+ '4003': ExchangeError, # Internal error, please contact customer service for help.
515
+ '4004': BadRequest, # Parameter error, please check whether the request parameters are abnormal.
516
+ '4005': AuthenticationError, # Abnormal access_id, please check whether the value passed by X-COINEX-KEY is normal.
517
+ '4006': AuthenticationError, # Signature verification failed, please check the signature according to the documentation instructions.
518
+ '4007': PermissionDenied, # IP address prohibited, please check whether the whitelist or export IP is normal.
519
+ '4008': AuthenticationError, # Abnormal X-COIN-SIGN value, please check.
520
+ '4009': ExchangeError, # Abnormal request method, please check.
521
+ '4010': ExchangeError, # Expired request, please try again later.
522
+ '4011': PermissionDenied, # User prohibited from accessing, please contact customer service for help.
523
+ '4017': ExchangeError, # Signature expired, please try again later.
524
+ '4115': AccountSuspended, # User prohibited from trading, please contact customer service for help.
525
+ '4117': BadSymbol, # Trading hasattr(self, prohibited) market, please try again later.
526
+ '4123': RateLimitExceeded, # Rate limit triggered. Please adjust your strategy and reduce the request rate.
527
+ '4130': ExchangeError, # Futures trading prohibited, please try again later.
528
+ '4158': ExchangeError, # Trading prohibited, please try again later.
529
+ '4213': RateLimitExceeded, # The request is too frequent, please try again later.
530
+ '4512': PermissionDenied, # Insufficient sub-account permissions, please check.
487
531
  },
488
532
  'broad': {
489
533
  'ip not allow visit': PermissionDenied,
@@ -4138,8 +4182,8 @@ class coinex(Exchange, ImplicitAPI):
4138
4182
 
4139
4183
  def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
4140
4184
  """
4141
- fetch the history of funding payments paid and received on self account
4142
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http034_funding_position
4185
+ fetch the history of funding fee payments paid and received on self account
4186
+ :see: https://docs.coinex.com/api/v2/futures/position/http/list-position-funding-history
4143
4187
  :param str symbol: unified market symbol
4144
4188
  :param int [since]: the earliest time in ms to fetch funding history for
4145
4189
  :param int [limit]: the maximum number of funding history structures to retrieve
@@ -4148,53 +4192,45 @@ class coinex(Exchange, ImplicitAPI):
4148
4192
  """
4149
4193
  if symbol is None:
4150
4194
  raise ArgumentsRequired(self.id + ' fetchFundingHistory() requires a symbol argument')
4151
- limit = 100 if (limit is None) else limit
4152
4195
  self.load_markets()
4153
4196
  market = self.market(symbol)
4154
4197
  request = {
4155
4198
  'market': market['id'],
4156
- 'limit': limit,
4157
- # 'offset': 0,
4158
- # 'end_time': 1638990636000,
4159
- # 'windowtime': 1638990636000,
4199
+ 'market_type': 'FUTURES',
4160
4200
  }
4201
+ request, params = self.handle_until_option('end_time', request, params)
4161
4202
  if since is not None:
4162
4203
  request['start_time'] = since
4163
- response = self.v1PerpetualPrivateGetPositionFunding(self.extend(request, params))
4204
+ if limit is not None:
4205
+ request['limit'] = limit
4206
+ response = self.v2PrivateGetFuturesPositionFundingHistory(self.extend(request, params))
4164
4207
  #
4165
4208
  # {
4166
4209
  # "code": 0,
4167
- # "data": {
4168
- # "limit": 100,
4169
- # "offset": 0,
4170
- # "records": [
4171
- # {
4172
- # "amount": "0.0012",
4173
- # "asset": "USDT",
4174
- # "funding": "-0.0095688273996",
4175
- # "funding_rate": "0.00020034",
4176
- # "market": "BTCUSDT",
4177
- # "position_id": 62052321,
4178
- # "price": "39802.45",
4179
- # "real_funding_rate": "0.00020034",
4180
- # "side": 2,
4181
- # "time": 1650729623.933885,
4182
- # "type": 1,
4183
- # "user_id": 3620173,
4184
- # "value": "47.76294"
4185
- # },
4186
- # ]
4187
- # },
4188
- # "message": "OK"
4210
+ # "data": [
4211
+ # {
4212
+ # "ccy": "USDT",
4213
+ # "created_at": 1715673620183,
4214
+ # "funding_rate": "0",
4215
+ # "funding_value": "0",
4216
+ # "market": "BTCUSDT",
4217
+ # "market_type": "FUTURES",
4218
+ # "position_id": 306458800,
4219
+ # "side": "long"
4220
+ # },
4221
+ # ],
4222
+ # "message": "OK",
4223
+ # "pagination": {
4224
+ # "has_next": True
4225
+ # }
4189
4226
  # }
4190
4227
  #
4191
- data = self.safe_value(response, 'data', {})
4192
- resultList = self.safe_value(data, 'records', [])
4228
+ data = self.safe_list(response, 'data', [])
4193
4229
  result = []
4194
- for i in range(0, len(resultList)):
4195
- entry = resultList[i]
4196
- timestamp = self.safe_timestamp(entry, 'time')
4197
- currencyId = self.safe_string(entry, 'asset')
4230
+ for i in range(0, len(data)):
4231
+ entry = data[i]
4232
+ timestamp = self.safe_integer(entry, 'created_at')
4233
+ currencyId = self.safe_string(entry, 'ccy')
4198
4234
  code = self.safe_currency_code(currencyId)
4199
4235
  result.append({
4200
4236
  'info': entry,
@@ -4203,14 +4239,14 @@ class coinex(Exchange, ImplicitAPI):
4203
4239
  'timestamp': timestamp,
4204
4240
  'datetime': self.iso8601(timestamp),
4205
4241
  'id': self.safe_number(entry, 'position_id'),
4206
- 'amount': self.safe_number(entry, 'funding'),
4242
+ 'amount': self.safe_number(entry, 'funding_value'),
4207
4243
  })
4208
4244
  return result
4209
4245
 
4210
4246
  def fetch_funding_rate(self, symbol: str, params={}):
4211
4247
  """
4212
4248
  fetch the current funding rate
4213
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http008_market_ticker
4249
+ :see: https://docs.coinex.com/api/v2/futures/market/http/list-market-funding-rate
4214
4250
  :param str symbol: unified market symbol
4215
4251
  :param dict [params]: extra parameters specific to the exchange API endpoint
4216
4252
  :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
@@ -4222,93 +4258,63 @@ class coinex(Exchange, ImplicitAPI):
4222
4258
  request = {
4223
4259
  'market': market['id'],
4224
4260
  }
4225
- response = self.v1PerpetualPublicGetMarketTicker(self.extend(request, params))
4261
+ response = self.v2PublicGetFuturesFundingRate(self.extend(request, params))
4226
4262
  #
4227
4263
  # {
4228
- # "code": 0,
4229
- # "data":
4230
- # {
4231
- # "date": 1650678472474,
4232
- # "ticker": {
4233
- # "vol": "6090.9430",
4234
- # "low": "39180.30",
4235
- # "open": "40474.97",
4236
- # "high": "40798.01",
4237
- # "last": "39659.30",
4238
- # "buy": "39663.79",
4239
- # "period": 86400,
4240
- # "funding_time": 372,
4241
- # "position_amount": "270.1956",
4242
- # "funding_rate_last": "0.00022913",
4243
- # "funding_rate_next": "0.00013158",
4244
- # "funding_rate_predict": "0.00016552",
4245
- # "insurance": "16045554.83969682659674035672",
4246
- # "sign_price": "39652.48",
4247
- # "index_price": "39648.44250000",
4248
- # "sell_total": "22.3913",
4249
- # "buy_total": "19.4498",
4250
- # "buy_amount": "12.8942",
4251
- # "sell": "39663.80",
4252
- # "sell_amount": "0.9388"
4264
+ # "code": 0,
4265
+ # "data": [
4266
+ # {
4267
+ # "latest_funding_rate": "0",
4268
+ # "latest_funding_time": 1715731200000,
4269
+ # "mark_price": "61602.22",
4270
+ # "market": "BTCUSDT",
4271
+ # "max_funding_rate": "0.00375",
4272
+ # "min_funding_rate": "-0.00375",
4273
+ # "next_funding_rate": "0.00021074",
4274
+ # "next_funding_time": 1715760000000
4253
4275
  # }
4254
- # },
4276
+ # ],
4255
4277
  # "message": "OK"
4256
4278
  # }
4257
4279
  #
4258
- data = self.safe_value(response, 'data', {})
4259
- ticker = self.safe_value(data, 'ticker', {})
4260
- timestamp = self.safe_integer(data, 'date')
4261
- ticker['timestamp'] = timestamp # avoid changing parseFundingRate signature
4262
- return self.parse_funding_rate(ticker, market)
4280
+ data = self.safe_list(response, 'data', [])
4281
+ first = self.safe_dict(data, 0, {})
4282
+ return self.parse_funding_rate(first, market)
4263
4283
 
4264
4284
  def parse_funding_rate(self, contract, market: Market = None):
4265
4285
  #
4266
- # fetchFundingRate
4286
+ # fetchFundingRate, fetchFundingRates
4267
4287
  #
4268
4288
  # {
4269
- # "vol": "6090.9430",
4270
- # "low": "39180.30",
4271
- # "open": "40474.97",
4272
- # "high": "40798.01",
4273
- # "last": "39659.30",
4274
- # "buy": "39663.79",
4275
- # "period": 86400,
4276
- # "funding_time": 372,
4277
- # "position_amount": "270.1956",
4278
- # "funding_rate_last": "0.00022913",
4279
- # "funding_rate_next": "0.00013158",
4280
- # "funding_rate_predict": "0.00016552",
4281
- # "insurance": "16045554.83969682659674035672",
4282
- # "sign_price": "39652.48",
4283
- # "index_price": "39648.44250000",
4284
- # "sell_total": "22.3913",
4285
- # "buy_total": "19.4498",
4286
- # "buy_amount": "12.8942",
4287
- # "sell": "39663.80",
4288
- # "sell_amount": "0.9388"
4289
+ # "latest_funding_rate": "0",
4290
+ # "latest_funding_time": 1715731200000,
4291
+ # "mark_price": "61602.22",
4292
+ # "market": "BTCUSDT",
4293
+ # "max_funding_rate": "0.00375",
4294
+ # "min_funding_rate": "-0.00375",
4295
+ # "next_funding_rate": "0.00021074",
4296
+ # "next_funding_time": 1715760000000
4289
4297
  # }
4290
4298
  #
4291
- timestamp = self.safe_integer(contract, 'timestamp')
4292
- contract = self.omit(contract, 'timestamp')
4293
- fundingDelta = self.safe_integer(contract, 'funding_time') * 60 * 1000
4294
- fundingHour = (timestamp + fundingDelta) / 3600000
4295
- fundingTimestamp = int(round(fundingHour)) * 3600000
4299
+ currentFundingTimestamp = self.safe_integer(contract, 'latest_funding_time')
4300
+ futureFundingTimestamp = self.safe_integer(contract, 'next_funding_time')
4301
+ marketId = self.safe_string(contract, 'market')
4296
4302
  return {
4297
4303
  'info': contract,
4298
- 'symbol': self.safe_symbol(None, market),
4299
- 'markPrice': self.safe_number(contract, 'sign_price'),
4300
- 'indexPrice': self.safe_number(contract, 'index_price'),
4304
+ 'symbol': self.safe_symbol(marketId, market, None, 'swap'),
4305
+ 'markPrice': self.safe_number(contract, 'mark_price'),
4306
+ 'indexPrice': None,
4301
4307
  'interestRate': None,
4302
4308
  'estimatedSettlePrice': None,
4303
- 'timestamp': timestamp,
4304
- 'datetime': self.iso8601(timestamp),
4305
- 'fundingRate': self.safe_number(contract, 'funding_rate_next'),
4306
- 'fundingTimestamp': fundingTimestamp,
4307
- 'fundingDatetime': self.iso8601(fundingTimestamp),
4308
- 'nextFundingRate': self.safe_number(contract, 'funding_rate_predict'),
4309
- 'nextFundingTimestamp': None,
4310
- 'nextFundingDatetime': None,
4311
- 'previousFundingRate': self.safe_number(contract, 'funding_rate_last'),
4309
+ 'timestamp': None,
4310
+ 'datetime': None,
4311
+ 'fundingRate': self.safe_number(contract, 'latest_funding_rate'),
4312
+ 'fundingTimestamp': currentFundingTimestamp,
4313
+ 'fundingDatetime': self.iso8601(currentFundingTimestamp),
4314
+ 'nextFundingRate': self.safe_number(contract, 'next_funding_rate'),
4315
+ 'nextFundingTimestamp': futureFundingTimestamp,
4316
+ 'nextFundingDatetime': self.iso8601(futureFundingTimestamp),
4317
+ 'previousFundingRate': None,
4312
4318
  'previousFundingTimestamp': None,
4313
4319
  'previousFundingDatetime': None,
4314
4320
  }
@@ -4316,65 +4322,43 @@ class coinex(Exchange, ImplicitAPI):
4316
4322
  def fetch_funding_rates(self, symbols: Strings = None, params={}):
4317
4323
  """
4318
4324
  fetch the current funding rates
4319
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http009_market_ticker_all
4325
+ :see: https://docs.coinex.com/api/v2/futures/market/http/list-market-funding-rate
4320
4326
  :param str[] symbols: unified market symbols
4321
4327
  :param dict [params]: extra parameters specific to the exchange API endpoint
4322
4328
  :returns dict[]: an array of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-structure>`
4323
4329
  """
4324
4330
  self.load_markets()
4325
4331
  symbols = self.market_symbols(symbols)
4332
+ request = {}
4326
4333
  market = None
4327
4334
  if symbols is not None:
4328
4335
  symbol = self.safe_value(symbols, 0)
4329
4336
  market = self.market(symbol)
4330
4337
  if not market['swap']:
4331
4338
  raise BadSymbol(self.id + ' fetchFundingRates() supports swap contracts only')
4332
- response = self.v1PerpetualPublicGetMarketTickerAll(params)
4339
+ marketIds = self.market_ids(symbols)
4340
+ request['market'] = ','.join(marketIds)
4341
+ response = self.v2PublicGetFuturesFundingRate(self.extend(request, params))
4333
4342
  #
4334
4343
  # {
4335
4344
  # "code": 0,
4336
- # "data":
4337
- # {
4338
- # "date": 1650678472474,
4339
- # "ticker": {
4340
- # "BTCUSDT": {
4341
- # "vol": "6090.9430",
4342
- # "low": "39180.30",
4343
- # "open": "40474.97",
4344
- # "high": "40798.01",
4345
- # "last": "39659.30",
4346
- # "buy": "39663.79",
4347
- # "period": 86400,
4348
- # "funding_time": 372,
4349
- # "position_amount": "270.1956",
4350
- # "funding_rate_last": "0.00022913",
4351
- # "funding_rate_next": "0.00013158",
4352
- # "funding_rate_predict": "0.00016552",
4353
- # "insurance": "16045554.83969682659674035672",
4354
- # "sign_price": "39652.48",
4355
- # "index_price": "39648.44250000",
4356
- # "sell_total": "22.3913",
4357
- # "buy_total": "19.4498",
4358
- # "buy_amount": "12.8942",
4359
- # "sell": "39663.80",
4360
- # "sell_amount": "0.9388"
4361
- # }
4345
+ # "data": [
4346
+ # {
4347
+ # "latest_funding_rate": "0",
4348
+ # "latest_funding_time": 1715731200000,
4349
+ # "mark_price": "61602.22",
4350
+ # "market": "BTCUSDT",
4351
+ # "max_funding_rate": "0.00375",
4352
+ # "min_funding_rate": "-0.00375",
4353
+ # "next_funding_rate": "0.00021074",
4354
+ # "next_funding_time": 1715760000000
4362
4355
  # }
4363
- # },
4356
+ # ],
4364
4357
  # "message": "OK"
4365
4358
  # }
4366
- data = self.safe_value(response, 'data', {})
4367
- tickers = self.safe_value(data, 'ticker', {})
4368
- timestamp = self.safe_integer(data, 'date')
4369
- result = []
4370
- marketIds = list(tickers.keys())
4371
- for i in range(0, len(marketIds)):
4372
- marketId = marketIds[i]
4373
- if marketId.find('_') == -1: # skip _signprice and _indexprice
4374
- marketInner = self.safe_market(marketId, None, None, 'swap')
4375
- ticker = tickers[marketId]
4376
- ticker['timestamp'] = timestamp
4377
- result.append(self.parse_funding_rate(ticker, marketInner))
4359
+ #
4360
+ data = self.safe_list(response, 'data', [])
4361
+ result = self.parse_funding_rates(data, market)
4378
4362
  return self.filter_by_array(result, 'symbol', symbols)
4379
4363
 
4380
4364
  def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
@@ -4442,13 +4426,13 @@ class coinex(Exchange, ImplicitAPI):
4442
4426
 
4443
4427
  def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
4444
4428
  """
4445
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http038_funding_history
4446
4429
  fetches historical funding rate prices
4430
+ :see: https://docs.coinex.com/api/v2/futures/market/http/list-market-funding-rate-history
4447
4431
  :param str symbol: unified symbol of the market to fetch the funding rate history for
4448
4432
  :param int [since]: timestamp in ms of the earliest funding rate to fetch
4449
4433
  :param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
4450
4434
  :param dict [params]: extra parameters specific to the exchange API endpoint
4451
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
4435
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
4452
4436
  :param int [params.until]: timestamp in ms of the latest funding rate
4453
4437
  :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
4454
4438
  """
@@ -4459,50 +4443,44 @@ class coinex(Exchange, ImplicitAPI):
4459
4443
  paginate, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'paginate')
4460
4444
  if paginate:
4461
4445
  return self.fetch_paginated_call_deterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params, 1000)
4462
- if limit is None:
4463
- limit = 100
4464
4446
  market = self.market(symbol)
4465
4447
  request = {
4466
4448
  'market': market['id'],
4467
- 'limit': limit,
4468
- 'offset': 0,
4469
- # 'end_time': 1638990636,
4470
4449
  }
4471
4450
  if since is not None:
4472
4451
  request['start_time'] = since
4452
+ if limit is not None:
4453
+ request['limit'] = limit
4473
4454
  request, params = self.handle_until_option('end_time', request, params)
4474
- response = self.v1PerpetualPublicGetMarketFundingHistory(self.extend(request, params))
4455
+ response = self.v2PublicGetFuturesFundingRateHistory(self.extend(request, params))
4475
4456
  #
4476
4457
  # {
4477
4458
  # "code": 0,
4478
- # "data": {
4479
- # "offset": 0,
4480
- # "limit": 3,
4481
- # "records": [
4482
- # {
4483
- # "time": 1650672021.6230309,
4484
- # "market": "BTCUSDT",
4485
- # "asset": "USDT",
4486
- # "funding_rate": "0.00022913",
4487
- # "funding_rate_real": "0.00022913"
4488
- # },
4489
- # ]
4490
- # },
4491
- # "message": "OK"
4459
+ # "data": [
4460
+ # {
4461
+ # "actual_funding_rate": "0",
4462
+ # "funding_time": 1715731221761,
4463
+ # "market": "BTCUSDT",
4464
+ # "theoretical_funding_rate": "0"
4465
+ # },
4466
+ # ],
4467
+ # "message": "OK",
4468
+ # "pagination": {
4469
+ # "has_next": True
4470
+ # }
4492
4471
  # }
4493
4472
  #
4494
- data = self.safe_value(response, 'data')
4495
- result = self.safe_value(data, 'records', [])
4473
+ data = self.safe_list(response, 'data', [])
4496
4474
  rates = []
4497
- for i in range(0, len(result)):
4498
- entry = result[i]
4475
+ for i in range(0, len(data)):
4476
+ entry = data[i]
4499
4477
  marketId = self.safe_string(entry, 'market')
4500
4478
  symbolInner = self.safe_symbol(marketId, market, None, 'swap')
4501
- timestamp = self.safe_timestamp(entry, 'time')
4479
+ timestamp = self.safe_integer(entry, 'funding_time')
4502
4480
  rates.append({
4503
4481
  'info': entry,
4504
4482
  'symbol': symbolInner,
4505
- 'fundingRate': self.safe_number(entry, 'funding_rate'),
4483
+ 'fundingRate': self.safe_number(entry, 'actual_funding_rate'),
4506
4484
  'timestamp': timestamp,
4507
4485
  'datetime': self.iso8601(timestamp),
4508
4486
  })
@@ -5549,7 +5527,7 @@ class coinex(Exchange, ImplicitAPI):
5549
5527
  code = self.safe_string(response, 'code')
5550
5528
  data = self.safe_value(response, 'data')
5551
5529
  message = self.safe_string(response, 'message')
5552
- if (code != '0') or ((message != 'Success') and (message != 'Succeeded') and (message != 'Ok') and not data):
5530
+ if (code != '0') or ((message != 'Success') and (message != 'Succeeded') and (message.lower() != 'ok') and not data):
5553
5531
  feedback = self.id + ' ' + message
5554
5532
  self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
5555
5533
  self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
ccxt/phemex.py CHANGED
@@ -1658,6 +1658,26 @@ class phemex(Exchange, ImplicitAPI):
1658
1658
  # "execId": "8718cae",
1659
1659
  # "execStatus": 6
1660
1660
  # }
1661
+ # spot with fees paid using PT token
1662
+ # "createdAt": "1714990724076",
1663
+ # "symbol": "BTCUSDT",
1664
+ # "currency": "USDT",
1665
+ # "action": "1",
1666
+ # "tradeType": "1",
1667
+ # "execQtyRq": "0.003",
1668
+ # "execPriceRp": "64935",
1669
+ # "side": "2",
1670
+ # "orderQtyRq": "0.003",
1671
+ # "priceRp": "51600",
1672
+ # "execValueRv": "194.805",
1673
+ # "feeRateRr": "0.000495",
1674
+ # "execFeeRv": "0",
1675
+ # "ordType": "3",
1676
+ # "execId": "XXXXXX",
1677
+ # "execStatus": "7",
1678
+ # "posSide": "1",
1679
+ # "ptFeeRv": "0.110012249248",
1680
+ # "ptPriceRp": "0.876524893"
1661
1681
  #
1662
1682
  priceString: Str
1663
1683
  amountString: Str
@@ -1706,10 +1726,16 @@ class phemex(Exchange, ImplicitAPI):
1706
1726
  priceString = self.safe_string(trade, 'execPriceRp')
1707
1727
  amountString = self.safe_string(trade, 'execQtyRq')
1708
1728
  costString = self.safe_string(trade, 'execValueRv')
1709
- feeCostString = self.safe_string(trade, 'execFeeRv')
1729
+ feeCostString = self.omit_zero(self.safe_string(trade, 'execFeeRv'))
1710
1730
  feeRateString = self.safe_string(trade, 'feeRateRr')
1711
- currencyId = self.safe_string(trade, 'currency')
1712
- feeCurrencyCode = self.safe_currency_code(currencyId)
1731
+ if feeCostString is not None:
1732
+ currencyId = self.safe_string(trade, 'currency')
1733
+ feeCurrencyCode = self.safe_currency_code(currencyId)
1734
+ else:
1735
+ ptFeeRv = self.omit_zero(self.safe_string(trade, 'ptFeeRv'))
1736
+ if ptFeeRv is not None:
1737
+ feeCostString = ptFeeRv
1738
+ feeCurrencyCode = 'PT'
1713
1739
  else:
1714
1740
  side = self.safe_string_lower(trade, 'side')
1715
1741
  type = self.parse_order_type(self.safe_string(trade, 'ordType'))
@@ -1720,7 +1746,7 @@ class phemex(Exchange, ImplicitAPI):
1720
1746
  amountString = self.from_ev(self.safe_string(trade, 'execBaseQtyEv'), market)
1721
1747
  amountString = self.safe_string(trade, 'execQty', amountString)
1722
1748
  costString = self.from_er(self.safe_string_2(trade, 'execQuoteQtyEv', 'execValueEv'), market)
1723
- feeCostString = self.from_er(self.safe_string(trade, 'execFeeEv'), market)
1749
+ feeCostString = self.from_er(self.omit_zero(self.safe_string(trade, 'execFeeEv')), market)
1724
1750
  if feeCostString is not None:
1725
1751
  feeRateString = self.from_er(self.safe_string(trade, 'feeRateEr'), market)
1726
1752
  if market['spot']:
@@ -1730,6 +1756,10 @@ class phemex(Exchange, ImplicitAPI):
1730
1756
  if info is not None:
1731
1757
  settlementCurrencyId = self.safe_string(info, 'settlementCurrency')
1732
1758
  feeCurrencyCode = self.safe_currency_code(settlementCurrencyId)
1759
+ else:
1760
+ feeCostString = self.safe_string(trade, 'ptFeeRv')
1761
+ if feeCostString is not None:
1762
+ feeCurrencyCode = 'PT'
1733
1763
  fee = {
1734
1764
  'cost': feeCostString,
1735
1765
  'rate': feeRateString,
@@ -3608,7 +3638,8 @@ class phemex(Exchange, ImplicitAPI):
3608
3638
  raise BadRequest(self.id + ' fetchFundingHistory() limit argument cannot exceed 200')
3609
3639
  request['limit'] = limit
3610
3640
  response = None
3611
- if market['settle'] == 'USDT':
3641
+ isUsdt = market['settle'] == 'USDT'
3642
+ if isUsdt:
3612
3643
  response = self.privateGetApiDataGFuturesFundingFees(self.extend(request, params))
3613
3644
  else:
3614
3645
  response = self.privateGetApiDataFuturesFundingFees(self.extend(request, params))
@@ -3621,13 +3652,13 @@ class phemex(Exchange, ImplicitAPI):
3621
3652
  # {
3622
3653
  # "symbol": "BTCUSD",
3623
3654
  # "currency": "BTC",
3624
- # "execQty": 18,
3655
+ # "execQty": 18, # "execQty" regular, but "execQtyRq" in hedge
3625
3656
  # "side": "Buy",
3626
- # "execPriceEp": 360086455,
3627
- # "execValueEv": 49987,
3628
- # "fundingRateEr": 10000,
3629
- # "feeRateEr": 10000,
3630
- # "execFeeEv": 5,
3657
+ # "execPriceEp": 360086455, # "execPriceEp" regular, but "execPriceRp" in hedge
3658
+ # "execValueEv": 49987, # "execValueEv" regular, but "execValueRv" in hedge
3659
+ # "fundingRateEr": 10000, # "fundingRateEr" regular, but "fundingRateRr" in hedge
3660
+ # "feeRateEr": 10000, # "feeRateEr" regular, but "feeRateRr" in hedge
3661
+ # "execFeeEv": 5, # "execFeeEv" regular, but "execFeeRv" in hedge
3631
3662
  # "createTime": 1651881600000
3632
3663
  # }
3633
3664
  # ]
@@ -3640,17 +3671,31 @@ class phemex(Exchange, ImplicitAPI):
3640
3671
  for i in range(0, len(rows)):
3641
3672
  entry = rows[i]
3642
3673
  timestamp = self.safe_integer(entry, 'createTime')
3674
+ execFee = self.safe_string_2(entry, 'execFeeEv', 'execFeeRv')
3675
+ currencyCode = self.safe_currency_code(self.safe_string(entry, 'currency'))
3643
3676
  result.append({
3644
3677
  'info': entry,
3645
3678
  'symbol': self.safe_string(entry, 'symbol'),
3646
- 'code': self.safe_currency_code(self.safe_string(entry, 'currency')),
3679
+ 'code': currencyCode,
3647
3680
  'timestamp': timestamp,
3648
3681
  'datetime': self.iso8601(timestamp),
3649
3682
  'id': None,
3650
- 'amount': self.from_ev(self.safe_string(entry, 'execFeeEv'), market),
3683
+ 'amount': self.parse_funding_fee_to_precision(execFee, market, currencyCode),
3651
3684
  })
3652
3685
  return result
3653
3686
 
3687
+ def parse_funding_fee_to_precision(self, value, market: Market = None, currencyCode: Str = None):
3688
+ if value is None or currencyCode is None:
3689
+ return value
3690
+ # it was confirmed by phemex support, that USDT contracts use direct amounts in funding fees, while USD & INVERSE needs 'valueScale'
3691
+ isUsdt = market['settle'] == 'USDT'
3692
+ if not isUsdt:
3693
+ currency = self.safe_currency(currencyCode)
3694
+ scale = self.safe_string(currency['info'], 'valueScale')
3695
+ tickPrecision = self.parse_precision(scale)
3696
+ value = Precise.string_mul(value, tickPrecision)
3697
+ return value
3698
+
3654
3699
  def fetch_funding_rate(self, symbol: str, params={}):
3655
3700
  """
3656
3701
  fetch the current funding rate
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.21'
7
+ __version__ = '4.3.23'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10