ccxt 4.3.24__py2.py3-none-any.whl → 4.3.28__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/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.24'
7
+ __version__ = '4.3.28'
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:
@@ -2652,6 +2655,7 @@ class Exchange(object):
2652
2655
  shouldParseFees = parseFee or parseFees
2653
2656
  fees = self.safe_list(order, 'fees', [])
2654
2657
  trades = []
2658
+ isTriggerOrSLTpOrder = ((self.safe_string(order, 'triggerPrice') is not None or (self.safe_string(order, 'stopLossPrice') is not None)) or (self.safe_string(order, 'takeProfitPrice') is not None))
2655
2659
  if parseFilled or parseCost or shouldParseFees:
2656
2660
  rawTrades = self.safe_value(order, 'trades', trades)
2657
2661
  oldNumber = self.number
@@ -2802,7 +2806,7 @@ class Exchange(object):
2802
2806
  postOnly = self.safe_value(order, 'postOnly')
2803
2807
  # timeInForceHandling
2804
2808
  if timeInForce is None:
2805
- if self.safe_string(order, 'type') == 'market':
2809
+ if not isTriggerOrSLTpOrder and (self.safe_string(order, 'type') == 'market'):
2806
2810
  timeInForce = 'IOC'
2807
2811
  # allow postOnly override
2808
2812
  if postOnly:
@@ -3621,12 +3625,24 @@ class Exchange(object):
3621
3625
  params = self.omit(params, paramName)
3622
3626
  return [value, params]
3623
3627
 
3628
+ def handle_param_string_2(self, params: object, paramName1: str, paramName2: str, defaultValue: Str = None):
3629
+ value = self.safe_string_2(params, paramName1, paramName2, defaultValue)
3630
+ if value is not None:
3631
+ params = self.omit(params, [paramName1, paramName2])
3632
+ return [value, params]
3633
+
3624
3634
  def handle_param_integer(self, params: object, paramName: str, defaultValue: Int = None):
3625
3635
  value = self.safe_integer(params, paramName, defaultValue)
3626
3636
  if value is not None:
3627
3637
  params = self.omit(params, paramName)
3628
3638
  return [value, params]
3629
3639
 
3640
+ def handle_param_integer_2(self, params: object, paramName1: str, paramName2: str, defaultValue: Int = None):
3641
+ value = self.safe_integer_2(params, paramName1, paramName2, defaultValue)
3642
+ if value is not None:
3643
+ params = self.omit(params, [paramName1, paramName2])
3644
+ return [value, params]
3645
+
3630
3646
  def resolve_path(self, path, params):
3631
3647
  return [
3632
3648
  self.implode_params(path, params),
@@ -3752,7 +3768,7 @@ class Exchange(object):
3752
3768
  self.cancelOrder(id, symbol)
3753
3769
  return self.create_order(symbol, type, side, amount, price, params)
3754
3770
 
3755
- def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
3771
+ def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
3756
3772
  self.cancelOrderWs(id, symbol)
3757
3773
  return self.createOrderWs(symbol, type, side, amount, price, params)
3758
3774
 
@@ -3988,25 +4004,13 @@ class Exchange(object):
3988
4004
  value = value if (value is not None) else defaultValue
3989
4005
  return [value, params]
3990
4006
 
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]
4007
+ def handle_option_and_params_2(self, params: object, methodName1: str, optionName1: str, optionName2: str, defaultValue=None):
4008
+ value = None
4009
+ value, params = self.handle_option_and_params(params, methodName1, optionName1, defaultValue)
4010
+ # if still None, try optionName2
4011
+ value2 = None
4012
+ value2, params = self.handle_option_and_params(params, methodName1, optionName2, value)
4013
+ return [value2, params]
4010
4014
 
4011
4015
  def handle_option(self, methodName: str, optionName: str, defaultValue=None):
4012
4016
  # eslint-disable-next-line no-unused-vars
