ccxt 4.4.75__py2.py3-none-any.whl → 4.4.78__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. ccxt/__init__.py +3 -3
  2. ccxt/abstract/apex.py +31 -0
  3. ccxt/abstract/myokx.py +4 -0
  4. ccxt/abstract/okx.py +4 -0
  5. ccxt/abstract/upbit.py +51 -37
  6. ccxt/abstract/xt.py +3 -0
  7. ccxt/apex.py +1884 -0
  8. ccxt/ascendex.py +2 -2
  9. ccxt/async_support/__init__.py +3 -3
  10. ccxt/async_support/apex.py +1884 -0
  11. ccxt/async_support/ascendex.py +2 -2
  12. ccxt/async_support/base/exchange.py +2 -2
  13. ccxt/async_support/binance.py +39 -217
  14. ccxt/async_support/bingx.py +1 -1
  15. ccxt/async_support/bitfinex.py +2 -2
  16. ccxt/async_support/bitflyer.py +2 -2
  17. ccxt/async_support/bitget.py +135 -65
  18. ccxt/async_support/bitmart.py +2 -2
  19. ccxt/async_support/bitmex.py +6 -6
  20. ccxt/async_support/bitrue.py +48 -0
  21. ccxt/async_support/cex.py +1 -1
  22. ccxt/async_support/coinbase.py +29 -4
  23. ccxt/async_support/coincatch.py +66 -0
  24. ccxt/async_support/coinex.py +3 -1
  25. ccxt/async_support/coinlist.py +85 -2
  26. ccxt/async_support/cryptocom.py +2 -2
  27. ccxt/async_support/defx.py +1 -1
  28. ccxt/async_support/delta.py +1 -1
  29. ccxt/async_support/deribit.py +2 -2
  30. ccxt/async_support/derive.py +2 -2
  31. ccxt/async_support/digifinex.py +2 -2
  32. ccxt/async_support/gate.py +1 -1
  33. ccxt/async_support/hitbtc.py +5 -2
  34. ccxt/async_support/htx.py +2 -2
  35. ccxt/async_support/hyperliquid.py +13 -6
  36. ccxt/async_support/kraken.py +2 -2
  37. ccxt/async_support/krakenfutures.py +2 -2
  38. ccxt/async_support/kucoinfutures.py +2 -2
  39. ccxt/async_support/mexc.py +50 -52
  40. ccxt/async_support/okx.py +21 -9
  41. ccxt/async_support/oxfun.py +2 -2
  42. ccxt/async_support/paradex.py +5 -10
  43. ccxt/async_support/phemex.py +4 -3
  44. ccxt/async_support/poloniex.py +3 -3
  45. ccxt/async_support/probit.py +1 -0
  46. ccxt/async_support/tradeogre.py +2 -1
  47. ccxt/async_support/upbit.py +265 -89
  48. ccxt/async_support/vertex.py +2 -2
  49. ccxt/async_support/whitebit.py +1 -0
  50. ccxt/async_support/woo.py +5 -3
  51. ccxt/async_support/woofipro.py +2 -2
  52. ccxt/async_support/xt.py +115 -5
  53. ccxt/base/exchange.py +76 -3
  54. ccxt/binance.py +39 -217
  55. ccxt/bingx.py +1 -1
  56. ccxt/bitfinex.py +2 -2
  57. ccxt/bitflyer.py +2 -2
  58. ccxt/bitget.py +135 -65
  59. ccxt/bitmart.py +2 -2
  60. ccxt/bitmex.py +6 -6
  61. ccxt/bitrue.py +48 -0
  62. ccxt/cex.py +1 -1
  63. ccxt/coinbase.py +29 -4
  64. ccxt/coincatch.py +66 -0
  65. ccxt/coinex.py +3 -1
  66. ccxt/coinlist.py +85 -2
  67. ccxt/cryptocom.py +2 -2
  68. ccxt/defx.py +1 -1
  69. ccxt/delta.py +1 -1
  70. ccxt/deribit.py +2 -2
  71. ccxt/derive.py +2 -2
  72. ccxt/digifinex.py +2 -2
  73. ccxt/gate.py +1 -1
  74. ccxt/hitbtc.py +5 -2
  75. ccxt/htx.py +2 -2
  76. ccxt/hyperliquid.py +13 -6
  77. ccxt/kraken.py +2 -2
  78. ccxt/krakenfutures.py +2 -2
  79. ccxt/kucoinfutures.py +2 -2
  80. ccxt/mexc.py +50 -52
  81. ccxt/okx.py +21 -9
  82. ccxt/oxfun.py +2 -2
  83. ccxt/paradex.py +5 -10
  84. ccxt/phemex.py +4 -3
  85. ccxt/poloniex.py +3 -3
  86. ccxt/pro/__init__.py +5 -1
  87. ccxt/pro/apex.py +984 -0
  88. ccxt/pro/coinbase.py +4 -6
  89. ccxt/pro/gate.py +22 -2
  90. ccxt/pro/hollaex.py +2 -2
  91. ccxt/pro/hyperliquid.py +1 -1
  92. ccxt/pro/p2b.py +2 -2
  93. ccxt/pro/tradeogre.py +272 -0
  94. ccxt/probit.py +1 -0
  95. ccxt/test/tests_async.py +27 -0
  96. ccxt/test/tests_sync.py +27 -0
  97. ccxt/tradeogre.py +2 -1
  98. ccxt/upbit.py +265 -89
  99. ccxt/vertex.py +2 -2
  100. ccxt/whitebit.py +1 -0
  101. ccxt/woo.py +5 -3
  102. ccxt/woofipro.py +2 -2
  103. ccxt/xt.py +115 -5
  104. {ccxt-4.4.75.dist-info → ccxt-4.4.78.dist-info}/METADATA +4 -4
  105. {ccxt-4.4.75.dist-info → ccxt-4.4.78.dist-info}/RECORD +108 -106
  106. ccxt/abstract/ace.py +0 -15
  107. ccxt/ace.py +0 -1152
  108. ccxt/async_support/ace.py +0 -1152
  109. {ccxt-4.4.75.dist-info → ccxt-4.4.78.dist-info}/LICENSE.txt +0 -0
  110. {ccxt-4.4.75.dist-info → ccxt-4.4.78.dist-info}/WHEEL +0 -0
  111. {ccxt-4.4.75.dist-info → ccxt-4.4.78.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,7 @@
5
5
 
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.upbit import ImplicitAPI
8
- from ccxt.base.types import Any, Balances, Currency, DepositAddress, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, OrderBooks, Trade, TradingFeeInterface, Transaction
8
+ from ccxt.base.types import Any, Balances, Currency, DepositAddress, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, OrderBooks, Trade, TradingFeeInterface, TradingFees, Transaction
9
9
  from typing import List
10
10
  from ccxt.base.errors import ExchangeError
11
11
  from ccxt.base.errors import AuthenticationError
@@ -28,7 +28,7 @@ class upbit(Exchange, ImplicitAPI):
28
28
  'name': 'Upbit',
29
29
  'countries': ['KR'],
30
30
  'version': 'v1',
31
- 'rateLimit': 1000,
31
+ 'rateLimit': 50,
32
32
  'pro': True,
33
33
  # new metainfo interface
34
34
  'has': {
@@ -45,6 +45,7 @@ class upbit(Exchange, ImplicitAPI):
45
45
  'createMarketOrderWithCost': False,
46
46
  'createMarketSellOrderWithCost': False,
47
47
  'createOrder': True,
48
+ 'editOrder': True,
48
49
  'fetchBalance': True,
49
50
  'fetchCanceledOrders': True,
50
51
  'fetchClosedOrders': True,
@@ -75,7 +76,7 @@ class upbit(Exchange, ImplicitAPI):
75
76
  'fetchTickers': True,
76
77
  'fetchTrades': True,
77
78
  'fetchTradingFee': True,
78
- 'fetchTradingFees': False,
79
+ 'fetchTradingFees': True,
79
80
  'fetchTransactions': False,
80
81
  'fetchWithdrawal': True,
81
82
  'fetchWithdrawals': True,
@@ -83,6 +84,7 @@ class upbit(Exchange, ImplicitAPI):
83
84
  'withdraw': True,
84
85
  },
85
86
  'timeframes': {
87
+ '1s': 'seconds',
86
88
  '1m': 'minutes',
87
89
  '3m': 'minutes',
88
90
  '5m': 'minutes',
@@ -94,6 +96,7 @@ class upbit(Exchange, ImplicitAPI):
94
96
  '1d': 'days',
95
97
  '1w': 'weeks',
96
98
  '1M': 'months',
99
+ '1y': 'years',
97
100
  },
98
101
  'hostname': 'api.upbit.com',
99
102
  'urls': {
@@ -107,54 +110,70 @@ class upbit(Exchange, ImplicitAPI):
107
110
  'fees': 'https://upbit.com/service_center/guide',
108
111
  },
109
112
  'api': {
113
+ # 'endpoint','API Cost'
114
+ # cost = 1000 / (rateLimit * RPS)
110
115
  'public': {
111
- 'get': [
112
- 'market/all',
113
- 'candles/{timeframe}',
114
- 'candles/{timeframe}/{unit}',
115
- 'candles/minutes/{unit}',
116
- 'candles/minutes/1',
117
- 'candles/minutes/3',
118
- 'candles/minutes/5',
119
- 'candles/minutes/10',
120
- 'candles/minutes/15',
121
- 'candles/minutes/30',
122
- 'candles/minutes/60',
123
- 'candles/minutes/240',
124
- 'candles/days',
125
- 'candles/weeks',
126
- 'candles/months',
127
- 'trades/ticks',
128
- 'ticker',
129
- 'orderbook',
130
- ],
116
+ 'get': {
117
+ 'market/all': 2, # RPS: 10
118
+ 'candles/{timeframe}': 2,
119
+ 'candles/{timeframe}/{unit}': 2,
120
+ 'candles/seconds': 2,
121
+ 'candles/minutes/{unit}': 2,
122
+ 'candles/minutes/1': 2,
123
+ 'candles/minutes/3': 2,
124
+ 'candles/minutes/5': 2,
125
+ 'candles/minutes/10': 2,
126
+ 'candles/minutes/15': 2,
127
+ 'candles/minutes/30': 2,
128
+ 'candles/minutes/60': 2,
129
+ 'candles/minutes/240': 2,
130
+ 'candles/days': 2,
131
+ 'candles/weeks': 2,
132
+ 'candles/months': 2,
133
+ 'candles/years': 2,
134
+ 'trades/ticks': 2,
135
+ 'ticker': 2,
136
+ 'ticker/all': 2,
137
+ 'orderbook': 2,
138
+ 'orderbook/supported_levels': 2, # Upbit KR only
139
+ },
131
140
  },
132
141
  'private': {
133
- 'get': [
134
- 'accounts',
135
- 'orders/chance',
136
- 'order',
137
- 'orders',
138
- 'orders/closed',
139
- 'orders/open',
140
- 'orders/uuids',
141
- 'withdraws',
142
- 'withdraw',
143
- 'withdraws/chance',
144
- 'deposits',
145
- 'deposit',
146
- 'deposits/coin_addresses',
147
- 'deposits/coin_address',
148
- ],
149
- 'post': [
150
- 'orders',
151
- 'withdraws/coin',
152
- 'withdraws/krw',
153
- 'deposits/generate_coin_address',
154
- ],
155
- 'delete': [
156
- 'order',
157
- ],
142
+ 'get': {
143
+ 'accounts': 0.67, # RPS: 30
144
+ 'orders/chance': 0.67,
145
+ 'order': 0.67,
146
+ 'orders/closed': 0.67,
147
+ 'orders/open': 0.67,
148
+ 'orders/uuids': 0.67,
149
+ 'withdraws': 0.67,
150
+ 'withdraw': 0.67,
151
+ 'withdraws/chance': 0.67,
152
+ 'withdraws/coin_addresses': 0.67,
153
+ 'deposits': 0.67,
154
+ 'deposits/chance/coin': 0.67,
155
+ 'deposit': 0.67,
156
+ 'deposits/coin_addresses': 0.67,
157
+ 'deposits/coin_address': 0.67,
158
+ 'travel_rule/vasps': 0.67,
159
+ 'status/wallet': 0.67, # Upbit KR only
160
+ 'api_keys': 0.67, # Upbit KR only
161
+ },
162
+ 'post': {
163
+ 'orders': 2.5, # RPS: 8
164
+ 'orders/cancel_and_new': 2.5, # RPS: 8
165
+ 'withdraws/coin': 0.67,
166
+ 'withdraws/krw': 0.67, # Upbit KR only.
167
+ 'deposits/krw': 0.67, # Upbit KR only.
168
+ 'deposits/generate_coin_address': 0.67,
169
+ 'travel_rule/deposit/uuid': 0.67, # RPS: 30, but each deposit can only be queried once every 10 minutes
170
+ 'travel_rule/deposit/txid': 0.67, # RPS: 30, but each deposit can only be queried once every 10 minutes
171
+ },
172
+ 'delete': {
173
+ 'order': 0.67,
174
+ 'orders/open': 40, # RPS: 0.5
175
+ 'orders/uuids': 0.67,
176
+ },
158
177
  },
159
178
  },
160
179
  'fees': {
@@ -257,8 +276,6 @@ class upbit(Exchange, ImplicitAPI):
257
276
  },
258
277
  'options': {
259
278
  'createMarketBuyOrderRequiresPrice': True,
260
- 'fetchTickersMaxLength': 4096, # 2048,
261
- 'fetchOrderBooksMaxLength': 4096, # 2048,
262
279
  'tradingFeesByQuoteCurrency': {
263
280
  'KRW': 0.0005,
264
281
  },
@@ -606,10 +623,6 @@ class upbit(Exchange, ImplicitAPI):
606
623
  ids = None
607
624
  if symbols is None:
608
625
  ids = ','.join(self.ids)
609
- # max URL length is 2083 symbols, including http schema, hostname, tld, etc...
610
- if len(ids) > self.options['fetchOrderBooksMaxLength']:
611
- numIds = len(self.ids)
612
- raise ExchangeError(self.id + ' fetchOrderBooks() has ' + str(numIds) + ' symbols(' + str(len(ids)) + ' characters) exceeding max URL length(' + str(self.options['fetchOrderBooksMaxLength']) + ' characters), you are required to specify a list of symbols in the first argument to fetchOrderBooks')
613
626
  else:
614
627
  ids = self.market_ids(symbols)
615
628
  ids = ','.join(ids)
@@ -746,10 +759,6 @@ class upbit(Exchange, ImplicitAPI):
746
759
  ids = None
747
760
  if symbols is None:
748
761
  ids = ','.join(self.ids)
749
- # max URL length is 2083 symbols, including http schema, hostname, tld, etc...
750
- if len(ids) > self.options['fetchTickersMaxLength']:
751
- numIds = len(self.ids)
752
- raise ExchangeError(self.id + ' fetchTickers() has ' + str(numIds) + ' symbols exceeding max URL length, you are required to specify a list of symbols in the first argument to fetchTickers')
753
762
  else:
754
763
  ids = self.market_ids(symbols)
755
764
  ids = ','.join(ids)
@@ -983,6 +992,26 @@ class upbit(Exchange, ImplicitAPI):
983
992
  'tierBased': False,
984
993
  }
985
994
 
995
+ async def fetch_trading_fees(self, params={}) -> TradingFees:
996
+ """
997
+ fetch the trading fees for markets
998
+ :param dict [params]: extra parameters specific to the exchange API endpoint
999
+ :returns dict: a `trading fee structure <https://docs.ccxt.com/#/?id=trading-fee-structure>`
1000
+ """
1001
+ await self.load_markets()
1002
+ fetchMarketResponse = await self.fetch_markets(params)
1003
+ response: dict = {}
1004
+ for i in range(0, len(fetchMarketResponse)):
1005
+ element: dict = {}
1006
+ element['maker'] = self.safe_number(fetchMarketResponse[i], 'maker')
1007
+ element['taker'] = self.safe_number(fetchMarketResponse[i], 'taker')
1008
+ element['symbol'] = self.safe_string(fetchMarketResponse[i], 'symbol')
1009
+ element['percentage'] = True
1010
+ element['tierBased'] = False
1011
+ element['info'] = fetchMarketResponse[i]
1012
+ response[self.safe_string(fetchMarketResponse[i], 'symbol')] = element
1013
+ return response
1014
+
986
1015
  def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
987
1016
  #
988
1017
  # {
@@ -1074,6 +1103,25 @@ class upbit(Exchange, ImplicitAPI):
1074
1103
  #
1075
1104
  return self.parse_ohlcvs(response, market, timeframe, since, limit)
1076
1105
 
1106
+ def calc_order_price(self, symbol: str, amount: float, price: Num = None, params={}) -> str:
1107
+ quoteAmount = None
1108
+ createMarketBuyOrderRequiresPrice = self.safe_value(self.options, 'createMarketBuyOrderRequiresPrice')
1109
+ cost = self.safe_string(params, 'cost')
1110
+ if cost is not None:
1111
+ quoteAmount = self.cost_to_precision(symbol, cost)
1112
+ elif createMarketBuyOrderRequiresPrice:
1113
+ if price is None or amount is None:
1114
+ raise InvalidOrder(self.id + ' createOrder() requires the price and amount argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend(quote quantity) in the amount argument')
1115
+ amountString = self.number_to_string(amount)
1116
+ priceString = self.number_to_string(price)
1117
+ costRequest = Precise.string_mul(amountString, priceString)
1118
+ quoteAmount = self.cost_to_precision(symbol, costRequest)
1119
+ else:
1120
+ if amount is None:
1121
+ raise ArgumentsRequired(self.id + ' When createMarketBuyOrderRequiresPrice is False, "amount" is required and should be the total quote amount to spend.')
1122
+ quoteAmount = self.cost_to_precision(symbol, amount)
1123
+ return quoteAmount
1124
+
1077
1125
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1078
1126
  """
1079
1127
  create a trade order
@@ -1082,13 +1130,14 @@ class upbit(Exchange, ImplicitAPI):
1082
1130
  https://global-docs.upbit.com/reference/order
1083
1131
 
1084
1132
  :param str symbol: unified symbol of the market to create an order in
1085
- :param str type: 'market' or 'limit'
1133
+ :param str type: supports 'market' and 'limit'. if params.ordType is set to best, a best-type order will be created regardless of the value of type.
1086
1134
  :param str side: 'buy' or 'sell'
1087
1135
  :param float amount: how much you want to trade in units of the base currency
1088
1136
  :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1089
1137
  :param dict [params]: extra parameters specific to the exchange API endpoint
1090
- :param float [params.cost]: for market buy orders, the quote quantity that can be used alternative for the amount
1091
- :param str [params.timeInForce]: 'IOC' or 'FOK'
1138
+ :param float [params.cost]: for market buy and best buy orders, the quote quantity that can be used alternative for the amount
1139
+ :param str [params.ordType]: self field can be used to place a ‘best’ type order
1140
+ :param str [params.timeInForce]: 'IOC' or 'FOK'. only for limit or best type orders. self field is required when the order type is 'best'.
1092
1141
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1093
1142
  """
1094
1143
  await self.load_markets()
@@ -1099,46 +1148,52 @@ class upbit(Exchange, ImplicitAPI):
1099
1148
  elif side == 'sell':
1100
1149
  orderSide = 'ask'
1101
1150
  else:
1102
- raise InvalidOrder(self.id + ' createOrder() allows buy or sell side only!')
1151
+ raise InvalidOrder(self.id + ' createOrder() supports only buy or sell in the side argument.')
1103
1152
  request: dict = {
1104
1153
  'market': market['id'],
1105
1154
  'side': orderSide,
1106
1155
  }
1107
1156
  if type == 'limit':
1157
+ if price is None or amount is None:
1158
+ raise ArgumentsRequired(self.id + ' the limit type order in createOrder() is required price and amount.')
1159
+ request['ord_type'] = 'limit'
1108
1160
  request['price'] = self.price_to_precision(symbol, price)
1109
- if (type == 'market') and (side == 'buy'):
1110
- # for market buy it requires the amount of quote currency to spend
1111
- quoteAmount = None
1112
- createMarketBuyOrderRequiresPrice = True
1113
- createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
1114
- cost = self.safe_number(params, 'cost')
1115
- params = self.omit(params, 'cost')
1116
- if cost is not None:
1117
- quoteAmount = self.cost_to_precision(symbol, cost)
1118
- elif createMarketBuyOrderRequiresPrice:
1119
- if price is None:
1120
- raise InvalidOrder(self.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend(quote quantity) in the amount argument')
1121
- else:
1122
- amountString = self.number_to_string(amount)
1123
- priceString = self.number_to_string(price)
1124
- costRequest = Precise.string_mul(amountString, priceString)
1125
- quoteAmount = self.cost_to_precision(symbol, costRequest)
1161
+ request['volume'] = self.amount_to_precision(symbol, amount)
1162
+ elif type == 'market':
1163
+ if side == 'buy':
1164
+ request['ord_type'] = 'price'
1165
+ orderPrice = self.calc_order_price(symbol, amount, price, params)
1166
+ request['price'] = orderPrice
1126
1167
  else:
1127
- quoteAmount = self.cost_to_precision(symbol, amount)
1128
- request['ord_type'] = 'price'
1129
- request['price'] = quoteAmount
1168
+ if amount is None:
1169
+ raise ArgumentsRequired(self.id + ' the market sell type order in createOrder() is required amount.')
1170
+ request['ord_type'] = 'market'
1171
+ request['volume'] = self.amount_to_precision(symbol, amount)
1130
1172
  else:
1131
- request['ord_type'] = type
1132
- request['volume'] = self.amount_to_precision(symbol, amount)
1133
- clientOrderId = self.safe_string_2(params, 'clientOrderId', 'identifier')
1173
+ raise InvalidOrder(self.id + ' createOrder() supports only limit or market types in the type argument.')
1174
+ customType = self.safe_string_2(params, 'ordType', 'ord_type')
1175
+ if customType == 'best':
1176
+ params = self.omit(params, ['ordType', 'ord_type'])
1177
+ request['ord_type'] = 'best'
1178
+ if side == 'buy':
1179
+ orderPrice = self.calc_order_price(symbol, amount, price, params)
1180
+ request['price'] = orderPrice
1181
+ else:
1182
+ if amount is None:
1183
+ raise ArgumentsRequired(self.id + ' the best sell type order in createOrder() is required amount.')
1184
+ request['volume'] = self.amount_to_precision(symbol, amount)
1185
+ clientOrderId = self.safe_string(params, 'clientOrderId')
1134
1186
  if clientOrderId is not None:
1135
1187
  request['identifier'] = clientOrderId
1136
- if type != 'market':
1188
+ if request['ord_type'] != 'market' and request['ord_type'] != 'price':
1137
1189
  timeInForce = self.safe_string_lower_2(params, 'timeInForce', 'time_in_force')
1138
- params = self.omit(params, 'timeInForce')
1190
+ params = self.omit(params, ['timeInForce'])
1139
1191
  if timeInForce is not None:
1140
1192
  request['time_in_force'] = timeInForce
1141
- params = self.omit(params, ['clientOrderId', 'identifier'])
1193
+ else:
1194
+ if request['ord_type'] == 'best':
1195
+ raise ArgumentsRequired(self.id + ' the best type order in createOrder() is required timeInForce.')
1196
+ params = self.omit(params, ['clientOrderId', 'cost'])
1142
1197
  response = await self.privatePostOrders(self.extend(request, params))
1143
1198
  #
1144
1199
  # {
@@ -1199,6 +1254,106 @@ class upbit(Exchange, ImplicitAPI):
1199
1254
  #
1200
1255
  return self.parse_order(response)
1201
1256
 
1257
+ async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}) -> Order:
1258
+ """
1259
+
1260
+ https://docs.upbit.com/reference/%EC%B7%A8%EC%86%8C-%ED%9B%84-%EC%9E%AC%EC%A3%BC%EB%AC%B8
1261
+
1262
+ canceled existing order and create new order. It's only generated same side and symbol canceled order. it returns the data of the canceled order, except for `new_order_uuid` and `new_identifier`. to get the details of the new order, use `fetchOrder(new_order_uuid)`.
1263
+ :param str id: the uuid of the previous order you want to edit.
1264
+ :param str symbol: the symbol of the new order. it must be the same symbol of the previous order.
1265
+ :param str type: the type of the new order. only limit or market is accepted. if params.newOrdType is set to best, a best-type order will be created regardless of the value of type.
1266
+ :param str side: the side of the new order. it must be the same side of the previous order.
1267
+ :param number amount: the amount of the asset you want to buy or sell. It could be overridden by specifying the new_volume parameter in params.
1268
+ :param number price: the price of the asset you want to buy or sell. It could be overridden by specifying the new_price parameter in params.
1269
+ :param dict [params]: extra parameters specific to the exchange API endpoint.
1270
+ :param str [params.clientOrderId]: to identify the previous order, either the id or self field is hasattr(self, required) method.
1271
+ :param float [params.cost]: for market buy and best buy orders, the quote quantity that can be used alternative for the amount.
1272
+ :param str [params.newTimeInForce]: 'IOC' or 'FOK'. only for limit or best type orders. self field is required when the order type is 'best'.
1273
+ :param str [params.newClientOrderId]: the order ID that the user can define.
1274
+ :param str [params.newOrdType]: self field only accepts limit, price, market, or best. You can refer to the Upbit developer documentation for details on how to use self field.
1275
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1276
+ """
1277
+ await self.load_markets()
1278
+ request: dict = {}
1279
+ prevClientOrderId = self.safe_string(params, 'clientOrderId')
1280
+ params = self.omit(params, 'clientOrderId')
1281
+ if id is not None:
1282
+ request['prev_order_uuid'] = id
1283
+ elif prevClientOrderId is not None:
1284
+ request['prev_order_identifier'] = prevClientOrderId
1285
+ else:
1286
+ raise ArgumentsRequired(self.id + ' editOrder() is required id or clientOrderId.')
1287
+ if type == 'limit':
1288
+ if price is None or amount is None:
1289
+ raise ArgumentsRequired(self.id + ' editOrder() is required price and amount to create limit type order.')
1290
+ request['new_ord_type'] = 'limit'
1291
+ request['new_price'] = self.price_to_precision(symbol, price)
1292
+ request['new_volume'] = self.amount_to_precision(symbol, amount)
1293
+ elif type == 'market':
1294
+ if side == 'buy':
1295
+ request['new_ord_type'] = 'price'
1296
+ orderPrice = self.calc_order_price(symbol, amount, price, params)
1297
+ request['new_price'] = orderPrice
1298
+ else:
1299
+ if amount is None:
1300
+ raise ArgumentsRequired(self.id + ' editOrder() is required amount to create market sell type order.')
1301
+ request['new_ord_type'] = 'market'
1302
+ request['new_volume'] = self.amount_to_precision(symbol, amount)
1303
+ else:
1304
+ raise InvalidOrder(self.id + ' editOrder() supports only limit or market types in the type argument.')
1305
+ customType = self.safe_string_2(params, 'newOrdType', 'new_ord_type')
1306
+ if customType == 'best':
1307
+ params = self.omit(params, ['newOrdType', 'new_ord_type'])
1308
+ request['new_ord_type'] = 'best'
1309
+ if side == 'buy':
1310
+ orderPrice = self.calc_order_price(symbol, amount, price, params)
1311
+ request['new_price'] = orderPrice
1312
+ else:
1313
+ if amount is None:
1314
+ raise ArgumentsRequired(self.id + ' editOrder() is required amount to create best sell order.')
1315
+ request['new_volume'] = self.amount_to_precision(symbol, amount)
1316
+ clientOrderId = self.safe_string(params, 'newClientOrderId')
1317
+ if clientOrderId is not None:
1318
+ request['new_identifier'] = clientOrderId
1319
+ if request['new_ord_type'] != 'market' and request['new_ord_type'] != 'price':
1320
+ timeInForce = self.safe_string_lower_2(params, 'newTimeInForce', 'new_time_in_force')
1321
+ params = self.omit(params, ['newTimeInForce', 'new_time_in_force'])
1322
+ if timeInForce is not None:
1323
+ request['new_time_in_force'] = timeInForce
1324
+ else:
1325
+ if request['new_ord_type'] == 'best':
1326
+ raise ArgumentsRequired(self.id + ' the best type order is required timeInForce.')
1327
+ params = self.omit(params, ['newClientOrderId', 'cost'])
1328
+ # print('check the each request params: ', request)
1329
+ response = await self.privatePostOrdersCancelAndNew(self.extend(request, params))
1330
+ # {
1331
+ # uuid: '63b38774-27db-4439-ac20-1be16a24d18e', #previous order data
1332
+ # side: 'bid', #previous order data
1333
+ # ord_type: 'limit', #previous order data
1334
+ # price: '100000000', #previous order data
1335
+ # state: 'wait', #previous order data
1336
+ # market: 'KRW-BTC', #previous order data
1337
+ # created_at: '2025-04-01T15:30:47+09:00', #previous order data
1338
+ # volume: '0.00008', #previous order data
1339
+ # remaining_volume: '0.00008', #previous order data
1340
+ # reserved_fee: '4', #previous order data
1341
+ # remaining_fee: '4', #previous order data
1342
+ # paid_fee: '0', #previous order data
1343
+ # locked: '8004', #previous order data
1344
+ # executed_volume: '0', #previous order data
1345
+ # trades_count: '0', #previous order data
1346
+ # identifier: '21', #previous order data
1347
+ # new_order_uuid: 'cb1cce56-6237-4a78-bc11-4cfffc1bb4c2', # new order data
1348
+ # new_order_identifier: '22' # new order data
1349
+ # }
1350
+ result: dict = {}
1351
+ result['uuid'] = self.safe_string(response, 'new_order_uuid')
1352
+ result['identifier'] = self.safe_string(response, 'new_order_identifier')
1353
+ result['side'] = self.safe_string(response, 'side')
1354
+ result['market'] = self.safe_string(response, 'market')
1355
+ return self.parse_order(result)
1356
+
1202
1357
  async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
