ccxt 4.3.7 → 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.
Files changed (44) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/ccxt.js +1 -1
  3. package/dist/cjs/src/base/Exchange.js +13 -3
  4. package/dist/cjs/src/binance.js +1 -1
  5. package/dist/cjs/src/bingx.js +22 -12
  6. package/dist/cjs/src/bitget.js +1 -1
  7. package/dist/cjs/src/coinex.js +629 -433
  8. package/dist/cjs/src/coinmetro.js +31 -31
  9. package/dist/cjs/src/okx.js +59 -2
  10. package/dist/cjs/src/woo.js +1 -1
  11. package/js/ccxt.d.ts +1 -1
  12. package/js/ccxt.js +1 -1
  13. package/js/src/abstract/bingx.d.ts +1 -1
  14. package/js/src/abstract/coinmetro.d.ts +1 -0
  15. package/js/src/base/Exchange.d.ts +19 -19
  16. package/js/src/base/Exchange.js +13 -3
  17. package/js/src/base/functions/generic.d.ts +20 -19
  18. package/js/src/binance.js +1 -1
  19. package/js/src/bingx.d.ts +2 -2
  20. package/js/src/bingx.js +22 -12
  21. package/js/src/bitget.js +1 -1
  22. package/js/src/bybit.d.ts +1 -1
  23. package/js/src/coinbase.d.ts +1 -1
  24. package/js/src/coinbaseinternational.d.ts +1 -1
  25. package/js/src/coinex.js +629 -433
  26. package/js/src/coinmetro.d.ts +1 -1
  27. package/js/src/coinmetro.js +31 -31
  28. package/js/src/gemini.d.ts +1 -1
  29. package/js/src/hollaex.d.ts +1 -1
  30. package/js/src/htx.d.ts +2 -2
  31. package/js/src/idex.d.ts +1 -1
  32. package/js/src/kucoin.d.ts +1 -1
  33. package/js/src/mexc.d.ts +1 -1
  34. package/js/src/okcoin.d.ts +1 -1
  35. package/js/src/okx.d.ts +5 -1
  36. package/js/src/okx.js +59 -2
  37. package/js/src/paymium.d.ts +1 -1
  38. package/js/src/pro/luno.d.ts +2 -2
  39. package/js/src/probit.d.ts +1 -1
  40. package/js/src/upbit.d.ts +1 -1
  41. package/js/src/whitebit.d.ts +1 -1
  42. package/js/src/woo.js +1 -1
  43. package/js/src/zonda.d.ts +1 -1
  44. package/package.json +7 -7
package/js/src/coinex.js CHANGED
@@ -1532,190 +1532,144 @@ export default class coinex extends Exchange {
1532
1532
  }