ccxt/bingx.py CHANGED
@@ -2078,6 +2078,10 @@ class bingx(Exchange, ImplicitAPI):
2078
2078
  types = {
2079
2079
  'trigger_market': 'market',
2080
2080
  'trigger_limit': 'limit',
2081
+ 'stop_limit': 'limit',
2082
+ 'stop_market': 'market',
2083
+ 'take_profit_market': 'market',
2084
+ 'stop': 'limit',
2081
2085
  }
2082
2086
  return self.safe_string(types, type, type)
2083
2087
 
@@ -2281,6 +2285,25 @@ class bingx(Exchange, ImplicitAPI):
2281
2285
  # side: 'SELL'
2282
2286
  # }
2283
2287
  # }
2288
+ # stop loss order
2289
+ # {
2290
+ # "symbol": "ETH-USDT",
2291
+ # "orderId": "1792461744476422144",
2292
+ # "price": "2775.65",
2293
+ # "StopPrice": "2778.42",
2294
+ # "origQty": "0.032359",
2295
+ # "executedQty": "0",
2296
+ # "cummulativeQuoteQty": "0",
2297
+ # "status": "NEW",
2298
+ # "type": "TAKE_STOP_LIMIT",
2299
+ # "side": "SELL",
2300
+ # "time": "1716191156868",
2301
+ # "updateTime": "1716191156868",
2302
+ # "origQuoteOrderQty": "0",
2303
+ # "fee": "0",
2304
+ # "feeAsset": "USDT",
2305
+ # "clientOrderID": ""
2306
+ # }
2284
2307
  #
2285
2308
  info = order
2286
2309
  newOrder = self.safe_dict_2(order, 'newOrderResponse', 'orderOpenResponse')
@@ -2308,21 +2331,31 @@ class bingx(Exchange, ImplicitAPI):
2308
2331
  stopLoss = self.safe_value(order, 'stopLoss')
2309
2332
  stopLossPrice = None
2310
2333
  if (stopLoss is not None) and (stopLoss != ''):
2311
- stopLossPrice = self.safe_number(stopLoss, 'stopLoss')
2334
+ stopLossPrice = self.omit_zero(self.safe_string(stopLoss, 'stopLoss'))
2312
2335
  if (stopLoss is not None) and ((not isinstance(stopLoss, numbers.Real))) and (stopLoss != ''):
2313
2336
  # stopLoss: '{"stopPrice":50,"workingType":"MARK_PRICE","type":"STOP_MARKET","quantity":1}',
2314
2337
  if isinstance(stopLoss, str):
2315
2338
  stopLoss = self.parse_json(stopLoss)
2316
- stopLossPrice = self.safe_number(stopLoss, 'stopPrice')
2339
+ stopLossPrice = self.omit_zero(self.safe_string(stopLoss, 'stopPrice'))
2317
2340
  takeProfit = self.safe_value(order, 'takeProfit')
2318
2341
  takeProfitPrice = None
2319
2342
  if takeProfit is not None and (takeProfit != ''):
2320
- takeProfitPrice = self.safe_number(takeProfit, 'takeProfit')
2343
+ takeProfitPrice = self.omit_zero(self.safe_string(takeProfit, 'takeProfit'))
2321
2344
  if (takeProfit is not None) and ((not isinstance(takeProfit, numbers.Real))) and (takeProfit != ''):
2322
2345
  # takeProfit: '{"stopPrice":150,"workingType":"MARK_PRICE","type":"TAKE_PROFIT_MARKET","quantity":1}',
2323
2346
  if isinstance(takeProfit, str):
2324
2347
  takeProfit = self.parse_json(takeProfit)