1203
1358
  """
1204
1359
 
@@ -1512,12 +1667,33 @@ class upbit(Exchange, ImplicitAPI):
1512
1667
  # "time_in_force": "ioc"
1513
1668
  # }
1514
1669
  #
1670
+ # {
1671
+ # uuid: '63b38774-27db-4439-ac20-1be16a24d18e',
1672
+ # side: 'bid',
1673
+ # ord_type: 'limit',
1674
+ # price: '100000000',
1675
+ # state: 'wait',
1676
+ # market: 'KRW-BTC',
1677
+ # created_at: '2025-04-01T15:30:47+09:00',
1678
+ # volume: '0.00008',
1679
+ # remaining_volume: '0.00008',
1680
+ # reserved_fee: '4',
1681
+ # remaining_fee: '4',
1682
+ # paid_fee: '0',
1683
+ # locked: '8004',
1684
+ # executed_volume: '0',
1685
+ # trades_count: '0',
1686
+ # identifier: '21',
1687
+ # new_order_uuid: 'cb1cce56-6237-4a78-bc11-4cfffc1bb4c2',
1688
+ # new_order_identifier: '22'
1689
+ # }
1515
1690
  id = self.safe_string(order, 'uuid')
1516
1691
  side = self.safe_string(order, 'side')
1517
1692
  if side == 'bid':
1518
1693
  side = 'buy'
1519
1694
  else:
1520
1695
  side = 'sell'
1696
+ identifier = self.safe_string(order, 'identifier')
1521
1697
  type = self.safe_string(order, 'ord_type')
1522
1698
  timestamp = self.parse8601(self.safe_string(order, 'created_at'))
1523
1699
  status = self.parse_order_status(self.safe_string(order, 'state'))
@@ -1567,7 +1743,7 @@ class upbit(Exchange, ImplicitAPI):
1567
1743
  return self.safe_order({
1568
1744
  'info': order,
1569
1745
  'id': id,
1570
- 'clientOrderId': None,
1746
+ 'clientOrderId': identifier,
1571
1747
  'timestamp': timestamp,
1572
1748
  'datetime': self.iso8601(timestamp),
1573
1749
  'lastTradeTimestamp': lastTradeTimestamp,
@@ -5,7 +5,7 @@
5
5
 
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.vertex import ImplicitAPI
8
- from ccxt.base.types import Any, Balances, Currencies, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFees, Transaction
8
+ from ccxt.base.types import Any, Balances, Currencies, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFees, Transaction
9
9
  from typing import List
10
10
  from ccxt.base.errors import ExchangeError
11
11
  from ccxt.base.errors import AuthenticationError
@@ -2859,7 +2859,7 @@ class vertex(Exchange, ImplicitAPI):
2859
2859
  'takeProfitPrice': None,
2860
2860
  })
2861
2861
 
2862
- async def fetch_positions(self, symbols: Strings = None, params={}):
2862
+ async def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
2863
2863
  """