1533
1533
  async fetchMarginBalance(params = {}) {
1534
1534
  await this.loadMarkets();
1535
- const symbol = this.safeString(params, 'symbol');
1536
- let marketId = this.safeString(params, 'market');
1537
- let market = undefined;
1538
- if (symbol !== undefined) {
1539
- market = this.market(symbol);
1540
- marketId = market['id'];
1541
- }
1542
- else if (marketId === undefined) {
1543
- throw new ArgumentsRequired(this.id + ' fetchMarginBalance() fetching a margin account requires a market parameter or a symbol parameter');
1544
- }
1545
- params = this.omit(params, ['symbol', 'market']);
1546
- const request = {
1547
- 'market': marketId,
1548
- };
1549
- const response = await this.v1PrivateGetMarginAccount(this.extend(request, params));
1535
+ const response = await this.v2PrivateGetAssetsMarginBalance(params);
1550
1536
  //
1551
- // {
1552
- // "code": 0,
1553
- // "data": {
1554
- // "account_id": 126,
1555
- // "leverage": 3,
1556
- // "market_type": "AAVEUSDT",
1557
- // "sell_asset_type": "AAVE",
1558
- // "buy_asset_type": "USDT",
1559
- // "balance": {
1560
- // "sell_type": "0.3", // borrowed
1561
- // "buy_type": "30"
1562
- // },
1563
- // "frozen": {
1564
- // "sell_type": "0",
1565
- // "buy_type": "0"
1566
- // },
1567
- // "loan": {
1568
- // "sell_type": "0.3", // loan
1569
- // "buy_type": "0"
1570
- // },
1571
- // "interest": {
1572
- // "sell_type": "0.0000125",
1573
- // "buy_type": "0"
1574
- // },
1575
- // "can_transfer": {
1576
- // "sell_type": "0.02500646",
1577
- // "buy_type": "4.28635738"
1578
- // },
1579
- // "warn_rate": "",
1580
- // "liquidation_price": ""
1581
- // },
1582
- // "message": "Success"
1583
- // }
1537
+ // {
1538
+ // "data": [
1539
+ // {
1540
+ // "margin_account": "BTCUSDT",
1541
+ // "base_ccy": "BTC",
1542
+ // "quote_ccy": "USDT",
1543
+ // "available": {
1544
+ // "base_ccy": "0.00000026",
1545
+ // "quote_ccy": "0"
1546
+ // },
1547
+ // "frozen": {
1548
+ // "base_ccy": "0",
1549
+ // "quote_ccy": "0"
1550
+ // },
1551
+ // "repaid": {
1552
+ // "base_ccy": "0",
1553
+ // "quote_ccy": "0"
1554
+ // },
1555
+ // "interest": {
1556
+ // "base_ccy": "0",
1557
+ // "quote_ccy": "0"
1558
+ // },
1559
+ // "rik_rate": "",
1560
+ // "liq_price": ""
1561
+ // },
1562
+ // ],
1563
+ // "code": 0,
1564
+ // "message": "OK"
1565
+ // }
1584
1566
  //
1585
1567
  const result = { 'info': response };
1586
- const data = this.safeValue(response, 'data', {});
1587
- const free = this.safeValue(data, 'can_transfer', {});
1588
- const total = this.safeValue(data, 'balance', {});
1589
- const loan = this.safeValue(data, 'loan', {});
1590
- const interest = this.safeValue(data, 'interest', {});
1591
- //
1592
- const sellAccount = this.account();
1593
- const sellCurrencyId = this.safeString(data, 'sell_asset_type');
1594
- const sellCurrencyCode = this.safeCurrencyCode(sellCurrencyId);
1595
- sellAccount['free'] = this.safeString(free, 'sell_type');
1596
- sellAccount['total'] = this.safeString(total, 'sell_type');
1597
- const sellDebt = this.safeString(loan, 'sell_type');
1598
- const sellInterest = this.safeString(interest, 'sell_type');
1599
- sellAccount['debt'] = Precise.stringAdd(sellDebt, sellInterest);
1600
- result[sellCurrencyCode] = sellAccount;
1601
- //
1602
- const buyAccount = this.account();
1603
- const buyCurrencyId = this.safeString(data, 'buy_asset_type');
1604
- const buyCurrencyCode = this.safeCurrencyCode(buyCurrencyId);
1605
- buyAccount['free'] = this.safeString(free, 'buy_type');
1606
- buyAccount['total'] = this.safeString(total, 'buy_type');
1607
- const buyDebt = this.safeString(loan, 'buy_type');
1608
- const buyInterest = this.safeString(interest, 'buy_type');
1609
- buyAccount['debt'] = Precise.stringAdd(buyDebt, buyInterest);
1610
- result[buyCurrencyCode] = buyAccount;
1611
- //
1568
+ const balances = this.safeList(response, 'data', []);
1569
+ for (let i = 0; i < balances.length; i++) {
1570
+ const entry = balances[i];
1571
+ const free = this.safeDict(entry, 'available', {});
1572
+ const used = this.safeDict(entry, 'frozen', {});
1573
+ const loan = this.safeDict(entry, 'repaid', {});
1574
+ const interest = this.safeDict(entry, 'interest', {});
1575
+ const baseAccount = this.account();
1576
+ const baseCurrencyId = this.safeString(entry, 'base_ccy');
1577
+ const baseCurrencyCode = this.safeCurrencyCode(baseCurrencyId);
1578
+ baseAccount['free'] = this.safeString(free, 'base_ccy');
1579
+ baseAccount['used'] = this.safeString(used, 'base_ccy');
1580
+ const baseDebt = this.safeString(loan, 'base_ccy');
1581
+ const baseInterest = this.safeString(interest, 'base_ccy');
1582
+ baseAccount['debt'] = Precise.stringAdd(baseDebt, baseInterest);
1583
+ result[baseCurrencyCode] = baseAccount;
1584
+ }
1612
1585
  return this.safeBalance(result);
1613
1586
  }