2325
- takeProfitPrice = self.safe_number(takeProfit, 'stopPrice')
2348
+ takeProfitPrice = self.omit_zero(self.safe_string(takeProfit, 'stopPrice'))
2349
+ rawType = self.safe_string_lower_2(order, 'type', 'o')
2350
+ stopPrice = self.omit_zero(self.safe_string_2(order, 'StopPrice', 'stopPrice'))
2351
+ triggerPrice = stopPrice
2352
+ if stopPrice is not None:
2353
+ if (rawType.find('stop') > -1) and (stopLossPrice is None):
2354
+ stopLossPrice = stopPrice
2355
+ triggerPrice = None
2356
+ if (rawType.find('take') > -1) and (takeProfitPrice is None):
2357
+ takeProfitPrice = stopPrice
2358
+ triggerPrice = None
2326
2359
  return self.safe_order({
2327
2360
  'info': info,
2328
2361
  'id': self.safe_string_2(order, 'orderId', 'i'),
@@ -2332,13 +2365,13 @@ class bingx(Exchange, ImplicitAPI):
2332
2365
  'datetime': self.iso8601(timestamp),
2333
2366
  'lastTradeTimestamp': lastTradeTimestamp,
2334
2367
  'lastUpdateTimestamp': self.safe_integer(order, 'updateTime'),
2335
- 'type': self.parse_order_type(self.safe_string_lower_2(order, 'type', 'o')),
2368
+ 'type': self.parse_order_type(rawType),
2336
2369
  'timeInForce': self.safe_string(order, 'timeInForce'),
2337
2370
  'postOnly': None,
2338
2371
  'side': self.parse_order_side(side),
2339
2372
  'price': self.safe_string_2(order, 'price', 'p'),
2340
- 'stopPrice': self.safe_number(order, 'stopPrice'),
2341
- 'triggerPrice': self.safe_number(order, 'stopPrice'),
2373
+ 'stopPrice': triggerPrice,
2374
+ 'triggerPrice': triggerPrice,
2342
2375
  'stopLossPrice': stopLossPrice,
2343
2376
  'takeProfitPrice': takeProfitPrice,
2344
2377
  'average': self.safe_string_2(order, 'avgPrice', 'ap'),
ccxt/bitget.py CHANGED
@@ -778,6 +778,7 @@ class bitget(Exchange, ImplicitAPI):
778
778
  'v2/earn/loan/borrow-history': 2,
779
779
  'v2/earn/loan/debts': 2,
780
780
  'v2/earn/loan/reduces': 2,
781
+ 'v2/earn/account/assets': 2,
781
782
  },
782
783
  'post': {
783
784
  'v2/earn/savings/subscribe': 2,
ccxt/bitmart.py CHANGED
@@ -54,7 +54,7 @@ class bitmart(Exchange, ImplicitAPI):
54
54
  'borrowIsolatedMargin': True,
55
55
  'cancelAllOrders': True,
56
56
  'cancelOrder': True,
57
- 'cancelOrders': False,
57
+ 'cancelOrders': True,
58
58
  'createMarketBuyOrderWithCost': True,
59
59
  'createMarketOrderWithCost': False,
60
60
  'createMarketSellOrderWithCost': False,
@@ -198,7 +198,7 @@ class bitmart(Exchange, ImplicitAPI):
198
198
  'spot/v2/orders': 5,
199
199
  'spot/v1/trades': 5,
200
200
  # newer order endpoint
201
- 'spot/v2/trades': 5,
201
+ 'spot/v2/trades': 4,
202
202
  'spot/v3/orders': 5,
203
203
  'spot/v2/order_detail': 1,
204
204
  # margin
@@ -242,6 +242,7 @@ class bitmart(Exchange, ImplicitAPI):
242
242
  'spot/v4/query/history-orders': 5, # 12 times/2 sec = 6/s => 30/6 = 5
243
243
  'spot/v4/query/trades': 5, # 12 times/2 sec = 6/s => 30/6 = 5
244
244
  'spot/v4/query/order-trades': 5, # 12 times/2 sec = 6/s => 30/6 = 5
245
+ 'spot/v4/cancel_orders': 3,
245
246
  # newer endpoint
246
247
  'spot/v3/cancel_order': 1,
247
248
  'spot/v2/batch_orders': 1,
@@ -2523,6 +2524,60 @@ class bitmart(Exchange, ImplicitAPI):
2523
2524
  order = self.parse_order(id, market)
2524
2525
  return self.extend(order, {'id': id})
2525
2526
 
2527
+ def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
2528
+ """
2529
+ cancel multiple orders
2530
+ :see: https://developer-pro.bitmart.com/en/spot/#cancel-batch-order-v4-signed
2531
+ :param str[] ids: order ids
2532
+ :param str symbol: unified symbol of the market the order was made in
2533
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2534
+ :param str[] [params.clientOrderIds]: client order ids
2535
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2536
+ """
2537
+ if symbol is None:
2538
+ raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
2539
+ self.load_markets()
2540
+ market = self.market(symbol)
2541
+ if not market['spot']:
2542
+ raise NotSupported(self.id + ' cancelOrders() does not support ' + market['type'] + ' orders, only spot orders are accepted')
2543
+ clientOrderIds = self.safe_list(params, 'clientOrderIds')
2544
+ params = self.omit(params, ['clientOrderIds'])
2545
+ request = {
2546
+ 'symbol': market['id'],
2547
+ }
2548
+ if clientOrderIds is not None:
2549
+ request['clientOrderIds'] = clientOrderIds
2550
+ else:
2551
+ request['orderIds'] = ids
2552
+ response = self.privatePostSpotV4CancelOrders(self.extend(request, params))
2553
+ #
2554
+ # {
2555
+ # "message": "OK",
2556
+ # "code": 1000,
2557
+ # "trace": "c4edbce860164203954f7c3c81d60fc6.309.17022669632770001",
2558
+ # "data": {
2559
+ # "successIds": [
2560
+ # "213055379155243012"
2561
+ # ],
2562
+ # "failIds": [],
2563
+ # "totalCount": 1,
2564
+ # "successCount": 1,
2565
+ # "failedCount": 0
2566
+ # }
2567
+ # }
2568
+ #
2569
+ data = self.safe_dict(response, 'data', {})
2570
+ allOrders = []
2571
+ successIds = self.safe_list(data, 'successIds', [])
2572
+ for i in range(0, len(successIds)):
2573
+ id = successIds[i]
2574
+ allOrders.append(self.safe_order({'id': id, 'status': 'canceled'}, market))
2575
+ failIds = self.safe_list(data, 'failIds', [])
2576
+ for i in range(0, len(failIds)):
2577
+ id = failIds[i]
2578
+ allOrders.append(self.safe_order({'id': id, 'status': 'failed'}, market))
2579
+ return allOrders
2580
+
2526
2581
  def cancel_all_orders(self, symbol: Str = None, params={}):
2527
2582
  """
2528
2583
  cancel all open orders in a market
ccxt/bybit.py CHANGED
@@ -2400,12 +2400,12 @@ class bybit(Exchange, ImplicitAPI):
2400
2400
  if symbol is None:
2401
2401
  raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
2402
2402
  self.load_markets()
2403
- if limit is None:
2404
- limit = 200
2405
2403
  paginate = False
2406
2404
  paginate, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'paginate')
2407
2405
  if paginate:
2408
2406
  return self.fetch_paginated_call_deterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params, 200)
2407
+ if limit is None:
2408
+ limit = 200
2409
2409
  request = {
2410
2410
  # 'category': '', # Product type. linear,inverse
2411
2411
  # 'symbol': '', # Symbol name
ccxt/coinbase.py CHANGED
@@ -2844,7 +2844,7 @@ class coinbase(Exchange, ImplicitAPI):
2844
2844
  marketId = self.safe_string(order, 'product_id')
2845
2845
  symbol = self.safe_symbol(marketId, market, '-')
2846
2846
  if symbol is not None:
2847
- market = self.market(symbol)
2847
+ market = self.safe_market(symbol, market)
2848
2848
  orderConfiguration = self.safe_dict(order, 'order_configuration', {})
2849
2849
  limitGTC = self.safe_dict(orderConfiguration, 'limit_limit_gtc')
2850
2850
  limitGTD = self.safe_dict(orderConfiguration, 'limit_limit_gtd')
ccxt/coinex.py CHANGED
@@ -457,11 +457,16 @@ class coinex(Exchange, ImplicitAPI):
457
457
  'fetchDepositAddress': {
458
458
  'fillResponseFromRequest': True,
459
459
  },
460
- 'accountsById': {
460
+ 'accountsByType': {
461
461
  'spot': 'SPOT',
462
462
  'margin': 'MARGIN',
463
463
  'swap': 'FUTURES',
464
464
  },
465
+ 'accountsById': {
466
+ 'SPOT': 'spot',
467
+ 'MARGIN': 'margin',
468
+ 'FUTURES': 'swap',
469
+ },
465
470
  'networks': {
466
471
  'BEP20': 'BSC',
467
472
  'TRX': 'TRC20',
@@ -4615,9 +4620,9 @@ class coinex(Exchange, ImplicitAPI):
4615
4620
  self.load_markets()
4616
4621
  currency = self.currency(code)
4617
4622
  amountToPrecision = self.currency_to_precision(code, amount)
4618
- accountsById = self.safe_dict(self.options, 'accountsById', {})
4619
- fromId = self.safe_string(accountsById, fromAccount, fromAccount)
4620
- toId = self.safe_string(accountsById, toAccount, toAccount)
4623
+ accountsByType = self.safe_dict(self.options, 'accountsById', {})
4624
+ fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
4625
+ toId = self.safe_string(accountsByType, toAccount, toAccount)
4621
4626
  request = {
4622
4627
  'ccy': currency['id'],
4623
4628
  'amount': amountToPrecision,
@@ -4651,6 +4656,8 @@ class coinex(Exchange, ImplicitAPI):
4651
4656
  '0': 'ok',
4652
4657
  'SUCCESS': 'ok',
4653
4658
  'OK': 'ok',
4659
+ 'finished': 'ok',
4660
+ 'FINISHED': 'ok',
4654
4661
  }
4655
4662
  return self.safe_string(statuses, status, status)
4656
4663
 
@@ -4674,91 +4681,55 @@ class coinex(Exchange, ImplicitAPI):
4674
4681
  def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> TransferEntries:
4675
4682
  """
4676
4683
  fetch a history of internal transfers made on an account
4677
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account025_margin_transfer_history
4678
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account024_contract_transfer_history
4684
+ :see: https://docs.coinex.com/api/v2/assets/transfer/http/list-transfer-history
4679
4685
  :param str code: unified currency code of the currency transferred
4680
4686
  :param int [since]: the earliest time in ms to fetch transfers for
4681
- :param int [limit]: the maximum number of transfers structures to retrieve
4687
+ :param int [limit]: the maximum number of transfer structures to retrieve
4682
4688
  :param dict [params]: extra parameters specific to the exchange API endpoint
4689
+ :param str [params.marginMode]: 'cross' or 'isolated' for fetching transfers to and from your margin account
4683
4690
  :returns dict[]: a list of `transfer structures <https://docs.ccxt.com/#/?id=transfer-structure>`
4684
4691
  """
4685
4692
  self.load_markets()
4686
- currency = None
4693
+ if code is None:
4694
+ raise ArgumentsRequired(self.id + ' fetchTransfers() requires a code argument')
4695
+ currency = self.currency(code)
4687
4696
  request = {
4688
- 'page': 1,
4689
- # 'limit': limit,
4690
- # 'asset': 'USDT',
4691
- # 'start_time': since,
4692
- # 'end_time': 1515806440,
4693
- # 'transfer_type': 'transfer_in', # transfer_in: from Spot to Swap Account, transfer_out: from Swap to Spot Account
4697
+ 'ccy': currency['id'],
4694
4698
  }
4695
- page = self.safe_integer(params, 'page')
4696
- if page is not None:
4697
- request['page'] = page
4698
- if code is not None:
4699
- currency = self.currency(code)
4700
- request['asset'] = currency['id']
4701
- if since is not None:
4702
- request['start_time'] = since
4703
- if limit is not None:
4704
- request['limit'] = limit
4705
- else:
4706
- request['limit'] = 100
4707
- params = self.omit(params, 'page')
4708
4699
  marginMode = None
4709
4700
  marginMode, params = self.handle_margin_mode_and_params('fetchTransfers', params)
4710
- response = None
4711
4701
  if marginMode is not None:
4712
- response = self.v1PrivateGetMarginTransferHistory(self.extend(request, params))
4702
+ request['transfer_type'] = 'MARGIN'
4713
4703
  else:
4714
- response = self.v1PrivateGetContractTransferHistory(self.extend(request, params))
4715
- #
4716
- # Swap
4704
+ request['transfer_type'] = 'FUTURES'
4705
+ if since is not None:
4706
+ request['start_time'] = since
4707
+ if limit is not None:
4708
+ request['limit'] = limit
4709
+ request, params = self.handle_until_option('end_time', request, params)
4710
+ response = self.v2PrivateGetAssetsTransferHistory(self.extend(request, params))
4717
4711
  #
4718
4712
  # {
4719
- # "code": 0,
4720
- # "data": {
4721
- # "records": [
4722
- # {
4723
- # "amount": "10",
4724
- # "asset": "USDT",
4725
- # "transfer_type": "transfer_out",
4726
- # "created_at": 1651633422
4727
- # },
4728
- # ],
4729
- # "total": 5
4713
+ # "data": [
4714
+ # {
4715
+ # "created_at": 1715848480646,
4716
+ # "from_account_type": "SPOT",
4717
+ # "to_account_type": "FUTURES",
4718
+ # "ccy": "USDT",
4719
+ # "amount": "10",
4720
+ # "status": "finished"
4721
+ # },
4722
+ # ],
4723
+ # "pagination": {
4724
+ # "total": 8,
4725
+ # "has_next": False
4730
4726
  # },
4731
- # "message": "Success"
4732
- # }
4733
- #
4734
- # Margin
4735
- #
4736
- # {
4737
4727
  # "code": 0,
4738
- # "data": {
4739
- # "records": [
4740
- # {
4741
- # "id": 7580062,
4742
- # "updated_at": 1653684379,
4743
- # "user_id": 3620173,
4744
- # "from_account_id": 0,
4745
- # "to_account_id": 1,
4746
- # "asset": "BTC",
4747
- # "amount": "0.00160829",
4748
- # "balance": "0.00160829",
4749
- # "transfer_type": "IN",
4750
- # "status": "SUCCESS",
4751
- # "created_at": 1653684379
4752
- # }
4753
- # ],
4754
- # "total": 1
4755
- # },
4756
- # "message": "Success"
4728
+ # "message": "OK"
4757
4729
  # }
4758
4730
  #
4759
- data = self.safe_value(response, 'data', {})
4760
- transfers = self.safe_list(data, 'records', [])
4761
- return self.parse_transfers(transfers, currency, since, limit)
4731
+ data = self.safe_list(response, 'data', [])
4732
+ return self.parse_transfers(data, currency, since, limit)
4762
4733
 
4763
4734
  def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
4764
4735
  """
ccxt/kraken.py CHANGED
@@ -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
+ 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
+ self.load_markets()
1325
+ # only buy orders are supported by the endpoint
1326
+ params['cost'] = cost
1327
+ return self.create_order(symbol, 'market', side, cost, None, params)
1328
+
1329
+ 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
+ self.load_markets()
1339
+ return self.create_market_order_with_cost(symbol, 'buy', cost, params)
1340
+
1311
1341
  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 = 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 = 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:
ccxt/krakenfutures.py CHANGED
@@ -2099,7 +2099,7 @@ class krakenfutures(Exchange, ImplicitAPI):
2099
2099
 
2100
2100
  def fetch_positions(self, symbols: Strings = None, params={}):
2101
2101
  """
2102
- :see: https://docs.futures.kraken.com/#websocket-api-private-feeds-open-positions
2102
+ :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-account-information-get-open-positions
2103
2103
  Fetches current contract trading positions
2104
2104
  :param str[] symbols: List of unified symbols
2105
2105
  :param dict [params]: Not used by krakenfutures