ccxt 4.3.23__py2.py3-none-any.whl → 4.3.27__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.
@@ -58,6 +58,9 @@ class kraken(Exchange, ImplicitAPI):
58
58
  'cancelOrder': True,
59
59
  'cancelOrders': True,
60
60
  'createDepositAddress': True,
61
+ 'createMarketBuyOrderWithCost': True,
62
+ 'createMarketOrderWithCost': False,
63
+ 'createMarketSellOrderWithCost': False,
61
64
  'createOrder': True,
62
65
  'createStopLimitOrder': True,
63
66
  'createStopMarketOrder': True,
@@ -1308,6 +1311,33 @@ class kraken(Exchange, ImplicitAPI):
1308
1311
  #
1309
1312
  return self.parse_balance(response)
1310
1313
 
1314
+ async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
1315
+ """
1316
+ create a market order by providing the symbol, side and cost
1317
+ :see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
1318
+ :param str symbol: unified symbol of the market to create an order in(only USD markets are supported)
1319
+ :param str side: 'buy' or 'sell'
1320
+ :param float cost: how much you want to trade in units of the quote currency
1321
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1322
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1323
+ """
1324
+ await self.load_markets()
1325
+ # only buy orders are supported by the endpoint
1326
+ params['cost'] = cost
1327
+ return await self.create_order(symbol, 'market', side, cost, None, params)
1328
+
1329
+ async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
1330
+ """
1331
+ create a market buy order by providing the symbol, side and cost
1332
+ :see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
1333
+ :param str symbol: unified symbol of the market to create an order in
1334
+ :param float cost: how much you want to trade in units of the quote currency
1335
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1336
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1337
+ """
1338
+ await self.load_markets()
1339
+ return await self.create_market_order_with_cost(symbol, 'buy', cost, params)
1340
+
1311
1341
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1312
1342
  """
1313
1343
  :see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
@@ -1336,7 +1366,7 @@ class kraken(Exchange, ImplicitAPI):
1336
1366
  'ordertype': type,
1337
1367
  'volume': self.amount_to_precision(symbol, amount),
1338
1368
  }
1339
- orderRequest = self.order_request('createOrder', symbol, type, request, price, params)
1369
+ orderRequest = self.order_request('createOrder', symbol, type, request, amount, price, params)
1340
1370
  response = await self.privatePostAddOrder(self.extend(orderRequest[0], orderRequest[1]))
1341
1371
  #
1342
1372
  # {
@@ -1616,7 +1646,7 @@ class kraken(Exchange, ImplicitAPI):
1616
1646
  'trades': trades,
1617
1647
  }, market)
1618
1648
 
1619
- def order_request(self, method, symbol, type, request, price=None, params={}):
1649
+ def order_request(self, method: str, symbol: str, type: str, request: dict, amount: Num, price: Num = None, params={}):
1620
1650
  clientOrderId = self.safe_string_2(params, 'userref', 'clientOrderId')
1621
1651
  params = self.omit(params, ['userref', 'clientOrderId'])
1622
1652
  if clientOrderId is not None:
@@ -1630,9 +1660,21 @@ class kraken(Exchange, ImplicitAPI):
1630
1660
  trailingLimitAmount = self.safe_string(params, 'trailingLimitAmount')
1631
1661
  isTrailingAmountOrder = trailingAmount is not None
1632
1662
  isLimitOrder = type.endswith('limit') # supporting limit, stop-loss-limit, take-profit-limit, etc
1633
- if isLimitOrder and not isTrailingAmountOrder:
1663
+ isMarketOrder = type == 'market'
1664
+ cost = self.safe_string(params, 'cost')
1665
+ flags = self.safe_string(params, 'oflags')
1666
+ params = self.omit(params, ['cost', 'oflags'])
1667
+ isViqcOrder = (flags is not None) and (flags.find('viqc') > -1) # volume in quote currency
1668
+ if isMarketOrder and (cost is not None or isViqcOrder):
1669
+ if cost is None and (amount is not None):
1670
+ request['volume'] = self.cost_to_precision(symbol, self.number_to_string(amount))
1671
+ else:
1672
+ request['volume'] = self.cost_to_precision(symbol, cost)
1673
+ extendedOflags = flags + ',viqc' if (flags is not None) else 'viqc'
1674
+ request['oflags'] = extendedOflags
1675
+ elif isLimitOrder and not isTrailingAmountOrder:
1634
1676
  request['price'] = self.price_to_precision(symbol, price)
1635
- reduceOnly = self.safe_value_2(params, 'reduceOnly', 'reduce_only')
1677
+ reduceOnly = self.safe_bool_2(params, 'reduceOnly', 'reduce_only')
1636
1678
  if isStopLossOrTakeProfitTrigger:
1637
1679
  if isStopLossTriggerOrder:
1638
1680
  request['price'] = self.price_to_precision(symbol, stopLossTriggerPrice)
@@ -1666,7 +1708,7 @@ class kraken(Exchange, ImplicitAPI):
1666
1708
  request['reduce_only'] = True # ws request can't have stringified bool
1667
1709
  else:
1668
1710
  request['reduce_only'] = 'true' # not using hasattr(self, boolean) case, because the urlencodedNested transforms it into 'True' string
1669
- close = self.safe_value(params, 'close')
1711
+ close = self.safe_dict(params, 'close')
1670
1712
  if close is not None:
1671
1713
  close = self.extend({}, close)
1672
1714
  closePrice = self.safe_value(close, 'price')
@@ -1683,7 +1725,8 @@ class kraken(Exchange, ImplicitAPI):
1683
1725
  postOnly = None
1684
1726
  postOnly, params = self.handle_post_only(isMarket, False, params)
1685
1727
  if postOnly:
1686
- request['oflags'] = 'post'
1728
+ extendedPostFlags = flags + ',post' if (flags is not None) else 'post'
1729
+ request['oflags'] = extendedPostFlags
1687
1730
  params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingLimitAmount', 'offset'])
1688
1731
  return [request, params]
1689
1732
 
@@ -1716,7 +1759,7 @@ class kraken(Exchange, ImplicitAPI):
1716
1759
  }
1717
1760
  if amount is not None:
1718
1761
  request['volume'] = self.amount_to_precision(symbol, amount)
1719
- orderRequest = self.order_request('editOrder', symbol, type, request, price, params)
1762
+ orderRequest = self.order_request('editOrder', symbol, type, request, amount, price, params)
1720
1763
  response = await self.privatePostEditOrder(self.extend(orderRequest[0], orderRequest[1]))
1721
1764
  #
1722
1765
  # {
@@ -2808,6 +2851,8 @@ class kraken(Exchange, ImplicitAPI):
2808
2851
  raise CancelPending(self.id + ' ' + body)
2809
2852
  if body.find('Invalid arguments:volume') >= 0:
2810
2853
  raise InvalidOrder(self.id + ' ' + body)
2854
+ if body.find('Invalid arguments:viqc') >= 0:
2855
+ raise InvalidOrder(self.id + ' ' + body)
2811
2856
  if body.find('Rate limit exceeded') >= 0:
2812
2857
  raise RateLimitExceeded(self.id + ' ' + body)
2813
2858
  if response is None:
@@ -4490,6 +4490,7 @@ class kucoin(Exchange, ImplicitAPI):
4490
4490
  partnerSignature = self.hmac(self.encode(partnerPayload), self.encode(partnerSecret), hashlib.sha256, 'base64')
4491
4491
  headers['KC-API-PARTNER-SIGN'] = partnerSignature
4492
4492
  headers['KC-API-PARTNER'] = partnerId
4493
+ headers['KC-API-PARTNER-VERIFY'] = 'true'
4493
4494
  if isBroker:
4494
4495
  brokerName = self.safe_string(partner, 'name')
4495
4496
  if brokerName is not None:
@@ -2168,7 +2168,7 @@ class phemex(Exchange, ImplicitAPI):
2168
2168
  if feeCost is not None:
2169
2169
  fee = {
2170
2170
  'cost': feeCost,
2171
- 'currency': None,
2171
+ 'currency': self.safe_currency_code(self.safe_string(order, 'feeCurrency')),
2172
2172
  }
2173
2173
  timeInForce = self.parse_time_in_force(self.safe_string(order, 'timeInForce'))
2174
2174
  stopPrice = self.parse_number(self.omit_zero(self.from_ep(self.safe_string(order, 'stopPxEp'))))
@@ -2313,6 +2313,7 @@ class phemex(Exchange, ImplicitAPI):
2313
2313
  clientOrderId = None
2314
2314
  marketId = self.safe_string(order, 'symbol')
2315
2315
  symbol = self.safe_symbol(marketId, market)
2316
+ market = self.safe_market(marketId, market)
2316
2317
  status = self.parse_order_status(self.safe_string(order, 'ordStatus'))
2317
2318
  side = self.parse_order_side(self.safe_string_lower(order, 'side'))
2318
2319
  type = self.parse_order_type(self.safe_string(order, 'orderType'))
@@ -2338,6 +2339,19 @@ class phemex(Exchange, ImplicitAPI):
2338
2339
  reduceOnly = True
2339
2340
  takeProfit = self.safe_string(order, 'takeProfitRp')
2340
2341
  stopLoss = self.safe_string(order, 'stopLossRp')
2342
+ feeValue = self.omit_zero(self.safe_string(order, 'execFeeRv'))
2343
+ ptFeeRv = self.omit_zero(self.safe_string(order, 'ptFeeRv'))
2344
+ fee = None
2345
+ if feeValue is not None:
2346
+ fee = {
2347
+ 'cost': feeValue,
2348
+ 'currency': market['quote'],
2349
+ }
2350
+ elif ptFeeRv is not None:
2351
+ fee = {
2352
+ 'cost': ptFeeRv,
2353
+ 'currency': 'PT',
2354
+ }
2341
2355
  return self.safe_order({
2342
2356
  'info': order,
2343
2357
  'id': id,
@@ -2362,7 +2376,7 @@ class phemex(Exchange, ImplicitAPI):
2362
2376
  'cost': cost,
2363
2377
  'average': None,
2364
2378
  'status': status,
2365
- 'fee': None,
2379
+ 'fee': fee,
2366
2380
  'trades': None,
2367
2381
  })
2368
2382
 
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.23'
7
+ __version__ = '4.3.27'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -1689,11 +1689,14 @@ class Exchange(object):
1689
1689
  return default
1690
1690
 
1691
1691
  def omit_zero(self, string_number):
1692
- if string_number is None or string_number == '':
1693
- return None
1694
- if float(string_number) == 0:
1695
- return None
1696
- return string_number
1692
+ try:
1693
+ if string_number is None or string_number == '':
1694
+ return None
1695
+ if float(string_number) == 0:
1696
+ return None
1697
+ return string_number
1698
+ except Exception:
1699
+ return string_number
1697
1700
 
1698
1701
  def check_order_arguments(self, market, type, side, amount, price, params):
1699
1702
  if price is None:
@@ -3621,12 +3624,24 @@ class Exchange(object):
3621
3624
  params = self.omit(params, paramName)
3622
3625
  return [value, params]
3623
3626
 
3627
+ def handle_param_string_2(self, params: object, paramName1: str, paramName2: str, defaultValue: Str = None):
3628
+ value = self.safe_string_2(params, paramName1, paramName2, defaultValue)
3629
+ if value is not None:
3630
+ params = self.omit(params, [paramName1, paramName2])
3631
+ return [value, params]
3632
+
3624
3633
  def handle_param_integer(self, params: object, paramName: str, defaultValue: Int = None):
3625
3634
  value = self.safe_integer(params, paramName, defaultValue)
3626
3635
  if value is not None:
3627
3636
  params = self.omit(params, paramName)
3628
3637
  return [value, params]
3629
3638
 
3639
+ def handle_param_integer_2(self, params: object, paramName1: str, paramName2: str, defaultValue: Int = None):
3640
+ value = self.safe_integer_2(params, paramName1, paramName2, defaultValue)
3641
+ if value is not None:
3642
+ params = self.omit(params, [paramName1, paramName2])
3643
+ return [value, params]
3644
+
3630
3645
  def resolve_path(self, path, params):
3631
3646
  return [
3632
3647
  self.implode_params(path, params),
@@ -3752,7 +3767,7 @@ class Exchange(object):
3752
3767
  self.cancelOrder(id, symbol)
3753
3768
  return self.create_order(symbol, type, side, amount, price, params)
3754
3769
 
3755
- def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
3770
+ def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
3756
3771
  self.cancelOrderWs(id, symbol)
3757
3772
  return self.createOrderWs(symbol, type, side, amount, price, params)
3758
3773
 
@@ -3988,25 +4003,13 @@ class Exchange(object):
3988
4003
  value = value if (value is not None) else defaultValue
3989
4004
  return [value, params]
3990
4005
 
3991
- def handle_option_and_params_2(self, params: object, methodName: str, methodName2: str, optionName: str, defaultValue=None):
3992
- # This method can be used to obtain method specific properties, i.e: self.handle_option_and_params(params, 'fetchPosition', 'marginMode', 'isolated')
3993
- defaultOptionName = 'default' + self.capitalize(optionName) # we also need to check the 'defaultXyzWhatever'
3994
- # check if params contain the key
3995
- value = self.safe_value_2(params, optionName, defaultOptionName)
3996
- if value is not None:
3997
- params = self.omit(params, [optionName, defaultOptionName])
3998
- else:
3999
- # check if exchange has properties for self method
4000
- exchangeWideMethodOptions = self.safe_value_2(self.options, methodName, methodName2)
4001
- if exchangeWideMethodOptions is not None:
4002
- # check if the option is defined inside self method's props
4003
- value = self.safe_value_2(exchangeWideMethodOptions, optionName, defaultOptionName)
4004
- if value is None:
4005
- # if it's still None, check if global exchange-wide option exists
4006
- value = self.safe_value_2(self.options, optionName, defaultOptionName)
4007
- # if it's still None, use the default value
4008
- value = value if (value is not None) else defaultValue
4009
- return [value, params]
4006
+ def handle_option_and_params_2(self, params: object, methodName1: str, optionName1: str, optionName2: str, defaultValue=None):
4007
+ value = None
4008
+ value, params = self.handle_option_and_params(params, methodName1, optionName1, defaultValue)
4009
+ # if still None, try optionName2
4010
+ value2 = None
4011
+ value2, params = self.handle_option_and_params(params, methodName1, optionName2, value)
4012
+ return [value2, params]
4010
4013
 
4011
4014
  def handle_option(self, methodName: str, optionName: str, defaultValue=None):
4012
4015
  # eslint-disable-next-line no-unused-vars
@@ -5566,8 +5569,9 @@ class Exchange(object):
5566
5569
  errors = 0
5567
5570
  responseLength = len(response)
5568
5571
  if self.verbose:
5569
- iteration = (i + str(1))
5570
- cursorMessage = 'Cursor pagination call ' + iteration + ' method ' + method + ' response length ' + str(responseLength) + ' cursor ' + cursorValue
5572
+ cursorString = '' if (cursorValue is None) else cursorValue
5573
+ iteration = (i + 1)
5574
+ cursorMessage = 'Cursor pagination call ' + str(iteration) + ' method ' + method + ' response length ' + str(responseLength) + ' cursor ' + cursorString
5571
5575
  self.log(cursorMessage)
5572
5576
  if responseLength == 0:
5573
5577
  break
ccxt/bitrue.py CHANGED
@@ -2932,6 +2932,10 @@ class bitrue(Exchange, ImplicitAPI):
2932
2932
  signPath = signPath + '/' + version + '/' + path
2933
2933
  signMessage = timestamp + method + signPath
2934
2934
  if method == 'GET':
2935
+ keys = list(params.keys())
2936
+ keysLength = len(keys)
2937
+ if keysLength > 0:
2938
+ signMessage += '?' + self.urlencode(params)
2935
2939
  signature = self.hmac(self.encode(signMessage), self.encode(self.secret), hashlib.sha256)
2936
2940
  headers = {
2937
2941
  'X-CH-APIKEY': self.apiKey,
@@ -2944,7 +2948,7 @@ class bitrue(Exchange, ImplicitAPI):
2944
2948
  'recvWindow': recvWindow,
2945
2949
  }, params)
2946
2950
  body = self.json(query)
2947
- signMessage = signMessage + json.dumps(body)
2951
+ signMessage += body
2948
2952
  signature = self.hmac(self.encode(signMessage), self.encode(self.secret), hashlib.sha256)
2949
2953
  headers = {
2950
2954
  'Content-Type': 'application/json',
@@ -0,0 +1,17 @@
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.coinbase import coinbase
7
+ from ccxt.abstract.coinbaseadvanced import ImplicitAPI
8
+
9
+
10
+ class coinbaseadvanced(coinbase, ImplicitAPI):
11
+
12
+ def describe(self):
13
+ return self.deep_extend(super(coinbaseadvanced, self).describe(), {
14
+ 'id': 'coinbaseadvanced',
15
+ 'name': 'Coinbase Advanced',
16
+ 'alias': True,
17
+ })
@@ -4,7 +4,7 @@
4
4
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
5
 
6
6
  from ccxt.base.exchange import Exchange
7
- from ccxt.abstract.coinbasepro import ImplicitAPI
7
+ from ccxt.abstract.coinbaseexchange import ImplicitAPI
8
8
  import hashlib
9
9
  from ccxt.base.types import Account, Balances, Currencies, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees, Transaction
10
10
  from typing import List
@@ -22,12 +22,12 @@ from ccxt.base.decimal_to_precision import TICK_SIZE
22
22
  from ccxt.base.precise import Precise
23
23
 
24
24
 
25
- class coinbasepro(Exchange, ImplicitAPI):
25
+ class coinbaseexchange(Exchange, ImplicitAPI):
26
26
 
27
27
  def describe(self):
28
- return self.deep_extend(super(coinbasepro, self).describe(), {
29
- 'id': 'coinbasepro',
30
- 'name': 'Coinbase Pro(Deprecated)',
28
+ return self.deep_extend(super(coinbaseexchange, self).describe(), {
29
+ 'id': 'coinbaseexchange',
30
+ 'name': 'Coinbase Exchange',
31
31
  'countries': ['US'],
32
32
  'rateLimit': 100,
33
33
  'userAgent': self.userAgents['chrome'],
@@ -89,19 +89,19 @@ class coinbasepro(Exchange, ImplicitAPI):
89
89
  '6h': 21600,
90
90
  '1d': 86400,
91
91
  },
92
- 'hostname': 'pro.coinbase.com',
92
+ 'hostname': 'exchange.coinbase.com',
93
93
  'urls': {
94
94
  'test': {
95
- 'public': 'https://api-public.sandbox.pro.coinbase.com',
96
- 'private': 'https://api-public.sandbox.pro.coinbase.com',
95
+ 'public': 'https://api-public.sandbox.exchange.coinbase.com',
96
+ 'private': 'https://api-public.sandbox.exchange.coinbase.com',
97
97
  },
98
- 'logo': 'https://user-images.githubusercontent.com/1294454/41764625-63b7ffde-760a-11e8-996d-a6328fa9347a.jpg',
98
+ 'logo': 'https://github.com/ccxt/ccxt/assets/43336371/34a65553-88aa-4a38-a714-064bd228b97e',
99
99
  'api': {
100
100
  'public': 'https://api.{hostname}',
101
101
  'private': 'https://api.{hostname}',
102
102
  },
103
- 'www': 'https://pro.coinbase.com/',
104
- 'doc': 'https://docs.pro.coinbase.com',
103
+ 'www': 'https://coinbase.com/',
104
+ 'doc': 'https://docs.cloud.coinbase.com/exchange/docs/',
105
105
  'fees': [
106
106
  'https://docs.pro.coinbase.com/#fees',
107
107
  'https://support.pro.coinbase.com/customer/en/portal/articles/2945310-fees',
@@ -315,7 +315,7 @@ class coinbasepro(Exchange, ImplicitAPI):
315
315
 
316
316
  def fetch_markets(self, params={}) -> List[Market]:
317
317
  """
318
- retrieves data on all markets for coinbasepro
318
+ retrieves data on all markets for coinbaseexchange
319
319
  :see: https://docs.cloud.coinbase.com/exchange/reference/exchangerestapi_getproducts
320
320
  :param dict [params]: extra parameters specific to the exchange API endpoint
321
321
  :returns dict[]: an array of objects representing market data
@@ -1047,7 +1047,7 @@ class coinbasepro(Exchange, ImplicitAPI):
1047
1047
  """
1048
1048
  :see: https://docs.cloud.coinbase.com/exchange/reference/exchangerestapi_getorder
1049
1049
  fetches information on an order made by the user
1050
- :param str symbol: not used by coinbasepro fetchOrder
1050
+ :param str symbol: not used by coinbaseexchange fetchOrder
1051
1051
  :param dict [params]: extra parameters specific to the exchange API endpoint
1052
1052
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1053
1053
  """