1614
1587
  async fetchSpotBalance(params = {}) {
1615
1588
  await this.loadMarkets();
1616
- const response = await this.v1PrivateGetBalanceInfo(params);
1589
+ const response = await this.v2PrivateGetAssetsSpotBalance(params);
1617
1590
  //
1618
1591
  // {
1619
- // "code": 0,
1620
- // "data": {
1621
- // "BCH": { # BCH account
1622
- // "available": "13.60109", # Available BCH
1623
- // "frozen": "0.00000" # Frozen BCH
1624
- // },
1625
- // "BTC": { # BTC account
1626
- // "available": "32590.16", # Available BTC
1627
- // "frozen": "7000.00" # Frozen BTC
1628
- // },
1629
- // "ETH": { # ETH account
1630
- // "available": "5.06000", # Available ETH
1631
- // "frozen": "0.00000" # Frozen ETH
1632
- // }
1633
- // },
1634
- // "message": "Ok"
1592
+ // "code": 0,
1593
+ // "data": [
1594
+ // {
1595
+ // "available": "0.00000046",
1596
+ // "ccy": "USDT",
1597
+ // "frozen": "0"
1598
+ // }
1599
+ // ],
1600
+ // "message": "OK"
1635
1601
  // }
1636
1602
  //
1637
1603
  const result = { 'info': response };
1638
- const balances = this.safeValue(response, 'data', {});
1639
- const currencyIds = Object.keys(balances);
1640
- for (let i = 0; i < currencyIds.length; i++) {
1641
- const currencyId = currencyIds[i];
1604
+ const balances = this.safeList(response, 'data', []);
1605
+ for (let i = 0; i < balances.length; i++) {
1606
+ const entry = balances[i];
1607
+ const currencyId = this.safeString(entry, 'ccy');
1642
1608
  const code = this.safeCurrencyCode(currencyId);
1643
- const balance = this.safeValue(balances, currencyId, {});
1644
1609
  const account = this.account();
1645
- account['free'] = this.safeString(balance, 'available');
1646
- account['used'] = this.safeString(balance, 'frozen');
1610
+ account['free'] = this.safeString(entry, 'available');
1611
+ account['used'] = this.safeString(entry, 'frozen');
1647
1612
  result[code] = account;
1648
1613
  }
1649
1614
  return this.safeBalance(result);
1650
1615
  }
1651
1616
  async fetchSwapBalance(params = {}) {
1652
1617
  await this.loadMarkets();
1653
- const response = await this.v1PerpetualPrivateGetAssetQuery(params);
1618
+ const response = await this.v2PrivateGetAssetsFuturesBalance(params);
1654
1619
  //
1655
1620
  // {
1656
1621
  // "code": 0,
1657
- // "data": {
1658
- // "USDT": {
1659
- // "available": "37.24817690383456000000",
1660
- // "balance_total": "37.24817690383456000000",
1661
- // "frozen": "0.00000000000000000000",
1662
- // "margin": "0.00000000000000000000",
1663
- // "profit_unreal": "0.00000000000000000000",
1664
- // "transfer": "37.24817690383456000000"
1622
+ // "data": [
1623
+ // {
1624
+ // "available": "0.00000046",
1625
+ // "ccy": "USDT",
1626
+ // "frozen": "0",
1627
+ // "margin": "0",
1628
+ // "transferrable": "0.00000046",
1629
+ // "unrealized_pnl": "0"
1665
1630
  // }
1666
- // },
1631
+ // ],
1667
1632
  // "message": "OK"
1668
1633
  // }
1669
1634
  //
1670
1635
  const result = { 'info': response };
1671
- const balances = this.safeValue(response, 'data', {});
1672
- const currencyIds = Object.keys(balances);
1673
- for (let i = 0; i < currencyIds.length; i++) {
1674
- const currencyId = currencyIds[i];
1636
+ const balances = this.safeList(response, 'data', []);
1637
+ for (let i = 0; i < balances.length; i++) {
1638
+ const entry = balances[i];
1639
+ const currencyId = this.safeString(entry, 'ccy');
1675
1640
  const code = this.safeCurrencyCode(currencyId);
1676
- const balance = this.safeValue(balances, currencyId, {});
1677
1641
  const account = this.account();
1678
- account['free'] = this.safeString(balance, 'available');
1679
- account['used'] = this.safeString(balance, 'frozen');
1680
- account['total'] = this.safeString(balance, 'balance_total');
1642
+ account['free'] = this.safeString(entry, 'available');
1643
+ account['used'] = this.safeString(entry, 'frozen');
1681
1644
  result[code] = account;
1682
1645
  }
1683
1646
  return this.safeBalance(result);
1684
1647
  }
1685
1648
  async fetchFinancialBalance(params = {}) {
1686
1649
  await this.loadMarkets();
1687
- const response = await this.v1PrivateGetAccountInvestmentBalance(params);
1650
+ const response = await this.v2PrivateGetAssetsFinancialBalance(params);
1688
1651
  //
1689
1652
  // {
1690
- // "code": 0,
1691
- // "data": [
1692
- // {
1693
- // "asset": "CET",
1694
- // "available": "0",
1695
- // "frozen": "0",
1696
- // "lock": "0",
1697
- // },
1698
- // {
1699
- // "asset": "USDT",
1700
- // "available": "999900",
1701
- // "frozen": "0",
1702
- // "lock": "0"
1703
- // }
1704
- // ],
1705
- // "message": "Success"
1706
- // }
1653
+ // "code": 0,
1654
+ // "data": [
1655
+ // {
1656
+ // "available": "0.00000046",
1657
+ // "ccy": "USDT",
1658
+ // "frozen": "0"
1659
+ // }
1660
+ // ],
1661
+ // "message": "OK"
1662
+ // }
1707
1663
  //
1708
1664
  const result = { 'info': response };
1709
- const balances = this.safeValue(response, 'data', {});
1665
+ const balances = this.safeList(response, 'data', []);
1710
1666
  for (let i = 0; i < balances.length; i++) {
1711
- const balance = balances[i];
1712
- const currencyId = this.safeString(balance, 'asset');
1667
+ const entry = balances[i];
1668
+ const currencyId = this.safeString(entry, 'ccy');
1713
1669
  const code = this.safeCurrencyCode(currencyId);
1714
1670
  const account = this.account();
1715
- account['free'] = this.safeString(balance, 'available');
1716
- const frozen = this.safeString(balance, 'frozen');
1717
- const locked = this.safeString(balance, 'lock');
1718
- account['used'] = Precise.stringAdd(frozen, locked);
1671
+ account['free'] = this.safeString(entry, 'available');
1672
+ account['used'] = this.safeString(entry, 'frozen');
1719
1673
  result[code] = account;
1720
1674
  }
1721
1675
  return this.safeBalance(result);
@@ -1725,10 +1679,10 @@ export default class coinex extends Exchange {
1725
1679
  * @method
1726
1680
  * @name coinex#fetchBalance
1727
1681
  * @description query for balance and get the amount of funds available for trading or funds locked in orders
1728
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account001_account_info // spot
1729
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account004_investment_balance // financial
1730
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account006_margin_account // margin
1731
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http016_asset_query // swap
1682
+ * @see https://docs.coinex.com/api/v2/assets/balance/http/get-spot-balance // spot
1683
+ * @see https://docs.coinex.com/api/v2/assets/balance/http/get-futures-balance // swap
1684
+ * @see https://docs.coinex.com/api/v2/assets/balance/http/get-marigin-balance // margin
1685
+ * @see https://docs.coinex.com/api/v2/assets/balance/http/get-financial-balance // financial
1732
1686
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1733
1687
  * @param {string} [params.type] 'margin', 'swap', 'financial', or 'spot'
1734
1688
  * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
@@ -1789,7 +1743,7 @@ export default class coinex extends Exchange {
1789
1743
  // "client_id": "",
1790
1744
  // }
1791
1745
  //
1792
- // Spot and Margin createOrder, createOrders, cancelOrder, cancelOrders, fetchOrder
1746
+ // Spot and Margin cancelOrder, cancelOrders, fetchOrder
1793
1747
  //
1794
1748
  // {
1795
1749
  // "amount":"1.5",
@@ -1817,7 +1771,7 @@ export default class coinex extends Exchange {
1817
1771
  // "client_id": "",
1818
1772
  // }
1819
1773
  //
1820
- // Swap createOrder, cancelOrder, fetchOrder
1774
+ // Swap cancelOrder, fetchOrder
1821
1775
  //
1822
1776
  // {
1823
1777
  // "amount": "0.0005",
@@ -1854,10 +1808,6 @@ export default class coinex extends Exchange {
1854
1808
  // "user_id": 3620173
1855
1809
  // }
1856
1810
  //
1857
- // Stop order createOrder
1858
- //
1859
- // {"status":"success"}
1860
- //
1861
1811
  // Swap Stop cancelOrder, fetchOrder
1862
1812
  //
1863
1813
  // {
@@ -2030,25 +1980,128 @@ export default class coinex extends Exchange {
2030
1980
  // "user_id": 3620173
2031
1981
  // }
2032
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
+ //
2033
2075
  const rawStatus = this.safeString(order, 'status');
2034
- 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
+ }
2035
2084
  const marketId = this.safeString(order, 'market');
2036
2085
  const defaultType = this.safeString(this.options, 'defaultType');
2037
2086
  const orderType = ('source' in order) ? 'swap' : defaultType;
2038
2087
  market = this.safeMarket(marketId, market, undefined, orderType);
2039
- const feeCurrencyId = this.safeString(order, 'fee_asset');
2088
+ const feeCurrencyId = this.safeString2(order, 'fee_asset', 'fee_ccy');
2040
2089
  let feeCurrency = this.safeCurrencyCode(feeCurrencyId);
2041
2090
  if (feeCurrency === undefined) {
2042
2091
  feeCurrency = market['quote'];
2043
2092
  }
2044
- const rawSide = this.safeInteger(order, 'side');
2093
+ const rawIntegerSide = this.safeInteger(order, 'side');
2094
+ const rawStringSide = this.safeString(order, 'side');
2045
2095
  let side = undefined;
2046
- if (rawSide === 1) {
2096
+ if (rawIntegerSide === 1) {
2047
2097
  side = 'sell';
2048
2098
  }
2049
- else if (rawSide === 2) {
2099
+ else if (rawIntegerSide === 2) {
2050
2100
  side = 'buy';
2051
2101
  }
2102
+ else if ((rawStringSide === 'buy') || (rawStringSide === 'sell')) {
2103
+ side = rawStringSide;
2104
+ }
2052
2105
  else {
2053
2106
  side = this.safeString(order, 'type');
2054
2107
  }
@@ -2056,12 +2109,19 @@ export default class coinex extends Exchange {
2056
2109
  let type = undefined;
2057
2110
  if (rawType === undefined) {
2058
2111
  const typeInteger = this.safeInteger(order, 'type');
2112
+ const typeString = this.safeString(order, 'type');
2059
2113
  if (typeInteger === 1) {
2060
2114
  type = 'limit';
2061
2115
  }
2062
2116
  else if (typeInteger === 2) {
2063
2117
  type = 'market';
2064
2118
  }
2119
+ else if ((typeString === 'limit') || (typeString === 'market')) {
2120
+ type = typeString;
2121
+ }
2122
+ else if (typeString === 'maker_only') {
2123
+ type = 'limit';
2124
+ }
2065
2125
  }
2066
2126
  else {
2067
2127
  type = rawType;
@@ -2071,11 +2131,11 @@ export default class coinex extends Exchange {
2071
2131
  clientOrderId = undefined;
2072
2132
  }
2073
2133
  return this.safeOrder({
2074
- 'id': this.safeString2(order, 'id', 'order_id'),
2134
+ 'id': this.safeStringN(order, ['id', 'order_id', 'stop_id']),
2075
2135
  'clientOrderId': clientOrderId,
2076
2136
  'datetime': this.iso8601(timestamp),
2077
2137
  'timestamp': timestamp,
2078
- 'lastTradeTimestamp': this.safeTimestamp(order, 'update_time'),
2138
+ 'lastTradeTimestamp': update,
2079
2139
  'status': this.parseOrderStatus(rawStatus),
2080
2140
  'symbol': market['symbol'],
2081
2141
  'type': type,
@@ -2088,15 +2148,15 @@ export default class coinex extends Exchange {
2088
2148
  'triggerPrice': this.safeString(order, 'stop_price'),
2089
2149
  'takeProfitPrice': this.safeNumber(order, 'take_profit_price'),
2090
2150
  'stopLossPrice': this.safeNumber(order, 'stop_loss_price'),
2091
- 'cost': this.safeString(order, 'deal_money'),
2092
- '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'),
2093
2153
  'amount': this.safeString(order, 'amount'),
2094
- 'filled': this.safeString(order, 'deal_amount'),
2095
- 'remaining': this.safeString(order, 'left'),
2154
+ 'filled': this.safeString2(order, 'deal_amount', 'filled_amount'),
2155
+ 'remaining': this.safeString2(order, 'left', 'unfilled_amount'),
2096
2156
  'trades': undefined,
2097
2157
  'fee': {
2098
2158
  'currency': feeCurrency,
2099
- 'cost': this.safeString(order, 'deal_fee'),
2159
+ 'cost': this.safeStringN(order, ['deal_fee', 'quote_fee', 'fee']),
2100
2160
  },
2101
2161
  'info': order,
2102
2162
  }, market);
@@ -2107,6 +2167,7 @@ export default class coinex extends Exchange {
2107
2167
  * @name coinex#createMarketBuyOrderWithCost
2108
2168
  * @description create a market buy order by providing the symbol and cost
2109
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
2110
2171
  * @param {string} symbol unified symbol of the market to create an order in
2111
2172
  * @param {float} cost how much you want to trade in units of the quote currency
2112
2173
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -2124,22 +2185,18 @@ export default class coinex extends Exchange {
2124
2185
  const market = this.market(symbol);
2125
2186
  const swap = market['swap'];
2126
2187
  const clientOrderId = this.safeString2(params, 'client_id', 'clientOrderId');
2127
- const stopPrice = this.safeValue2(params, 'stopPrice', 'triggerPrice');
2128
- const stopLossPrice = this.safeValue(params, 'stopLossPrice');
2129
- 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');
2130
2191
  const option = this.safeString(params, 'option');
2131
2192
  const isMarketOrder = type === 'market';
2132
- const postOnly = this.isPostOnly(isMarketOrder, option === 'MAKER_ONLY', params);
2133
- const positionId = this.safeInteger2(params, 'position_id', 'positionId'); // Required for closing swap positions
2134
- const timeInForceRaw = this.safeString(params, 'timeInForce'); // Spot: IOC, FOK, PO, GTC, ... NORMAL (default), MAKER_ONLY
2135
- 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');
2136
2196
  if (reduceOnly) {
2137
2197
  if (!market['swap']) {
2138
2198
  throw new InvalidOrder(this.id + ' createOrder() does not support reduceOnly for ' + market['type'] + ' orders, reduceOnly orders are supported for swap markets only');
2139
2199
  }
2140
- if (positionId === undefined) {
2141
- throw new ArgumentsRequired(this.id + ' createOrder() requires a position_id/positionId parameter for reduceOnly orders');
2142
- }
2143
2200
  }
2144
2201
  const request = {
2145
2202
  'market': market['id'],
@@ -2152,73 +2209,56 @@ export default class coinex extends Exchange {
2152
2209
  else {
2153
2210
  request['client_id'] = clientOrderId;
2154
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
+ }
2155
2233
  if (swap) {
2234
+ request['market_type'] = 'FUTURES';
2156
2235
  if (stopLossPrice || takeProfitPrice) {
2157
- request['stop_type'] = this.safeInteger(params, 'stop_type', 1); // 1: triggered by the latest transaction, 2: mark price, 3: index price
2158
- if (positionId === undefined) {
2159
- throw new ArgumentsRequired(this.id + ' createOrder() requires a position_id parameter for stop loss and take profit orders');
2160
- }
2161
- request['position_id'] = positionId;
2162
2236
  if (stopLossPrice) {
2163
2237
  request['stop_loss_price'] = this.priceToPrecision(symbol, stopLossPrice);
2238
+ request['stop_loss_type'] = this.safeString(params, 'stop_type', 'latest_price');
2164
2239
  }
2165
2240
  else if (takeProfitPrice) {
2166
2241
  request['take_profit_price'] = this.priceToPrecision(symbol, takeProfitPrice);
2242
+ request['take_profit_type'] = this.safeString(params, 'stop_type', 'latest_price');
2167
2243
  }
2168
2244
  }
2169
2245
  else {
2170
- const requestSide = (side === 'buy') ? 2 : 1;
2246
+ request['amount'] = this.amountToPrecision(symbol, amount);
2171
2247
  if (stopPrice !== undefined) {
2172
- request['stop_price'] = this.priceToPrecision(symbol, stopPrice);
2173
- request['stop_type'] = this.safeInteger(params, 'stop_type', 1); // 1: triggered by the latest transaction, 2: mark price, 3: index price;
2174
- request['amount'] = this.amountToPrecision(symbol, amount);
2175
- request['side'] = requestSide;
2176
- if (type === 'limit') {
2177
- request['price'] = this.priceToPrecision(symbol, price);
2178
- }
2179
- request['amount'] = this.amountToPrecision(symbol, amount);
2180
- }
2181
- let timeInForce = undefined;
2182
- if ((type !== 'market') || (stopPrice !== undefined)) {
2183
- if (postOnly) {
2184
- request['option'] = 1;
2185
- }
2186
- else if (timeInForceRaw !== undefined) {
2187
- if (timeInForceRaw === 'IOC') {
2188
- timeInForce = 2;
2189
- }
2190
- else if (timeInForceRaw === 'FOK') {
2191
- timeInForce = 3;
2192
- }
2193
- else {
2194
- timeInForce = 1;
2195
- }
2196
- request['effect_type'] = timeInForce; // exchange takes 'IOC' and 'FOK'
2197
- }
2198
- }
2199
- if (type === 'limit' && stopPrice === undefined) {
2200
- if (reduceOnly) {
2201
- request['position_id'] = positionId;
2202
- }
2203
- else {
2204
- request['side'] = requestSide;
2205
- }
2206
- request['price'] = this.priceToPrecision(symbol, price);
2207
- request['amount'] = this.amountToPrecision(symbol, amount);
2208
- }
2209
- else if (type === 'market' && stopPrice === undefined) {
2210
- if (reduceOnly) {
2211
- request['position_id'] = positionId;
2212
- }
2213
- else {
2214
- request['side'] = requestSide;
2215
- request['amount'] = this.amountToPrecision(symbol, amount);
2216
- }
2248
+ request['trigger_price'] = this.priceToPrecision(symbol, stopPrice);
2249
+ request['trigger_price_type'] = this.safeString(params, 'stop_type', 'latest_price');
2217
2250
  }
2218
2251
  }
2219
2252
  }
2220
2253
  else {
2221
- 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
+ }
2222
2262
  if ((type === 'market') && (side === 'buy')) {
2223
2263
  let createMarketBuyOrderRequiresPrice = true;
2224
2264
  [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
@@ -2243,39 +2283,11 @@ export default class coinex extends Exchange {
2243
2283
  else {
2244
2284
  request['amount'] = this.amountToPrecision(symbol, amount);
2245
2285
  }
2246
- if ((type === 'limit') || (type === 'ioc')) {
2247
- request['price'] = this.priceToPrecision(symbol, price);
2248
- }
2249
2286
  if (stopPrice !== undefined) {
2250
- request['stop_price'] = this.priceToPrecision(symbol, stopPrice);
2251
- }
2252
- if ((type !== 'market') || (stopPrice !== undefined)) {
2253
- // following options cannot be applied to vanilla market orders (but can be applied to stop-market orders)
2254
- if ((timeInForceRaw !== undefined) || postOnly) {
2255
- if ((postOnly || (timeInForceRaw !== 'IOC')) && ((type === 'limit') && (stopPrice !== undefined))) {
2256
- throw new InvalidOrder(this.id + ' createOrder() only supports the IOC option for stop-limit orders');
2257
- }
2258
- if (postOnly) {
2259
- request['option'] = 'MAKER_ONLY';
2260
- }
2261
- else {
2262
- if (timeInForceRaw !== undefined) {
2263
- request['option'] = timeInForceRaw; // exchange takes 'IOC' and 'FOK'
2264
- }
2265
- }
2266
- }
2267
- }
2268
- }
2269
- const accountId = this.safeInteger(params, 'account_id');
2270
- let marginMode = undefined;
2271
- [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
2272
- if (marginMode !== undefined) {
2273
- if (accountId === undefined) {
2274
- throw new BadRequest(this.id + ' createOrder() requires an account_id parameter for margin orders');
2287
+ request['trigger_price'] = this.priceToPrecision(symbol, stopPrice);
2275
2288
  }
2276
- request['account_id'] = accountId;
2277
2289
  }
2278
- params = this.omit(params, ['reduceOnly', 'positionId', 'timeInForce', 'postOnly', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice']);
2290
+ params = this.omit(params, ['reduceOnly', 'timeInForce', 'postOnly', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice']);
2279
2291
  return this.extend(request, params);
2280
2292
  }
2281
2293
  async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
@@ -2283,17 +2295,13 @@ export default class coinex extends Exchange {
2283
2295
  * @method
2284
2296
  * @name coinex#createOrder
2285
2297
  * @description create a trade order
2286
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade001_limit_order
2287
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade003_market_order
2288
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade004_IOC_order
2289
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade005_stop_limit_order
2290
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade006_stop_market_order
2291
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http017_put_limit
2292
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http018_put_market
2293
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http019_put_limit_stop
2294
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http020_put_market_stop
2295
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http031_market_close
2296
- * @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
2297
2305
  * @param {string} symbol unified symbol of the market to create an order in
2298
2306
  * @param {string} type 'market' or 'limit'
2299
2307
  * @param {string} side 'buy' or 'sell'
@@ -2306,15 +2314,14 @@ export default class coinex extends Exchange {
2306
2314
  * @param {string} [params.timeInForce] 'GTC', 'IOC', 'FOK', 'PO'
2307
2315
  * @param {boolean} [params.postOnly] set to true if you wish to make a post only order
2308
2316
  * @param {boolean} [params.reduceOnly] *contract only* indicates if this order is to reduce the size of a position
2309
- * @param {int} [params.position_id] *required for reduce only orders* the position id to reduce
2310
2317
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2311
2318
  */
2312
2319
  await this.loadMarkets();
2313
2320
  const market = this.market(symbol);
2314
- const reduceOnly = this.safeValue(params, 'reduceOnly');
2315
- const triggerPrice = this.safeNumber2(params, 'stopPrice', 'triggerPrice');
2316
- const stopLossTriggerPrice = this.safeNumber(params, 'stopLossPrice');
2317
- 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');
2318
2325
  const isTriggerOrder = triggerPrice !== undefined;
2319
2326
  const isStopLossTriggerOrder = stopLossTriggerPrice !== undefined;
2320
2327
  const isTakeProfitTriggerOrder = takeProfitTriggerPrice !== undefined;
@@ -2323,135 +2330,212 @@ export default class coinex extends Exchange {
2323
2330
  let response = undefined;
2324
2331
  if (market['spot']) {
2325
2332
  if (isTriggerOrder) {
2326
- if (type === 'limit') {
2327
- response = await this.v1PrivatePostOrderStopLimit(request);
2328
- }
2329
- else {
2330
- response = await this.v1PrivatePostOrderStopMarket(request);
2331
- }
2333
+ response = await this.v2PrivatePostSpotStopOrder(request);
2334
+ //
2335
+ // {
2336
+ // "code": 0,
2337
+ // "data": {
2338
+ // "stop_id": 117180138153
2339
+ // },
2340
+ // "message": "OK"
2341
+ // }
2342
+ //
2332
2343
  }
2333
2344
  else {
2334
- if (type === 'limit') {
2335
- response = await this.v1PrivatePostOrderLimit(request);
2336
- }
2337
- else {
2338
- response = await this.v1PrivatePostOrderMarket(request);
2339
- }
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
+ //
2340
2375
  }
2341
2376
  }
2342
2377
  else {
2343
2378
  if (isTriggerOrder) {
2344
- if (type === 'limit') {
2345
- response = await this.v1PerpetualPrivatePostOrderPutStopLimit(request);
2346
- }
2347
- else {
2348
- response = await this.v1PerpetualPrivatePostOrderPutStopMarket(request);
2349
- }
2379
+ response = await this.v2PrivatePostFuturesStopOrder(request);
2380
+ //
2381
+ // {
2382
+ // "code": 0,
2383
+ // "data": {
2384
+ // "stop_id": 136915460994
2385
+ // },
2386
+ // "message": "OK"
2387
+ // }
2388
+ //
2350
2389
  }
2351
2390
  else if (isStopLossOrTakeProfitTrigger) {
2352
2391
  if (isStopLossTriggerOrder) {
2353
- 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
+ //
2354
2431
  }
2355
2432
  else if (isTakeProfitTriggerOrder) {
2356
- 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
+ //
2357
2472
  }
2358
2473
  }
2359
2474
  else {
2360
2475
  if (reduceOnly) {
2361
- if (type === 'limit') {
2362
- response = await this.v1PerpetualPrivatePostOrderCloseLimit(request);
2363
- }
2364
- else {
2365
- response = await this.v1PerpetualPrivatePostOrderCloseMarket(request);
2366
- }
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
+ //
2367
2505
  }
2368
2506
  else {
2369
- if (type === 'limit') {
2370
- response = await this.v1PerpetualPrivatePostOrderPutLimit(request);
2371
- }
2372
- else {
2373
- response = await this.v1PerpetualPrivatePostOrderPutMarket(request);
2374
- }
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
+ //
2375
2536
  }
2376
2537
  }
2377
2538
  }
2378
- //
2379
- // Spot and Margin
2380
- //
2381
- // {
2382
- // "code": 0,
2383
- // "data": {
2384
- // "amount": "0.0005",
2385
- // "asset_fee": "0",
2386
- // "avg_price": "0.00",
2387
- // "client_id": "",
2388
- // "create_time": 1650951627,
2389
- // "deal_amount": "0",
2390
- // "deal_fee": "0",
2391
- // "deal_money": "0",
2392
- // "fee_asset": null,
2393
- // "fee_discount": "1",
2394
- // "finished_time": null,
2395
- // "id": 74510932594,
2396
- // "left": "0.0005",
2397
- // "maker_fee_rate": "0.002",
2398
- // "market": "BTCUSDT",
2399
- // "money_fee": "0",
2400
- // "order_type": "limit",
2401
- // "price": "30000",
2402
- // "status": "not_deal",
2403
- // "stock_fee": "0",
2404
- // "taker_fee_rate": "0.002",
2405
- // "type": "buy"
2406
- // },
2407
- // "message": "Success"
2408
- // }
2409
- //
2410
- // Swap
2411
- //
2412
- // {
2413
- // "code": 0,
2414
- // "data": {
2415
- // "amount": "0.0005",
2416
- // "client_id": "",
2417
- // "create_time": 1651004578.618224,
2418
- // "deal_asset_fee": "0.00000000000000000000",
2419
- // "deal_fee": "0.00000000000000000000",
2420
- // "deal_profit": "0.00000000000000000000",
2421
- // "deal_stock": "0.00000000000000000000",
2422
- // "effect_type": 1,
2423
- // "fee_asset": "",
2424
- // "fee_discount": "0.00000000000000000000",
2425
- // "last_deal_amount": "0.00000000000000000000",
2426
- // "last_deal_id": 0,
2427
- // "last_deal_price": "0.00000000000000000000",
2428
- // "last_deal_role": 0,
2429
- // "last_deal_time": 0,
2430
- // "last_deal_type": 0,
2431
- // "left": "0.0005",
2432
- // "leverage": "3",
2433
- // "maker_fee": "0.00030",
2434
- // "market": "BTCUSDT",
2435
- // "order_id": 18221659097,
2436
- // "position_id": 0,
2437
- // "position_type": 1,
2438
- // "price": "30000.00",
2439
- // "side": 2,
2440
- // "source": "api.v1",
2441
- // "stop_id": 0,
2442
- // "taker_fee": "0.00050",
2443
- // "target": 0,
2444
- // "type": 1,
2445
- // "update_time": 1651004578.618224,
2446
- // "user_id": 3620173
2447
- // },
2448
- // "message": "OK"
2449
- // }
2450
- //
2451
- // Stop Order
2452
- //
2453
- // {"code":0,"data":{"status":"success"},"message":"OK"}
2454
- //
2455
2539
  const data = this.safeDict(response, 'data', {});
2456
2540
  return this.parseOrder(data, market);
2457
2541
  }
@@ -2460,7 +2544,10 @@ export default class coinex extends Exchange {
2460
2544
  * @method
2461
2545
  * @name coinex#createOrders
2462
2546
  * @description create a list of trade orders (all orders should be of the same symbol)
2463
- * @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
2464
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
2465
2552
  * @param {object} [params] extra parameters specific to the api endpoint
2466
2553
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
@@ -2468,6 +2555,9 @@ export default class coinex extends Exchange {
2468
2555
  await this.loadMarkets();
2469
2556
  const ordersRequests = [];
2470
2557
  let symbol = undefined;
2558
+ let reduceOnly = false;
2559
+ let isTriggerOrder = false;
2560
+ let isStopLossOrTakeProfitTrigger = false;
2471
2561
  for (let i = 0; i < orders.length; i++) {
2472
2562
  const rawOrder = orders[i];
2473
2563
  const marketId = this.safeString(rawOrder, 'symbol');
@@ -2487,56 +2577,148 @@ export default class coinex extends Exchange {
2487
2577
  if (type !== 'limit') {
2488
2578
  throw new NotSupported(this.id + ' createOrders() does not support ' + type + ' orders, only limit orders are accepted');
2489
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;
2490
2588
  const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, orderParams);
2491
2589
  ordersRequests.push(orderRequest);
2492
2590
  }
2493
2591
  const market = this.market(symbol);
2494
- if (!market['spot']) {
2495
- throw new NotSupported(this.id + ' createOrders() does not support ' + market['type'] + ' orders, only spot orders are accepted');
2496
- }
2497
2592
  const request = {
2498
2593
  'market': market['id'],
2499
- 'batch_orders': this.json(ordersRequests),
2594
+ 'orders': ordersRequests,
2500
2595
  };
2501
- const response = await this.v1PrivatePostOrderLimitBatch(request);
2502
- //
2503
- // {
2504
- // "code": 0,
2505
- // "data": [
2506
- // {
2507
- // "code": 0,
2508
- // "data": {
2509
- // "amount": "0.0005",
2510
- // "asset_fee": "0",
2511
- // "avg_price": "0.00",
2512
- // "client_id": "x-167673045-d34bfb41242d8fd1",
2513
- // "create_time": 1701229157,
2514
- // "deal_amount": "0",
2515
- // "deal_fee": "0",
2516
- // "deal_money": "0",
2517
- // "fee_asset": null,
2518
- // "fee_discount": "1",
2519
- // "finished_time": null,
2520
- // "id": 107745856676,
2521
- // "left": "0.0005",
2522
- // "maker_fee_rate": "0.002",
2523
- // "market": "BTCUSDT",
2524
- // "money_fee": "0",
2525
- // "order_type": "limit",
2526
- // "price": "23000",
2527
- // "source_id": "",
2528
- // "status": "not_deal",
2529
- // "stock_fee": "0",
2530
- // "taker_fee_rate": "0.002",
2531
- // "type": "buy"
2532
- // },
2533
- // "message": "OK"
2534
- // },
2535
- // ],
2536
- // "message": "Success"
2537
- // }
2538
- //
2539
- 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', []);
2540
2722
  const results = [];
2541
2723
  for (let i = 0; i < data.length; i++) {
2542
2724
  const entry = data[i];
@@ -2550,9 +2732,16 @@ export default class coinex extends Exchange {
2550
2732
  status = 'open';
2551
2733
  }
2552
2734
  }
2553
- const item = this.safeValue(entry, 'data', {});
2554
- item['status'] = status;
2555
- 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
+ }
2556
2745
  results.push(order);
2557
2746
  }
2558
2747
  return results;
@@ -5824,18 +6013,25 @@ export default class coinex extends Exchange {
5824
6013
  this.checkRequiredCredentials();
5825
6014
  query = this.keysort(query);
5826
6015
  const urlencoded = this.rawencode(query);
5827
- const preparedString = method + '/' + version + '/' + path + '?' + urlencoded + nonce + this.secret;
6016
+ let preparedString = method + '/' + version + '/' + path;
6017
+ if (method === 'POST') {
6018
+ body = this.json(query);
6019
+ preparedString += body;
6020
+ }
6021
+ else if (urlencoded) {
6022
+ preparedString += '?' + urlencoded;
6023
+ }
6024
+ preparedString += nonce + this.secret;
5828
6025
  const signature = this.hash(this.encode(preparedString), sha256);
5829
6026
  headers = {
5830
6027
  'X-COINEX-KEY': this.apiKey,
5831
6028
  'X-COINEX-SIGN': signature,
5832
6029
  'X-COINEX-TIMESTAMP': nonce,
5833
6030
  };
5834
- if ((method === 'GET') || (method === 'DELETE') || (method === 'PUT')) {
5835
- url += '?' + urlencoded;
5836
- }
5837
- else {
5838
- body = this.json(query);
6031
+ if (method !== 'POST') {
6032
+ if (urlencoded) {
6033
+ url += '?' + urlencoded;
6034
+ }
5839
6035
  }
5840
6036
  }
5841
6037
  }