2864
2864
  fetch all open positions
2865
2865
 
@@ -587,6 +587,7 @@ class whitebit(Exchange, ImplicitAPI):
587
587
  'deposit': canDeposit,
588
588
  'withdraw': canWithdraw,
589
589
  'fee': None,
590
+ 'networks': None, # todo
590
591
  'precision': None,
591
592
  'limits': {
592
593
  'amount': {
ccxt/async_support/woo.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.woo import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Account, Any, Balances, Bool, Conversion, Currencies, Currency, DepositAddress, Int, LedgerEntry, Leverage, MarginModification, Market, MarketType, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, FundingRate, FundingRates, Trade, TradingFees, Transaction, TransferEntry
9
+ from ccxt.base.types import Account, Any, Balances, Bool, Conversion, Currencies, Currency, DepositAddress, Int, LedgerEntry, Leverage, MarginModification, Market, MarketType, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, FundingRate, FundingRates, Trade, TradingFees, Transaction, TransferEntry
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import AuthenticationError
@@ -574,6 +574,7 @@ class woo(Exchange, ImplicitAPI):
574
574
  contractSize = self.parse_number('1')
575
575
  linear = True
576
576
  inverse = False
577
+ active = self.safe_string(market, 'is_trading') == '1'
577
578
  return {
578
579
  'id': marketId,
579
580
  'symbol': symbol,
@@ -589,7 +590,7 @@ class woo(Exchange, ImplicitAPI):
589
590
  'swap': swap,
590
591
  'future': False,
591
592
  'option': False,
592
- 'active': self.safe_string(market, 'is_trading') == '1',
593
+ 'active': active,
593
594
  'contract': contract,
594
595
  'linear': linear,
595
596
  'inverse': inverse,
@@ -926,6 +927,7 @@ class woo(Exchange, ImplicitAPI):
926
927
  'networks': resultingNetworks,
927
928
  'deposit': None,
928
929
  'withdraw': None,
930
+ 'type': 'crypto',
929
931
  'limits': {
930
932
  'deposit': {
931
933
  'min': None,
@@ -3163,7 +3165,7 @@ class woo(Exchange, ImplicitAPI):
3163
3165
  #
3164
3166
  return self.parse_position(response, market)
3165
3167
 
3166
- async def fetch_positions(self, symbols: Strings = None, params={}):
3168
+ async def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
3167
3169
  await self.load_markets()
3168
3170
  response = await self.v3PrivateGetPositions(params)
3169
3171
  #
@@ -5,7 +5,7 @@
5
5
 
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.woofipro import ImplicitAPI
8
- from ccxt.base.types import Any, Balances, Currencies, Currency, Int, LedgerEntry, Leverage, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, FundingRate, FundingRates, Trade, TradingFees, Transaction
8
+ from ccxt.base.types import Any, Balances, Currencies, Currency, Int, LedgerEntry, Leverage, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, FundingRate, FundingRates, Trade, TradingFees, Transaction
9
9
  from typing import List
10
10
  from ccxt.base.errors import ExchangeError
11
11
  from ccxt.base.errors import AuthenticationError
@@ -2599,7 +2599,7 @@ class woofipro(Exchange, ImplicitAPI):
2599
2599
  data = self.safe_dict(response, 'data')
2600
2600
  return self.parse_position(data, market)
2601
2601
 
2602
- async def fetch_positions(self, symbols: Strings = None, params={}):
2602
+ async def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
2603
2603
  """
2604
2604
  fetch all open positions
2605
2605