ccxt 4.3.8 → 4.3.9

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.
package/js/src/coinex.js CHANGED
@@ -1743,7 +1743,7 @@ export default class coinex extends Exchange {
1743
1743
  // "client_id": "",
1744
1744
  // }
1745
1745
  //
1746
- // Spot and Margin createOrder, createOrders, cancelOrder, cancelOrders, fetchOrder
1746
+ // Spot and Margin cancelOrder, cancelOrders, fetchOrder
1747
1747
  //
1748
1748
  // {
1749
1749
  // "amount":"1.5",
@@ -1771,7 +1771,7 @@ export default class coinex extends Exchange {
1771
1771
  // "client_id": "",
1772
1772
  // }
1773
1773
  //
1774
- // Swap createOrder, cancelOrder, fetchOrder
1774
+ // Swap cancelOrder, fetchOrder
1775
1775
  //
1776
1776
  // {
1777
1777
  // "amount": "0.0005",
@@ -1808,10 +1808,6 @@ export default class coinex extends Exchange {
1808
1808
  // "user_id": 3620173
1809
1809
  // }
1810
1810
  //
1811
- // Stop order createOrder
1812
- //
1813
- // {"status":"success"}
1814
- //
1815
1811
  // Swap Stop cancelOrder, fetchOrder
1816
1812
  //
1817
1813
  // {
@@ -1984,25 +1980,128 @@ export default class coinex extends Exchange {
1984
1980
  // "user_id": 3620173
1985
1981
  // }
1986
1982
  //
1983
+ // Spot and Margin createOrder, createOrders v2
1984
+ //
1985
+ // {
1986
+ // "amount": "0.0001",
1987
+ // "base_fee": "0",
1988
+ // "ccy": "BTC",
1989
+ // "client_id": "x-167673045-a0a3c6461459a801",
1990
+ // "created_at": 1714114386250,
1991
+ // "discount_fee": "0",
1992
+ // "filled_amount": "0",
1993
+ // "filled_value": "0",
1994
+ // "last_fill_amount": "0",
1995
+ // "last_fill_price": "0",
1996
+ // "maker_fee_rate": "0.002",
1997
+ // "market": "BTCUSDT",
1998
+ // "market_type": "SPOT",
1999
+ // "order_id": 117178743547,
2000
+ // "price": "61000",
2001
+ // "quote_fee": "0",
2002
+ // "side": "buy",
2003
+ // "taker_fee_rate": "0.002",
2004
+ // "type": "limit",
2005
+ // "unfilled_amount": "0.0001",
2006
+ // "updated_at": 1714114386250
2007
+ // }
2008
+ //
2009
+ // Spot, Margin and Swap trigger createOrder, createOrders v2
2010
+ //
2011
+ // {
2012
+ // "stop_id": 117180138153
2013
+ // }
2014
+ //
2015
+ // Swap createOrder, createOrders v2
2016
+ //
2017
+ // {
2018
+ // "amount": "0.0001",
2019
+ // "client_id": "x-167673045-1471b81d747080a0",
2020
+ // "created_at": 1714116769986,
2021
+ // "fee": "0",
2022
+ // "fee_ccy": "USDT",
2023
+ // "filled_amount": "0",
2024
+ // "filled_value": "0",
2025
+ // "last_filled_amount": "0",
2026
+ // "last_filled_price": "0",
2027
+ // "maker_fee_rate": "0.0003",
2028
+ // "market": "BTCUSDT",
2029
+ // "market_type": "FUTURES",
2030
+ // "order_id": 136913377780,
2031
+ // "price": "61000.42",
2032
+ // "realized_pnl": "0",
2033
+ // "side": "buy",
2034
+ // "taker_fee_rate": "0.0005",
2035
+ // "type": "limit",
2036
+ // "unfilled_amount": "0.0001",
2037
+ // "updated_at": 1714116769986
2038
+ // }
2039
+ //
2040
+ // Swap stopLossPrice and takeProfitPrice createOrder v2
2041
+ //
2042
+ // {
2043
+ // "adl_level": 1,
2044
+ // "ath_margin_size": "2.14586666",
2045
+ // "ath_position_amount": "0.0001",
2046
+ // "avg_entry_price": "64376",
2047
+ // "bkr_price": "0",
2048
+ // "close_avbl": "0.0001",
2049
+ // "cml_position_value": "6.4376",
2050
+ // "created_at": 1714119054558,
2051
+ // "leverage": "3",
2052
+ // "liq_price": "0",
2053
+ // "maintenance_margin_rate": "0.005",
2054
+ // "maintenance_margin_value": "0.03218632",
2055
+ // "margin_avbl": "2.14586666",
2056
+ // "margin_mode": "cross",
2057
+ // "market": "BTCUSDT",
2058
+ // "market_type": "FUTURES",
2059
+ // "max_position_value": "6.4376",
2060
+ // "open_interest": "0.0001",
2061
+ // "position_id": 303884204,
2062
+ // "position_margin_rate": "3.10624785634397912265",
2063
+ // "realized_pnl": "-0.0032188",
2064
+ // "settle_price": "64376",
2065
+ // "settle_value": "6.4376",
2066
+ // "side": "long",
2067
+ // "stop_loss_price": "62000",
2068
+ // "stop_loss_type": "latest_price",
2069
+ // "take_profit_price": "0",
2070
+ // "take_profit_type": "",
2071
+ // "unrealized_pnl": "0",
2072
+ // "updated_at": 1714119054559
2073
+ // }
2074
+ //
1987
2075
  const rawStatus = this.safeString(order, 'status');
1988
- const timestamp = this.safeTimestamp(order, 'create_time');
2076
+ let timestamp = this.safeTimestamp(order, 'create_time');
2077
+ if (timestamp === undefined) {
2078
+ timestamp = this.safeInteger(order, 'created_at');
2079
+ }
2080
+ let update = this.safeTimestamp(order, 'update_time');
2081
+ if (update === undefined) {
2082
+ update = this.safeInteger(order, 'updated_at');
2083
+ }
1989
2084
  const marketId = this.safeString(order, 'market');
1990
2085
  const defaultType = this.safeString(this.options, 'defaultType');
1991
2086
  const orderType = ('source' in order) ? 'swap' : defaultType;
1992
2087
  market = this.safeMarket(marketId, market, undefined, orderType);
1993
- const feeCurrencyId = this.safeString(order, 'fee_asset');
2088
+ const feeCurrencyId = this.safeString2(order, 'fee_asset', 'fee_ccy');
1994
2089
  let feeCurrency = this.safeCurrencyCode(feeCurrencyId);
1995
2090
  if (feeCurrency === undefined) {
1996
2091
  feeCurrency = market['quote'];
1997
2092
  }
1998
- const rawSide = this.safeInteger(order, 'side');
2093
+ const rawIntegerSide = this.safeInteger(order, 'side');
2094
+ const rawStringSide = this.safeString(order, 'side');
1999
2095
  let side = undefined;
2000
- if (rawSide === 1) {
2096
+ if (rawIntegerSide === 1) {
2001
2097
  side = 'sell';
2002
2098
  }
2003
- else if (rawSide === 2) {
2099
+ else if (rawIntegerSide === 2) {
2004
2100
  side = 'buy';
2005
2101
  }
2102
+ else if ((rawStringSide === 'buy') || (rawStringSide === 'sell')) {
2103
+ side = rawStringSide;
2104
+ }
2006
2105
  else {
2007
2106
  side = this.safeString(order, 'type');
2008
2107
  }
@@ -2010,12 +2109,19 @@ export default class coinex extends Exchange {
2010
2109
  let type = undefined;
2011
2110
  if (rawType === undefined) {
2012
2111
  const typeInteger = this.safeInteger(order, 'type');
2112
+ const typeString = this.safeString(order, 'type');
2013
2113
  if (typeInteger === 1) {
2014
2114
  type = 'limit';
2015
2115
  }
2016
2116
  else if (typeInteger === 2) {
2017
2117
  type = 'market';
2018
2118
  }
2119
+ else if ((typeString === 'limit') || (typeString === 'market')) {
2120
+ type = typeString;
2121
+ }
2122
+ else if (typeString === 'maker_only') {
2123
+ type = 'limit';
2124
+ }
2019
2125
  }
2020
2126
  else {
2021
2127
  type = rawType;
@@ -2025,11 +2131,11 @@ export default class coinex extends Exchange {
2025
2131
  clientOrderId = undefined;
2026
2132
  }
2027
2133
  return this.safeOrder({
2028
- 'id': this.safeString2(order, 'id', 'order_id'),
2134
+ 'id': this.safeStringN(order, ['id', 'order_id', 'stop_id']),
2029
2135
  'clientOrderId': clientOrderId,
2030
2136
  'datetime': this.iso8601(timestamp),
2031
2137
  'timestamp': timestamp,
2032
- 'lastTradeTimestamp': this.safeTimestamp(order, 'update_time'),
2138
+ 'lastTradeTimestamp': update,
2033
2139
  'status': this.parseOrderStatus(rawStatus),
2034
2140
  'symbol': market['symbol'],
2035
2141
  'type': type,
@@ -2042,15 +2148,15 @@ export default class coinex extends Exchange {
2042
2148
  'triggerPrice': this.safeString(order, 'stop_price'),
2043
2149
  'takeProfitPrice': this.safeNumber(order, 'take_profit_price'),
2044
2150
  'stopLossPrice': this.safeNumber(order, 'stop_loss_price'),
2045
- 'cost': this.safeString(order, 'deal_money'),
2046
- 'average': this.safeString(order, 'avg_price'),
2151
+ 'cost': this.safeString2(order, 'deal_money', 'filled_value'),
2152
+ 'average': this.safeString2(order, 'avg_price', 'avg_entry_price'),
2047
2153
  'amount': this.safeString(order, 'amount'),
2048
- 'filled': this.safeString(order, 'deal_amount'),
2049
- 'remaining': this.safeString(order, 'left'),
2154
+ 'filled': this.safeString2(order, 'deal_amount', 'filled_amount'),
2155
+ 'remaining': this.safeString2(order, 'left', 'unfilled_amount'),
2050
2156
  'trades': undefined,
2051
2157
  'fee': {
2052
2158
  'currency': feeCurrency,
2053
- 'cost': this.safeString(order, 'deal_fee'),
2159
+ 'cost': this.safeStringN(order, ['deal_fee', 'quote_fee', 'fee']),
2054
2160
  },
2055
2161
  'info': order,
2056
2162
  }, market);
@@ -2061,6 +2167,7 @@ export default class coinex extends Exchange {
2061
2167
  * @name coinex#createMarketBuyOrderWithCost
2062
2168
  * @description create a market buy order by providing the symbol and cost
2063
2169
  * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade003_market_order
2170
+ * @see https://docs.coinex.com/api/v2/spot/order/http/put-order
2064
2171
  * @param {string} symbol unified symbol of the market to create an order in
2065
2172
  * @param {float} cost how much you want to trade in units of the quote currency
2066
2173
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -2078,22 +2185,18 @@ export default class coinex extends Exchange {
2078
2185
  const market = this.market(symbol);
2079
2186
  const swap = market['swap'];
2080
2187
  const clientOrderId = this.safeString2(params, 'client_id', 'clientOrderId');
2081
- const stopPrice = this.safeValue2(params, 'stopPrice', 'triggerPrice');
2082
- const stopLossPrice = this.safeValue(params, 'stopLossPrice');
2083
- const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
2188
+ const stopPrice = this.safeString2(params, 'stopPrice', 'triggerPrice');
2189
+ const stopLossPrice = this.safeString(params, 'stopLossPrice');
2190
+ const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
2084
2191
  const option = this.safeString(params, 'option');
2085
2192
  const isMarketOrder = type === 'market';
2086
- const postOnly = this.isPostOnly(isMarketOrder, option === 'MAKER_ONLY', params);
2087
- const positionId = this.safeInteger2(params, 'position_id', 'positionId'); // Required for closing swap positions
2088
- const timeInForceRaw = this.safeString(params, 'timeInForce'); // Spot: IOC, FOK, PO, GTC, ... NORMAL (default), MAKER_ONLY
2089
- const reduceOnly = this.safeValue(params, 'reduceOnly');
2193
+ const postOnly = this.isPostOnly(isMarketOrder, option === 'maker_only', params);
2194
+ const timeInForceRaw = this.safeStringUpper(params, 'timeInForce');
2195
+ const reduceOnly = this.safeBool(params, 'reduceOnly');
2090
2196
  if (reduceOnly) {
2091
2197
  if (!market['swap']) {
2092
2198
  throw new InvalidOrder(this.id + ' createOrder() does not support reduceOnly for ' + market['type'] + ' orders, reduceOnly orders are supported for swap markets only');
2093
2199
  }
2094
- if (positionId === undefined) {
2095
- throw new ArgumentsRequired(this.id + ' createOrder() requires a position_id/positionId parameter for reduceOnly orders');
2096
- }
2097
2200
  }
2098
2201
  const request = {
2099
2202
  'market': market['id'],
@@ -2106,73 +2209,56 @@ export default class coinex extends Exchange {
2106
2209
  else {
2107
2210
  request['client_id'] = clientOrderId;
2108
2211
  }
2212
+ if ((stopLossPrice === undefined) && (takeProfitPrice === undefined)) {
2213
+ if (!reduceOnly) {
2214
+ request['side'] = side;
2215
+ }
2216
+ let requestType = type;
2217
+ if (postOnly) {
2218
+ requestType = 'maker_only';
2219
+ }
2220
+ else if (timeInForceRaw !== undefined) {
2221
+ if (timeInForceRaw === 'IOC') {
2222
+ requestType = 'ioc';
2223
+ }
2224
+ else if (timeInForceRaw === 'FOK') {
2225
+ requestType = 'fok';
2226
+ }
2227
+ }
2228
+ if (!isMarketOrder) {
2229
+ request['price'] = this.priceToPrecision(symbol, price);
2230
+ }
2231
+ request['type'] = requestType;
2232
+ }
2109
2233
  if (swap) {
2234
+ request['market_type'] = 'FUTURES';
2110
2235
  if (stopLossPrice || takeProfitPrice) {
2111
- request['stop_type'] = this.safeInteger(params, 'stop_type', 1); // 1: triggered by the latest transaction, 2: mark price, 3: index price
2112
- if (positionId === undefined) {
2113
- throw new ArgumentsRequired(this.id + ' createOrder() requires a position_id parameter for stop loss and take profit orders');
2114
- }
2115
- request['position_id'] = positionId;
2116
2236
  if (stopLossPrice) {
2117
2237
  request['stop_loss_price'] = this.priceToPrecision(symbol, stopLossPrice);
2238
+ request['stop_loss_type'] = this.safeString(params, 'stop_type', 'latest_price');
2118
2239
  }
2119
2240
  else if (takeProfitPrice) {
2120
2241
  request['take_profit_price'] = this.priceToPrecision(symbol, takeProfitPrice);
2242
+ request['take_profit_type'] = this.safeString(params, 'stop_type', 'latest_price');
2121
2243
  }
2122
2244
  }
2123
2245
  else {
2124
- const requestSide = (side === 'buy') ? 2 : 1;
2246
+ request['amount'] = this.amountToPrecision(symbol, amount);
2125
2247
  if (stopPrice !== undefined) {
2126
- request['stop_price'] = this.priceToPrecision(symbol, stopPrice);
2127
- request['stop_type'] = this.safeInteger(params, 'stop_type', 1); // 1: triggered by the latest transaction, 2: mark price, 3: index price;
2128
- request['amount'] = this.amountToPrecision(symbol, amount);
2129
- request['side'] = requestSide;
2130
- if (type === 'limit') {
2131
- request['price'] = this.priceToPrecision(symbol, price);
2132
- }
2133
- request['amount'] = this.amountToPrecision(symbol, amount);
2134
- }
2135
- let timeInForce = undefined;
2136
- if ((type !== 'market') || (stopPrice !== undefined)) {
2137
- if (postOnly) {
2138
- request['option'] = 1;
2139
- }
2140
- else if (timeInForceRaw !== undefined) {
2141
- if (timeInForceRaw === 'IOC') {
2142
- timeInForce = 2;
2143
- }
2144
- else if (timeInForceRaw === 'FOK') {
2145
- timeInForce = 3;
2146
- }
2147
- else {
2148
- timeInForce = 1;
2149
- }
2150
- request['effect_type'] = timeInForce; // exchange takes 'IOC' and 'FOK'
2151
- }
2152
- }
2153
- if (type === 'limit' && stopPrice === undefined) {
2154
- if (reduceOnly) {
2155
- request['position_id'] = positionId;
2156
- }
2157
- else {
2158
- request['side'] = requestSide;
2159
- }
2160
- request['price'] = this.priceToPrecision(symbol, price);
2161
- request['amount'] = this.amountToPrecision(symbol, amount);
2162
- }
2163
- else if (type === 'market' && stopPrice === undefined) {
2164
- if (reduceOnly) {
2165
- request['position_id'] = positionId;
2166
- }
2167
- else {
2168
- request['side'] = requestSide;
2169
- request['amount'] = this.amountToPrecision(symbol, amount);
2170
- }
2248
+ request['trigger_price'] = this.priceToPrecision(symbol, stopPrice);
2249
+ request['trigger_price_type'] = this.safeString(params, 'stop_type', 'latest_price');
2171
2250
  }
2172
2251
  }
2173
2252
  }
2174
2253
  else {
2175
- request['type'] = side;
2254
+ let marginMode = undefined;
2255
+ [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
2256
+ if (marginMode !== undefined) {
2257
+ request['market_type'] = 'MARGIN';
2258
+ }
2259
+ else {
2260
+ request['market_type'] = 'SPOT';
2261
+ }
2176
2262
  if ((type === 'market') && (side === 'buy')) {
2177
2263
  let createMarketBuyOrderRequiresPrice = true;
2178
2264
  [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
@@ -2197,39 +2283,11 @@ export default class coinex extends Exchange {
2197
2283
  else {
2198
2284
  request['amount'] = this.amountToPrecision(symbol, amount);
2199
2285
  }
2200
- if ((type === 'limit') || (type === 'ioc')) {
2201
- request['price'] = this.priceToPrecision(symbol, price);
2202
- }
2203
2286
  if (stopPrice !== undefined) {
2204
- request['stop_price'] = this.priceToPrecision(symbol, stopPrice);
2205
- }
2206
- if ((type !== 'market') || (stopPrice !== undefined)) {
2207
- // following options cannot be applied to vanilla market orders (but can be applied to stop-market orders)
2208
- if ((timeInForceRaw !== undefined) || postOnly) {
2209
- if ((postOnly || (timeInForceRaw !== 'IOC')) && ((type === 'limit') && (stopPrice !== undefined))) {
2210
- throw new InvalidOrder(this.id + ' createOrder() only supports the IOC option for stop-limit orders');
2211
- }
2212
- if (postOnly) {
2213
- request['option'] = 'MAKER_ONLY';
2214
- }
2215
- else {
2216
- if (timeInForceRaw !== undefined) {
2217
- request['option'] = timeInForceRaw; // exchange takes 'IOC' and 'FOK'
2218
- }
2219
- }
2220
- }
2287
+ request['trigger_price'] = this.priceToPrecision(symbol, stopPrice);
2221
2288
  }
2222
2289
  }
2223
- const accountId = this.safeInteger(params, 'account_id');
2224
- let marginMode = undefined;
2225
- [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
2226
- if (marginMode !== undefined) {
2227
- if (accountId === undefined) {
2228
- throw new BadRequest(this.id + ' createOrder() requires an account_id parameter for margin orders');
2229
- }
2230
- request['account_id'] = accountId;
2231
- }
2232
- params = this.omit(params, ['reduceOnly', 'positionId', 'timeInForce', 'postOnly', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice']);
2290
+ params = this.omit(params, ['reduceOnly', 'timeInForce', 'postOnly', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice']);
2233
2291
  return this.extend(request, params);
2234
2292
  }
2235
2293
  async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
@@ -2237,17 +2295,13 @@ export default class coinex extends Exchange {
2237
2295
  * @method
2238
2296
  * @name coinex#createOrder
2239
2297
  * @description create a trade order
2240
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade001_limit_order
2241
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade003_market_order
2242
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade004_IOC_order
2243
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade005_stop_limit_order
2244
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade006_stop_market_order
2245
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http017_put_limit
2246
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http018_put_market
2247
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http019_put_limit_stop
2248
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http020_put_market_stop
2249
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http031_market_close
2250
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http030_limit_close
2298
+ * @see https://docs.coinex.com/api/v2/spot/order/http/put-order
2299
+ * @see https://docs.coinex.com/api/v2/spot/order/http/put-stop-order
2300
+ * @see https://docs.coinex.com/api/v2/futures/order/http/put-order
2301
+ * @see https://docs.coinex.com/api/v2/futures/order/http/put-stop-order
2302
+ * @see https://docs.coinex.com/api/v2/futures/position/http/close-position
2303
+ * @see https://docs.coinex.com/api/v2/futures/position/http/set-position-stop-loss
2304
+ * @see https://docs.coinex.com/api/v2/futures/position/http/set-position-take-profit
2251
2305
  * @param {string} symbol unified symbol of the market to create an order in
2252
2306
  * @param {string} type 'market' or 'limit'
2253
2307
  * @param {string} side 'buy' or 'sell'
@@ -2260,15 +2314,14 @@ export default class coinex extends Exchange {
2260
2314
  * @param {string} [params.timeInForce] 'GTC', 'IOC', 'FOK', 'PO'
2261
2315
  * @param {boolean} [params.postOnly] set to true if you wish to make a post only order
2262
2316
  * @param {boolean} [params.reduceOnly] *contract only* indicates if this order is to reduce the size of a position
2263
- * @param {int} [params.position_id] *required for reduce only orders* the position id to reduce
2264
2317
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2265
2318
  */
2266
2319
  await this.loadMarkets();
2267
2320
  const market = this.market(symbol);
2268
- const reduceOnly = this.safeValue(params, 'reduceOnly');
2269
- const triggerPrice = this.safeNumber2(params, 'stopPrice', 'triggerPrice');
2270
- const stopLossTriggerPrice = this.safeNumber(params, 'stopLossPrice');
2271
- const takeProfitTriggerPrice = this.safeNumber(params, 'takeProfitPrice');
2321
+ const reduceOnly = this.safeBool(params, 'reduceOnly');
2322
+ const triggerPrice = this.safeString2(params, 'stopPrice', 'triggerPrice');
2323
+ const stopLossTriggerPrice = this.safeString(params, 'stopLossPrice');
2324
+ const takeProfitTriggerPrice = this.safeString(params, 'takeProfitPrice');
2272
2325
  const isTriggerOrder = triggerPrice !== undefined;
2273
2326
  const isStopLossTriggerOrder = stopLossTriggerPrice !== undefined;
2274
2327
  const isTakeProfitTriggerOrder = takeProfitTriggerPrice !== undefined;
@@ -2277,135 +2330,212 @@ export default class coinex extends Exchange {
2277
2330
  let response = undefined;
2278
2331
  if (market['spot']) {
2279
2332
  if (isTriggerOrder) {
2280
- if (type === 'limit') {
2281
- response = await this.v1PrivatePostOrderStopLimit(request);
2282
- }
2283
- else {
2284
- response = await this.v1PrivatePostOrderStopMarket(request);
2285
- }
2333
+ response = await this.v2PrivatePostSpotStopOrder(request);
2334
+ //
2335
+ // {
2336
+ // "code": 0,
2337
+ // "data": {
2338
+ // "stop_id": 117180138153
2339
+ // },
2340
+ // "message": "OK"
2341
+ // }
2342
+ //
2286
2343
  }
2287
2344
  else {
2288
- if (type === 'limit') {
2289
- response = await this.v1PrivatePostOrderLimit(request);
2290
- }
2291
- else {
2292
- response = await this.v1PrivatePostOrderMarket(request);
2293
- }
2345
+ response = await this.v2PrivatePostSpotOrder(request);
2346
+ //
2347
+ // {
2348
+ // "code": 0,
2349
+ // "data": {
2350
+ // "amount": "0.0001",
2351
+ // "base_fee": "0",
2352
+ // "ccy": "BTC",
2353
+ // "client_id": "x-167673045-a0a3c6461459a801",
2354
+ // "created_at": 1714114386250,
2355
+ // "discount_fee": "0",
2356
+ // "filled_amount": "0",
2357
+ // "filled_value": "0",
2358
+ // "last_fill_amount": "0",
2359
+ // "last_fill_price": "0",
2360
+ // "maker_fee_rate": "0.002",
2361
+ // "market": "BTCUSDT",
2362
+ // "market_type": "SPOT",
2363
+ // "order_id": 117178743547,
2364
+ // "price": "61000",
2365
+ // "quote_fee": "0",
2366
+ // "side": "buy",
2367
+ // "taker_fee_rate": "0.002",
2368
+ // "type": "limit",
2369
+ // "unfilled_amount": "0.0001",
2370
+ // "updated_at": 1714114386250
2371
+ // },
2372
+ // "message": "OK"
2373
+ // }
2374
+ //
2294
2375
  }
2295
2376
  }
2296
2377
  else {
2297
2378
  if (isTriggerOrder) {
2298
- if (type === 'limit') {
2299
- response = await this.v1PerpetualPrivatePostOrderPutStopLimit(request);
2300
- }
2301
- else {
2302
- response = await this.v1PerpetualPrivatePostOrderPutStopMarket(request);
2303
- }
2379
+ response = await this.v2PrivatePostFuturesStopOrder(request);
2380
+ //
2381
+ // {
2382
+ // "code": 0,
2383
+ // "data": {
2384
+ // "stop_id": 136915460994
2385
+ // },
2386
+ // "message": "OK"
2387
+ // }
2388
+ //
2304
2389
  }
2305
2390
  else if (isStopLossOrTakeProfitTrigger) {
2306
2391
  if (isStopLossTriggerOrder) {
2307
- response = await this.v1PerpetualPrivatePostPositionStopLoss(request);
2392
+ response = await this.v2PrivatePostFuturesSetPositionStopLoss(request);
2393
+ //
2394
+ // {
2395
+ // "code": 0,
2396
+ // "data": {
2397
+ // "adl_level": 1,
2398
+ // "ath_margin_size": "2.14586666",
2399
+ // "ath_position_amount": "0.0001",
2400
+ // "avg_entry_price": "64376",
2401
+ // "bkr_price": "0",
2402
+ // "close_avbl": "0.0001",
2403
+ // "cml_position_value": "6.4376",
2404
+ // "created_at": 1714119054558,
2405
+ // "leverage": "3",
2406
+ // "liq_price": "0",
2407
+ // "maintenance_margin_rate": "0.005",
2408
+ // "maintenance_margin_value": "0.03218632",
2409
+ // "margin_avbl": "2.14586666",
2410
+ // "margin_mode": "cross",
2411
+ // "market": "BTCUSDT",
2412
+ // "market_type": "FUTURES",
2413
+ // "max_position_value": "6.4376",
2414
+ // "open_interest": "0.0001",
2415
+ // "position_id": 303884204,
2416
+ // "position_margin_rate": "3.10624785634397912265",
2417
+ // "realized_pnl": "-0.0032188",
2418
+ // "settle_price": "64376",
2419
+ // "settle_value": "6.4376",
2420
+ // "side": "long",
2421
+ // "stop_loss_price": "62000",
2422
+ // "stop_loss_type": "latest_price",
2423
+ // "take_profit_price": "0",
2424
+ // "take_profit_type": "",
2425
+ // "unrealized_pnl": "0",
2426
+ // "updated_at": 1714119054559
2427
+ // },
2428
+ // "message": "OK"
2429
+ // }
2430
+ //
2308
2431
  }
2309
2432
  else if (isTakeProfitTriggerOrder) {
2310
- response = await this.v1PerpetualPrivatePostPositionTakeProfit(request);
2433
+ response = await this.v2PrivatePostFuturesSetPositionTakeProfit(request);
2434
+ //
2435
+ // {
2436
+ // "code": 0,
2437
+ // "data": {
2438
+ // "adl_level": 1,
2439
+ // "ath_margin_size": "2.14586666",
2440
+ // "ath_position_amount": "0.0001",
2441
+ // "avg_entry_price": "64376",
2442
+ // "bkr_price": "0",
2443
+ // "close_avbl": "0.0001",
2444
+ // "cml_position_value": "6.4376",
2445
+ // "created_at": 1714119054558,
2446
+ // "leverage": "3",
2447
+ // "liq_price": "0",
2448
+ // "maintenance_margin_rate": "0.005",
2449
+ // "maintenance_margin_value": "0.03218632",
2450
+ // "margin_avbl": "2.14586666",
2451
+ // "margin_mode": "cross",
2452
+ // "market": "BTCUSDT",
2453
+ // "market_type": "FUTURES",
2454
+ // "max_position_value": "6.4376",
2455
+ // "open_interest": "0.0001",
2456
+ // "position_id": 303884204,
2457
+ // "position_margin_rate": "3.10624785634397912265",
2458
+ // "realized_pnl": "-0.0032188",
2459
+ // "settle_price": "64376",
2460
+ // "settle_value": "6.4376",
2461
+ // "side": "long",
2462
+ // "stop_loss_price": "62000",
2463
+ // "stop_loss_type": "latest_price",
2464
+ // "take_profit_price": "70000",
2465
+ // "take_profit_type": "latest_price",
2466
+ // "unrealized_pnl": "0",
2467
+ // "updated_at": 1714119054559
2468
+ // },
2469
+ // "message": "OK"
2470
+ // }
2471
+ //
2311
2472
  }
2312
2473
  }
2313
2474
  else {
2314
2475
  if (reduceOnly) {
2315
- if (type === 'limit') {
2316
- response = await this.v1PerpetualPrivatePostOrderCloseLimit(request);
2317
- }
2318
- else {
2319
- response = await this.v1PerpetualPrivatePostOrderCloseMarket(request);
2320
- }
2476
+ response = await this.v2PrivatePostFuturesClosePosition(request);
2477
+ //
2478
+ // {
2479
+ // "code": 0,
2480
+ // "data": {
2481
+ // "amount": "0.0001",
2482
+ // "client_id": "x-167673045-4f264600c432ac06",
2483
+ // "created_at": 1714119323764,
2484
+ // "fee": "0.003221",
2485
+ // "fee_ccy": "USDT",
2486
+ // "filled_amount": "0.0001",
2487
+ // "filled_value": "6.442017",
2488
+ // "last_filled_amount": "0.0001",
2489
+ // "last_filled_price": "64420.17",
2490
+ // "maker_fee_rate": "0",
2491
+ // "market": "BTCUSDT",
2492
+ // "market_type": "FUTURES",
2493
+ // "order_id": 136915813578,
2494
+ // "price": "0",
2495
+ // "realized_pnl": "0.004417",
2496
+ // "side": "sell",
2497
+ // "taker_fee_rate": "0.0005",
2498
+ // "type": "market",
2499
+ // "unfilled_amount": "0",
2500
+ // "updated_at": 1714119323764
2501
+ // },
2502
+ // "message": "OK"
2503
+ // }
2504
+ //
2321
2505
  }
2322
2506
  else {
2323
- if (type === 'limit') {
2324
- response = await this.v1PerpetualPrivatePostOrderPutLimit(request);
2325
- }
2326
- else {
2327
- response = await this.v1PerpetualPrivatePostOrderPutMarket(request);
2328
- }
2507
+ response = await this.v2PrivatePostFuturesOrder(request);
2508
+ //
2509
+ // {
2510
+ // "code": 0,
2511
+ // "data": {
2512
+ // "amount": "0.0001",
2513
+ // "client_id": "x-167673045-1471b81d747080a0",
2514
+ // "created_at": 1714116769986,
2515
+ // "fee": "0",
2516
+ // "fee_ccy": "USDT",
2517
+ // "filled_amount": "0",
2518
+ // "filled_value": "0",
2519
+ // "last_filled_amount": "0",
2520
+ // "last_filled_price": "0",
2521
+ // "maker_fee_rate": "0.0003",
2522
+ // "market": "BTCUSDT",
2523
+ // "market_type": "FUTURES",
2524
+ // "order_id": 136913377780,
2525
+ // "price": "61000.42",
2526
+ // "realized_pnl": "0",
2527
+ // "side": "buy",
2528
+ // "taker_fee_rate": "0.0005",
2529
+ // "type": "limit",
2530
+ // "unfilled_amount": "0.0001",
2531
+ // "updated_at": 1714116769986
2532
+ // },
2533
+ // "message": "OK"
2534
+ // }
2535
+ //
2329
2536
  }
2330
2537
  }
2331
2538
  }
2332
- //
2333
- // Spot and Margin
2334
- //
2335
- // {
2336
- // "code": 0,
2337
- // "data": {
2338
- // "amount": "0.0005",
2339
- // "asset_fee": "0",
2340
- // "avg_price": "0.00",
2341
- // "client_id": "",
2342
- // "create_time": 1650951627,
2343
- // "deal_amount": "0",
2344
- // "deal_fee": "0",
2345
- // "deal_money": "0",
2346
- // "fee_asset": null,
2347
- // "fee_discount": "1",
2348
- // "finished_time": null,
2349
- // "id": 74510932594,
2350
- // "left": "0.0005",
2351
- // "maker_fee_rate": "0.002",
2352
- // "market": "BTCUSDT",
2353
- // "money_fee": "0",
2354
- // "order_type": "limit",
2355
- // "price": "30000",
2356
- // "status": "not_deal",
2357
- // "stock_fee": "0",
2358
- // "taker_fee_rate": "0.002",
2359
- // "type": "buy"
2360
- // },
2361
- // "message": "Success"
2362
- // }
2363
- //
2364
- // Swap
2365
- //
2366
- // {
2367
- // "code": 0,
2368
- // "data": {
2369
- // "amount": "0.0005",
2370
- // "client_id": "",
2371
- // "create_time": 1651004578.618224,
2372
- // "deal_asset_fee": "0.00000000000000000000",
2373
- // "deal_fee": "0.00000000000000000000",
2374
- // "deal_profit": "0.00000000000000000000",
2375
- // "deal_stock": "0.00000000000000000000",
2376
- // "effect_type": 1,
2377
- // "fee_asset": "",
2378
- // "fee_discount": "0.00000000000000000000",
2379
- // "last_deal_amount": "0.00000000000000000000",
2380
- // "last_deal_id": 0,
2381
- // "last_deal_price": "0.00000000000000000000",
2382
- // "last_deal_role": 0,
2383
- // "last_deal_time": 0,
2384
- // "last_deal_type": 0,
2385
- // "left": "0.0005",
2386
- // "leverage": "3",
2387
- // "maker_fee": "0.00030",
2388
- // "market": "BTCUSDT",
2389
- // "order_id": 18221659097,
2390
- // "position_id": 0,
2391
- // "position_type": 1,
2392
- // "price": "30000.00",
2393
- // "side": 2,
2394
- // "source": "api.v1",
2395
- // "stop_id": 0,
2396
- // "taker_fee": "0.00050",
2397
- // "target": 0,
2398
- // "type": 1,
2399
- // "update_time": 1651004578.618224,
2400
- // "user_id": 3620173
2401
- // },
2402
- // "message": "OK"
2403
- // }
2404
- //
2405
- // Stop Order
2406
- //
2407
- // {"code":0,"data":{"status":"success"},"message":"OK"}
2408
- //
2409
2539
  const data = this.safeDict(response, 'data', {});
2410
2540
  return this.parseOrder(data, market);
2411
2541
  }
@@ -2414,7 +2544,10 @@ export default class coinex extends Exchange {
2414
2544
  * @method
2415
2545
  * @name coinex#createOrders
2416
2546
  * @description create a list of trade orders (all orders should be of the same symbol)
2417
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade002_batch_limit_orders
2547
+ * @see https://docs.coinex.com/api/v2/spot/order/http/put-multi-order
2548
+ * @see https://docs.coinex.com/api/v2/spot/order/http/put-multi-stop-order
2549
+ * @see https://docs.coinex.com/api/v2/futures/order/http/put-multi-order
2550
+ * @see https://docs.coinex.com/api/v2/futures/order/http/put-multi-stop-order
2418
2551
  * @param {Array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
2419
2552
  * @param {object} [params] extra parameters specific to the api endpoint
2420
2553
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
@@ -2422,6 +2555,9 @@ export default class coinex extends Exchange {
2422
2555
  await this.loadMarkets();
2423
2556
  const ordersRequests = [];
2424
2557
  let symbol = undefined;
2558
+ let reduceOnly = false;
2559
+ let isTriggerOrder = false;
2560
+ let isStopLossOrTakeProfitTrigger = false;
2425
2561
  for (let i = 0; i < orders.length; i++) {
2426
2562
  const rawOrder = orders[i];
2427
2563
  const marketId = this.safeString(rawOrder, 'symbol');
@@ -2441,56 +2577,148 @@ export default class coinex extends Exchange {
2441
2577
  if (type !== 'limit') {
2442
2578
  throw new NotSupported(this.id + ' createOrders() does not support ' + type + ' orders, only limit orders are accepted');
2443
2579
  }
2580
+ reduceOnly = this.safeValue(orderParams, 'reduceOnly');
2581
+ const triggerPrice = this.safeNumber2(orderParams, 'stopPrice', 'triggerPrice');
2582
+ const stopLossTriggerPrice = this.safeNumber(orderParams, 'stopLossPrice');
2583
+ const takeProfitTriggerPrice = this.safeNumber(orderParams, 'takeProfitPrice');
2584
+ isTriggerOrder = triggerPrice !== undefined;
2585
+ const isStopLossTriggerOrder = stopLossTriggerPrice !== undefined;
2586
+ const isTakeProfitTriggerOrder = takeProfitTriggerPrice !== undefined;
2587
+ isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder || isTakeProfitTriggerOrder;
2444
2588
  const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, orderParams);
2445
2589
  ordersRequests.push(orderRequest);
2446
2590
  }
2447
2591
  const market = this.market(symbol);
2448
- if (!market['spot']) {
2449
- throw new NotSupported(this.id + ' createOrders() does not support ' + market['type'] + ' orders, only spot orders are accepted');
2450
- }
2451
2592
  const request = {
2452
2593
  'market': market['id'],
2453
- 'batch_orders': this.json(ordersRequests),
2594
+ 'orders': ordersRequests,
2454
2595
  };
2455
- const response = await this.v1PrivatePostOrderLimitBatch(request);
2456
- //
2457
- // {
2458
- // "code": 0,
2459
- // "data": [
2460
- // {
2461
- // "code": 0,
2462
- // "data": {
2463
- // "amount": "0.0005",
2464
- // "asset_fee": "0",
2465
- // "avg_price": "0.00",
2466
- // "client_id": "x-167673045-d34bfb41242d8fd1",
2467
- // "create_time": 1701229157,
2468
- // "deal_amount": "0",
2469
- // "deal_fee": "0",
2470
- // "deal_money": "0",
2471
- // "fee_asset": null,
2472
- // "fee_discount": "1",
2473
- // "finished_time": null,
2474
- // "id": 107745856676,
2475
- // "left": "0.0005",
2476
- // "maker_fee_rate": "0.002",
2477
- // "market": "BTCUSDT",
2478
- // "money_fee": "0",
2479
- // "order_type": "limit",
2480
- // "price": "23000",
2481
- // "source_id": "",
2482
- // "status": "not_deal",
2483
- // "stock_fee": "0",
2484
- // "taker_fee_rate": "0.002",
2485
- // "type": "buy"
2486
- // },
2487
- // "message": "OK"
2488
- // },
2489
- // ],
2490
- // "message": "Success"
2491
- // }
2492
- //
2493
- const data = this.safeValue(response, 'data', []);
2596
+ let response = undefined;
2597
+ if (market['spot']) {
2598
+ if (isTriggerOrder) {
2599
+ response = await this.v2PrivatePostSpotBatchStopOrder(request);
2600
+ //
2601
+ // {
2602
+ // "code": 0,
2603
+ // "data": [
2604
+ // {
2605
+ // "code": 0,
2606
+ // "data": {
2607
+ // "stop_id": 117186257510
2608
+ // },
2609
+ // "message": "OK"
2610
+ // },
2611
+ // ],
2612
+ // "message": "OK"
2613
+ // }
2614
+ //
2615
+ }
2616
+ else {
2617
+ response = await this.v2PrivatePostSpotBatchOrder(request);
2618
+ //
2619
+ // {
2620
+ // "code": 0,
2621
+ // "data": [
2622
+ // {
2623
+ // "amount": "0.0001",
2624
+ // "base_fee": "0",
2625
+ // "ccy": "BTC",
2626
+ // "client_id": "x-167673045-f3651372049dab0d",
2627
+ // "created_at": 1714121403450,
2628
+ // "discount_fee": "0",
2629
+ // "filled_amount": "0",
2630
+ // "filled_value": "0",
2631
+ // "last_fill_amount": "0",
2632
+ // "last_fill_price": "0",
2633
+ // "maker_fee_rate": "0.002",
2634
+ // "market": "BTCUSDT",
2635
+ // "market_type": "SPOT",
2636
+ // "order_id": 117185362233,
2637
+ // "price": "61000",
2638
+ // "quote_fee": "0",
2639
+ // "side": "buy",
2640
+ // "taker_fee_rate": "0.002",
2641
+ // "type": "limit",
2642
+ // "unfilled_amount": "0.0001",
2643
+ // "updated_at": 1714121403450
2644
+ // },
2645
+ // {
2646
+ // "code": 3109,
2647
+ // "data": null,
2648
+ // "message": "balance not enough"
2649
+ // }
2650
+ // ],
2651
+ // "message": "OK"
2652
+ // }
2653
+ //
2654
+ }
2655
+ }
2656
+ else {
2657
+ if (isTriggerOrder) {
2658
+ response = await this.v2PrivatePostFuturesBatchStopOrder(request);
2659
+ //
2660
+ // {
2661
+ // "code": 0,
2662
+ // "data": [
2663
+ // {
2664
+ // "code": 0,
2665
+ // "data": {
2666
+ // "stop_id": 136919625994
2667
+ // },
2668
+ // "message": "OK"
2669
+ // },
2670
+ // ],
2671
+ // "message": "OK"
2672
+ // }
2673
+ //
2674
+ }
2675
+ else if (isStopLossOrTakeProfitTrigger) {
2676
+ throw new NotSupported(this.id + ' createOrders() does not support stopLossPrice or takeProfitPrice orders');
2677
+ }
2678
+ else {
2679
+ if (reduceOnly) {
2680
+ throw new NotSupported(this.id + ' createOrders() does not support reduceOnly orders');
2681
+ }
2682
+ else {
2683
+ response = await this.v2PrivatePostFuturesBatchOrder(request);
2684
+ //
2685
+ // {
2686
+ // "code": 0,
2687
+ // "data": [
2688
+ // {
2689
+ // "code": 0,
2690
+ // "data": {
2691
+ // "amount": "0.0001",
2692
+ // "client_id": "x-167673045-2cb7436f3462a654",
2693
+ // "created_at": 1714122832493,
2694
+ // "fee": "0",
2695
+ // "fee_ccy": "USDT",
2696
+ // "filled_amount": "0",
2697
+ // "filled_value": "0",
2698
+ // "last_filled_amount": "0",
2699
+ // "last_filled_price": "0",
2700
+ // "maker_fee_rate": "0.0003",
2701
+ // "market": "BTCUSDT",
2702
+ // "market_type": "FUTURES",
2703
+ // "order_id": 136918835063,
2704
+ // "price": "61000",
2705
+ // "realized_pnl": "0",
2706
+ // "side": "buy",
2707
+ // "taker_fee_rate": "0.0005",
2708
+ // "type": "limit",
2709
+ // "unfilled_amount": "0.0001",
2710
+ // "updated_at": 1714122832493
2711
+ // },
2712
+ // "message": "OK"
2713
+ // },
2714
+ // ],
2715
+ // "message": "OK"
2716
+ // }
2717
+ //
2718
+ }
2719
+ }
2720
+ }
2721
+ const data = this.safeList(response, 'data', []);
2494
2722
  const results = [];
2495
2723
  for (let i = 0; i < data.length; i++) {
2496
2724
  const entry = data[i];
@@ -2504,9 +2732,16 @@ export default class coinex extends Exchange {
2504
2732
  status = 'open';
2505
2733
  }
2506
2734
  }
2507
- const item = this.safeValue(entry, 'data', {});
2508
- item['status'] = status;
2509
- const order = this.parseOrder(item, market);
2735
+ const innerData = this.safeDict(entry, 'data', {});
2736
+ let order = undefined;
2737
+ if (market['spot'] && !isTriggerOrder) {
2738
+ entry['status'] = status;
2739
+ order = this.parseOrder(entry, market);
2740
+ }
2741
+ else {
2742
+ innerData['status'] = status;
2743
+ order = this.parseOrder(innerData, market);
2744
+ }
2510
2745
  results.push(order);
2511
2746
  }
2512
2747
  return results;
@@ -5779,7 +6014,11 @@ export default class coinex extends Exchange {
5779
6014
  query = this.keysort(query);
5780
6015
  const urlencoded = this.rawencode(query);
5781
6016
  let preparedString = method + '/' + version + '/' + path;
5782
- if (urlencoded) {
6017
+ if (method === 'POST') {
6018
+ body = this.json(query);
6019
+ preparedString += body;
6020
+ }
6021
+ else if (urlencoded) {
5783
6022
  preparedString += '?' + urlencoded;
5784
6023
  }
5785
6024
  preparedString += nonce + this.secret;
@@ -5789,14 +6028,11 @@ export default class coinex extends Exchange {
5789
6028
  'X-COINEX-SIGN': signature,
5790
6029
  'X-COINEX-TIMESTAMP': nonce,
5791
6030
  };
5792
- if ((method === 'GET') || (method === 'DELETE') || (method === 'PUT')) {
6031
+ if (method !== 'POST') {
5793
6032
  if (urlencoded) {
5794
6033
  url += '?' + urlencoded;
5795
6034
  }
5796
6035
  }
5797
- else {
5798
- body = this.json(query);
5799
- }
5800
6036
  }
5801
6037
  }
5802
6038
  return { 'url': url, 'method': method, 'body': body, 'headers': headers };