ccxt 4.3.7__py2.py3-none-any.whl → 4.3.9__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ccxt might be problematic. Click here for more details.

ccxt/coinex.py CHANGED
@@ -1487,196 +1487,151 @@ class coinex(Exchange, ImplicitAPI):
1487
1487
 
1488
1488
  def fetch_margin_balance(self, params={}):
1489
1489
  self.load_markets()
1490
- symbol = self.safe_string(params, 'symbol')
1491
- marketId = self.safe_string(params, 'market')
1492
- market: Market = None
1493
- if symbol is not None:
1494
- market = self.market(symbol)
1495
- marketId = market['id']
1496
- elif marketId is None:
1497
- raise ArgumentsRequired(self.id + ' fetchMarginBalance() fetching a margin account requires a market parameter or a symbol parameter')
1498
- params = self.omit(params, ['symbol', 'market'])
1499
- request = {
1500
- 'market': marketId,
1501
- }
1502
- response = self.v1PrivateGetMarginAccount(self.extend(request, params))
1490
+ response = self.v2PrivateGetAssetsMarginBalance(params)
1503
1491
  #
1504
- # {
1505
- # "code": 0,
1506
- # "data": {
1507
- # "account_id": 126,
1508
- # "leverage": 3,
1509
- # "market_type": "AAVEUSDT",
1510
- # "sell_asset_type": "AAVE",
1511
- # "buy_asset_type": "USDT",
1512
- # "balance": {
1513
- # "sell_type": "0.3", # borrowed
1514
- # "buy_type": "30"
1515
- # },
1516
- # "frozen": {
1517
- # "sell_type": "0",
1518
- # "buy_type": "0"
1519
- # },
1520
- # "loan": {
1521
- # "sell_type": "0.3", # loan
1522
- # "buy_type": "0"
1523
- # },
1524
- # "interest": {
1525
- # "sell_type": "0.0000125",
1526
- # "buy_type": "0"
1527
- # },
1528
- # "can_transfer": {
1529
- # "sell_type": "0.02500646",
1530
- # "buy_type": "4.28635738"
1531
- # },
1532
- # "warn_rate": "",
1533
- # "liquidation_price": ""
1534
- # },
1535
- # "message": "Success"
1536
- # }
1492
+ # {
1493
+ # "data": [
1494
+ # {
1495
+ # "margin_account": "BTCUSDT",
1496
+ # "base_ccy": "BTC",
1497
+ # "quote_ccy": "USDT",
1498
+ # "available": {
1499
+ # "base_ccy": "0.00000026",
1500
+ # "quote_ccy": "0"
1501
+ # },
1502
+ # "frozen": {
1503
+ # "base_ccy": "0",
1504
+ # "quote_ccy": "0"
1505
+ # },
1506
+ # "repaid": {
1507
+ # "base_ccy": "0",
1508
+ # "quote_ccy": "0"
1509
+ # },
1510
+ # "interest": {
1511
+ # "base_ccy": "0",
1512
+ # "quote_ccy": "0"
1513
+ # },
1514
+ # "rik_rate": "",
1515
+ # "liq_price": ""
1516
+ # },
1517
+ # ],
1518
+ # "code": 0,
1519
+ # "message": "OK"
1520
+ # }
1537
1521
  #
1538
1522
  result = {'info': response}
1539
- data = self.safe_value(response, 'data', {})
1540
- free = self.safe_value(data, 'can_transfer', {})
1541
- total = self.safe_value(data, 'balance', {})
1542
- loan = self.safe_value(data, 'loan', {})
1543
- interest = self.safe_value(data, 'interest', {})
1544
- #
1545
- sellAccount = self.account()
1546
- sellCurrencyId = self.safe_string(data, 'sell_asset_type')
1547
- sellCurrencyCode = self.safe_currency_code(sellCurrencyId)
1548
- sellAccount['free'] = self.safe_string(free, 'sell_type')
1549
- sellAccount['total'] = self.safe_string(total, 'sell_type')
1550
- sellDebt = self.safe_string(loan, 'sell_type')
1551
- sellInterest = self.safe_string(interest, 'sell_type')
1552
- sellAccount['debt'] = Precise.string_add(sellDebt, sellInterest)
1553
- result[sellCurrencyCode] = sellAccount
1554
- #
1555
- buyAccount = self.account()
1556
- buyCurrencyId = self.safe_string(data, 'buy_asset_type')
1557
- buyCurrencyCode = self.safe_currency_code(buyCurrencyId)
1558
- buyAccount['free'] = self.safe_string(free, 'buy_type')
1559
- buyAccount['total'] = self.safe_string(total, 'buy_type')
1560
- buyDebt = self.safe_string(loan, 'buy_type')
1561
- buyInterest = self.safe_string(interest, 'buy_type')
1562
- buyAccount['debt'] = Precise.string_add(buyDebt, buyInterest)
1563
- result[buyCurrencyCode] = buyAccount
1564
- #
1523
+ balances = self.safe_list(response, 'data', [])
1524
+ for i in range(0, len(balances)):
1525
+ entry = balances[i]
1526
+ free = self.safe_dict(entry, 'available', {})
1527
+ used = self.safe_dict(entry, 'frozen', {})
1528
+ loan = self.safe_dict(entry, 'repaid', {})
1529
+ interest = self.safe_dict(entry, 'interest', {})
1530
+ baseAccount = self.account()
1531
+ baseCurrencyId = self.safe_string(entry, 'base_ccy')
1532
+ baseCurrencyCode = self.safe_currency_code(baseCurrencyId)
1533
+ baseAccount['free'] = self.safe_string(free, 'base_ccy')
1534
+ baseAccount['used'] = self.safe_string(used, 'base_ccy')
1535
+ baseDebt = self.safe_string(loan, 'base_ccy')
1536
+ baseInterest = self.safe_string(interest, 'base_ccy')
1537
+ baseAccount['debt'] = Precise.string_add(baseDebt, baseInterest)
1538
+ result[baseCurrencyCode] = baseAccount
1565
1539
  return self.safe_balance(result)
1566
1540
 
1567
1541
  def fetch_spot_balance(self, params={}):
1568
1542
  self.load_markets()
1569
- response = self.v1PrivateGetBalanceInfo(params)
1543
+ response = self.v2PrivateGetAssetsSpotBalance(params)
1570
1544
  #
1571
1545
  # {
1572
- # "code": 0,
1573
- # "data": {
1574
- # "BCH": { # BCH account
1575
- # "available": "13.60109", # Available BCH
1576
- # "frozen": "0.00000" # Frozen BCH
1577
- # },
1578
- # "BTC": { # BTC account
1579
- # "available": "32590.16", # Available BTC
1580
- # "frozen": "7000.00" # Frozen BTC
1581
- # },
1582
- # "ETH": { # ETH account
1583
- # "available": "5.06000", # Available ETH
1584
- # "frozen": "0.00000" # Frozen ETH
1585
- # }
1586
- # },
1587
- # "message": "Ok"
1546
+ # "code": 0,
1547
+ # "data": [
1548
+ # {
1549
+ # "available": "0.00000046",
1550
+ # "ccy": "USDT",
1551
+ # "frozen": "0"
1552
+ # }
1553
+ # ],
1554
+ # "message": "OK"
1588
1555
  # }
1589
1556
  #
1590
1557
  result = {'info': response}
1591
- balances = self.safe_value(response, 'data', {})
1592
- currencyIds = list(balances.keys())
1593
- for i in range(0, len(currencyIds)):
1594
- currencyId = currencyIds[i]
1558
+ balances = self.safe_list(response, 'data', [])
1559
+ for i in range(0, len(balances)):
1560
+ entry = balances[i]
1561
+ currencyId = self.safe_string(entry, 'ccy')
1595
1562
  code = self.safe_currency_code(currencyId)
1596
- balance = self.safe_value(balances, currencyId, {})
1597
1563
  account = self.account()
1598
- account['free'] = self.safe_string(balance, 'available')
1599
- account['used'] = self.safe_string(balance, 'frozen')
1564
+ account['free'] = self.safe_string(entry, 'available')
1565
+ account['used'] = self.safe_string(entry, 'frozen')
1600
1566
  result[code] = account
1601
1567
  return self.safe_balance(result)
1602
1568
 
1603
1569
  def fetch_swap_balance(self, params={}):
1604
1570
  self.load_markets()
1605
- response = self.v1PerpetualPrivateGetAssetQuery(params)
1571
+ response = self.v2PrivateGetAssetsFuturesBalance(params)
1606
1572
  #
1607
1573
  # {
1608
1574
  # "code": 0,
1609
- # "data": {
1610
- # "USDT": {
1611
- # "available": "37.24817690383456000000",
1612
- # "balance_total": "37.24817690383456000000",
1613
- # "frozen": "0.00000000000000000000",
1614
- # "margin": "0.00000000000000000000",
1615
- # "profit_unreal": "0.00000000000000000000",
1616
- # "transfer": "37.24817690383456000000"
1575
+ # "data": [
1576
+ # {
1577
+ # "available": "0.00000046",
1578
+ # "ccy": "USDT",
1579
+ # "frozen": "0",
1580
+ # "margin": "0",
1581
+ # "transferrable": "0.00000046",
1582
+ # "unrealized_pnl": "0"
1617
1583
  # }
1618
- # },
1584
+ # ],
1619
1585
  # "message": "OK"
1620
1586
  # }
1621
1587
  #
1622
1588
  result = {'info': response}
1623
- balances = self.safe_value(response, 'data', {})
1624
- currencyIds = list(balances.keys())
1625
- for i in range(0, len(currencyIds)):
1626
- currencyId = currencyIds[i]
1589
+ balances = self.safe_list(response, 'data', [])
1590
+ for i in range(0, len(balances)):
1591
+ entry = balances[i]
1592
+ currencyId = self.safe_string(entry, 'ccy')
1627
1593
  code = self.safe_currency_code(currencyId)
1628
- balance = self.safe_value(balances, currencyId, {})
1629
1594
  account = self.account()
1630
- account['free'] = self.safe_string(balance, 'available')
1631
- account['used'] = self.safe_string(balance, 'frozen')
1632
- account['total'] = self.safe_string(balance, 'balance_total')
1595
+ account['free'] = self.safe_string(entry, 'available')
1596
+ account['used'] = self.safe_string(entry, 'frozen')
1633
1597
  result[code] = account
1634
1598
  return self.safe_balance(result)
1635
1599
 
1636
1600
  def fetch_financial_balance(self, params={}):
1637
1601
  self.load_markets()
1638
- response = self.v1PrivateGetAccountInvestmentBalance(params)
1602
+ response = self.v2PrivateGetAssetsFinancialBalance(params)
1639
1603
  #
1640
1604
  # {
1641
- # "code": 0,
1642
- # "data": [
1643
- # {
1644
- # "asset": "CET",
1645
- # "available": "0",
1646
- # "frozen": "0",
1647
- # "lock": "0",
1648
- # },
1649
- # {
1650
- # "asset": "USDT",
1651
- # "available": "999900",
1652
- # "frozen": "0",
1653
- # "lock": "0"
1654
- # }
1655
- # ],
1656
- # "message": "Success"
1657
- # }
1605
+ # "code": 0,
1606
+ # "data": [
1607
+ # {
1608
+ # "available": "0.00000046",
1609
+ # "ccy": "USDT",
1610
+ # "frozen": "0"
1611
+ # }
1612
+ # ],
1613
+ # "message": "OK"
1614
+ # }
1658
1615
  #
1659
1616
  result = {'info': response}
1660
- balances = self.safe_value(response, 'data', {})
1617
+ balances = self.safe_list(response, 'data', [])
1661
1618
  for i in range(0, len(balances)):
1662
- balance = balances[i]
1663
- currencyId = self.safe_string(balance, 'asset')
1619
+ entry = balances[i]
1620
+ currencyId = self.safe_string(entry, 'ccy')
1664
1621
  code = self.safe_currency_code(currencyId)
1665
1622
  account = self.account()
1666
- account['free'] = self.safe_string(balance, 'available')
1667
- frozen = self.safe_string(balance, 'frozen')
1668
- locked = self.safe_string(balance, 'lock')
1669
- account['used'] = Precise.string_add(frozen, locked)
1623
+ account['free'] = self.safe_string(entry, 'available')
1624
+ account['used'] = self.safe_string(entry, 'frozen')
1670
1625
  result[code] = account
1671
1626
  return self.safe_balance(result)
1672
1627
 
1673
1628
  def fetch_balance(self, params={}) -> Balances:
1674
1629
  """
1675
1630
  query for balance and get the amount of funds available for trading or funds locked in orders
1676
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account001_account_info # spot
1677
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account004_investment_balance # financial
1678
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account006_margin_account # margin
1679
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http016_asset_query # swap
1631
+ :see: https://docs.coinex.com/api/v2/assets/balance/http/get-spot-balance # spot
1632
+ :see: https://docs.coinex.com/api/v2/assets/balance/http/get-futures-balance # swap
1633
+ :see: https://docs.coinex.com/api/v2/assets/balance/http/get-marigin-balance # margin
1634
+ :see: https://docs.coinex.com/api/v2/assets/balance/http/get-financial-balance # financial
1680
1635
  :param dict [params]: extra parameters specific to the exchange API endpoint
1681
1636
  :param str [params.type]: 'margin', 'swap', 'financial', or 'spot'
1682
1637
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
@@ -1733,7 +1688,7 @@ class coinex(Exchange, ImplicitAPI):
1733
1688
  # "client_id": "",
1734
1689
  # }
1735
1690
  #
1736
- # Spot and Margin createOrder, createOrders, cancelOrder, cancelOrders, fetchOrder
1691
+ # Spot and Margin cancelOrder, cancelOrders, fetchOrder
1737
1692
  #
1738
1693
  # {
1739
1694
  # "amount":"1.5",
@@ -1761,7 +1716,7 @@ class coinex(Exchange, ImplicitAPI):
1761
1716
  # "client_id": "",
1762
1717
  # }
1763
1718
  #
1764
- # Swap createOrder, cancelOrder, fetchOrder
1719
+ # Swap cancelOrder, fetchOrder
1765
1720
  #
1766
1721
  # {
1767
1722
  # "amount": "0.0005",
@@ -1798,10 +1753,6 @@ class coinex(Exchange, ImplicitAPI):
1798
1753
  # "user_id": 3620173
1799
1754
  # }
1800
1755
  #
1801
- # Stop order createOrder
1802
- #
1803
- # {"status":"success"}
1804
- #
1805
1756
  # Swap Stop cancelOrder, fetchOrder
1806
1757
  #
1807
1758
  # {
@@ -1974,43 +1925,148 @@ class coinex(Exchange, ImplicitAPI):
1974
1925
  # "user_id": 3620173
1975
1926
  # }
1976
1927
  #
1928
+ # Spot and Margin createOrder, createOrders v2
1929
+ #
1930
+ # {
1931
+ # "amount": "0.0001",
1932
+ # "base_fee": "0",
1933
+ # "ccy": "BTC",
1934
+ # "client_id": "x-167673045-a0a3c6461459a801",
1935
+ # "created_at": 1714114386250,
1936
+ # "discount_fee": "0",
1937
+ # "filled_amount": "0",
1938
+ # "filled_value": "0",
1939
+ # "last_fill_amount": "0",
1940
+ # "last_fill_price": "0",
1941
+ # "maker_fee_rate": "0.002",
1942
+ # "market": "BTCUSDT",
1943
+ # "market_type": "SPOT",
1944
+ # "order_id": 117178743547,
1945
+ # "price": "61000",
1946
+ # "quote_fee": "0",
1947
+ # "side": "buy",
1948
+ # "taker_fee_rate": "0.002",
1949
+ # "type": "limit",
1950
+ # "unfilled_amount": "0.0001",
1951
+ # "updated_at": 1714114386250
1952
+ # }
1953
+ #
1954
+ # Spot, Margin and Swap trigger createOrder, createOrders v2
1955
+ #
1956
+ # {
1957
+ # "stop_id": 117180138153
1958
+ # }
1959
+ #
1960
+ # Swap createOrder, createOrders v2
1961
+ #
1962
+ # {
1963
+ # "amount": "0.0001",
1964
+ # "client_id": "x-167673045-1471b81d747080a0",
1965
+ # "created_at": 1714116769986,
1966
+ # "fee": "0",
1967
+ # "fee_ccy": "USDT",
1968
+ # "filled_amount": "0",
1969
+ # "filled_value": "0",
1970
+ # "last_filled_amount": "0",
1971
+ # "last_filled_price": "0",
1972
+ # "maker_fee_rate": "0.0003",
1973
+ # "market": "BTCUSDT",
1974
+ # "market_type": "FUTURES",
1975
+ # "order_id": 136913377780,
1976
+ # "price": "61000.42",
1977
+ # "realized_pnl": "0",
1978
+ # "side": "buy",
1979
+ # "taker_fee_rate": "0.0005",
1980
+ # "type": "limit",
1981
+ # "unfilled_amount": "0.0001",
1982
+ # "updated_at": 1714116769986
1983
+ # }
1984
+ #
1985
+ # Swap stopLossPrice and takeProfitPrice createOrder v2
1986
+ #
1987
+ # {
1988
+ # "adl_level": 1,
1989
+ # "ath_margin_size": "2.14586666",
1990
+ # "ath_position_amount": "0.0001",
1991
+ # "avg_entry_price": "64376",
1992
+ # "bkr_price": "0",
1993
+ # "close_avbl": "0.0001",
1994
+ # "cml_position_value": "6.4376",
1995
+ # "created_at": 1714119054558,
1996
+ # "leverage": "3",
1997
+ # "liq_price": "0",
1998
+ # "maintenance_margin_rate": "0.005",
1999
+ # "maintenance_margin_value": "0.03218632",
2000
+ # "margin_avbl": "2.14586666",
2001
+ # "margin_mode": "cross",
2002
+ # "market": "BTCUSDT",
2003
+ # "market_type": "FUTURES",
2004
+ # "max_position_value": "6.4376",
2005
+ # "open_interest": "0.0001",
2006
+ # "position_id": 303884204,
2007
+ # "position_margin_rate": "3.10624785634397912265",
2008
+ # "realized_pnl": "-0.0032188",
2009
+ # "settle_price": "64376",
2010
+ # "settle_value": "6.4376",
2011
+ # "side": "long",
2012
+ # "stop_loss_price": "62000",
2013
+ # "stop_loss_type": "latest_price",
2014
+ # "take_profit_price": "0",
2015
+ # "take_profit_type": "",
2016
+ # "unrealized_pnl": "0",
2017
+ # "updated_at": 1714119054559
2018
+ # }
2019
+ #
1977
2020
  rawStatus = self.safe_string(order, 'status')
1978
2021
  timestamp = self.safe_timestamp(order, 'create_time')
2022
+ if timestamp is None:
2023
+ timestamp = self.safe_integer(order, 'created_at')
2024
+ update = self.safe_timestamp(order, 'update_time')
2025
+ if update is None:
2026
+ update = self.safe_integer(order, 'updated_at')
1979
2027
  marketId = self.safe_string(order, 'market')
1980
2028
  defaultType = self.safe_string(self.options, 'defaultType')
1981
2029
  orderType = 'swap' if ('source' in order) else defaultType
1982
2030
  market = self.safe_market(marketId, market, None, orderType)
1983
- feeCurrencyId = self.safe_string(order, 'fee_asset')
2031
+ feeCurrencyId = self.safe_string_2(order, 'fee_asset', 'fee_ccy')
1984
2032
  feeCurrency = self.safe_currency_code(feeCurrencyId)
1985
2033
  if feeCurrency is None:
1986
2034
  feeCurrency = market['quote']
1987
- rawSide = self.safe_integer(order, 'side')
2035
+ rawIntegerSide = self.safe_integer(order, 'side')
2036
+ rawStringSide = self.safe_string(order, 'side')
1988
2037
  side: Str = None
1989
- if rawSide == 1:
2038
+ if rawIntegerSide == 1:
1990
2039
  side = 'sell'
1991
- elif rawSide == 2:
2040
+ elif rawIntegerSide == 2:
1992
2041
  side = 'buy'
2042
+ elif (rawStringSide == 'buy') or (rawStringSide == 'sell'):
2043
+ side = rawStringSide
1993
2044
  else:
1994
2045
  side = self.safe_string(order, 'type')
1995
2046
  rawType = self.safe_string(order, 'order_type')
1996
2047
  type: Str = None
1997
2048
  if rawType is None:
1998
2049
  typeInteger = self.safe_integer(order, 'type')
2050
+ typeString = self.safe_string(order, 'type')
1999
2051
  if typeInteger == 1:
2000
2052
  type = 'limit'
2001
2053
  elif typeInteger == 2:
2002
2054
  type = 'market'
2055
+ elif (typeString == 'limit') or (typeString == 'market'):
2056
+ type = typeString
2057
+ elif typeString == 'maker_only':
2058
+ type = 'limit'
2003
2059
  else:
2004
2060
  type = rawType
2005
2061
  clientOrderId = self.safe_string(order, 'client_id')
2006
2062
  if clientOrderId == '':
2007
2063
  clientOrderId = None
2008
2064
  return self.safe_order({
2009
- 'id': self.safe_string_2(order, 'id', 'order_id'),
2065
+ 'id': self.safe_string_n(order, ['id', 'order_id', 'stop_id']),
2010
2066
  'clientOrderId': clientOrderId,
2011
2067
  'datetime': self.iso8601(timestamp),
2012
2068
  'timestamp': timestamp,
2013
- 'lastTradeTimestamp': self.safe_timestamp(order, 'update_time'),
2069
+ 'lastTradeTimestamp': update,
2014
2070
  'status': self.parse_order_status(rawStatus),
2015
2071
  'symbol': market['symbol'],
2016
2072
  'type': type,
@@ -2023,15 +2079,15 @@ class coinex(Exchange, ImplicitAPI):
2023
2079
  'triggerPrice': self.safe_string(order, 'stop_price'),
2024
2080
  'takeProfitPrice': self.safe_number(order, 'take_profit_price'),
2025
2081
  'stopLossPrice': self.safe_number(order, 'stop_loss_price'),
2026
- 'cost': self.safe_string(order, 'deal_money'),
2027
- 'average': self.safe_string(order, 'avg_price'),
2082
+ 'cost': self.safe_string_2(order, 'deal_money', 'filled_value'),
2083
+ 'average': self.safe_string_2(order, 'avg_price', 'avg_entry_price'),
2028
2084
  'amount': self.safe_string(order, 'amount'),
2029
- 'filled': self.safe_string(order, 'deal_amount'),
2030
- 'remaining': self.safe_string(order, 'left'),
2085
+ 'filled': self.safe_string_2(order, 'deal_amount', 'filled_amount'),
2086
+ 'remaining': self.safe_string_2(order, 'left', 'unfilled_amount'),
2031
2087
  'trades': None,
2032
2088
  'fee': {
2033
2089
  'currency': feeCurrency,
2034
- 'cost': self.safe_string(order, 'deal_fee'),
2090
+ 'cost': self.safe_string_n(order, ['deal_fee', 'quote_fee', 'fee']),
2035
2091
  },
2036
2092
  'info': order,
2037
2093
  }, market)
@@ -2040,6 +2096,7 @@ class coinex(Exchange, ImplicitAPI):
2040
2096
  """
2041
2097
  create a market buy order by providing the symbol and cost
2042
2098
  :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade003_market_order
2099
+ :see: https://docs.coinex.com/api/v2/spot/order/http/put-order
2043
2100
  :param str symbol: unified symbol of the market to create an order in
2044
2101
  :param float cost: how much you want to trade in units of the quote currency
2045
2102
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -2056,20 +2113,17 @@ class coinex(Exchange, ImplicitAPI):
2056
2113
  market = self.market(symbol)
2057
2114
  swap = market['swap']
2058
2115
  clientOrderId = self.safe_string_2(params, 'client_id', 'clientOrderId')
2059
- stopPrice = self.safe_value_2(params, 'stopPrice', 'triggerPrice')
2060
- stopLossPrice = self.safe_value(params, 'stopLossPrice')
2061
- takeProfitPrice = self.safe_value(params, 'takeProfitPrice')
2116
+ stopPrice = self.safe_string_2(params, 'stopPrice', 'triggerPrice')
2117
+ stopLossPrice = self.safe_string(params, 'stopLossPrice')
2118
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
2062
2119
  option = self.safe_string(params, 'option')
2063
2120
  isMarketOrder = type == 'market'
2064
- postOnly = self.is_post_only(isMarketOrder, option == 'MAKER_ONLY', params)
2065
- positionId = self.safe_integer_2(params, 'position_id', 'positionId') # Required for closing swap positions
2066
- timeInForceRaw = self.safe_string(params, 'timeInForce') # Spot: IOC, FOK, PO, GTC, ... NORMAL(default), MAKER_ONLY
2067
- reduceOnly = self.safe_value(params, 'reduceOnly')
2121
+ postOnly = self.is_post_only(isMarketOrder, option == 'maker_only', params)
2122
+ timeInForceRaw = self.safe_string_upper(params, 'timeInForce')
2123
+ reduceOnly = self.safe_bool(params, 'reduceOnly')
2068
2124
  if reduceOnly:
2069
2125
  if not market['swap']:
2070
2126
  raise InvalidOrder(self.id + ' createOrder() does not support reduceOnly for ' + market['type'] + ' orders, reduceOnly orders are supported for swap markets only')
2071
- if positionId is None:
2072
- raise ArgumentsRequired(self.id + ' createOrder() requires a position_id/positionId parameter for reduceOnly orders')
2073
2127
  request = {
2074
2128
  'market': market['id'],
2075
2129
  }
@@ -2079,53 +2133,41 @@ class coinex(Exchange, ImplicitAPI):
2079
2133
  request['client_id'] = brokerId + '-' + self.uuid16()
2080
2134
  else:
2081
2135
  request['client_id'] = clientOrderId
2136
+ if (stopLossPrice is None) and (takeProfitPrice is None):
2137
+ if not reduceOnly:
2138
+ request['side'] = side
2139
+ requestType = type
2140
+ if postOnly:
2141
+ requestType = 'maker_only'
2142
+ elif timeInForceRaw is not None:
2143
+ if timeInForceRaw == 'IOC':
2144
+ requestType = 'ioc'
2145
+ elif timeInForceRaw == 'FOK':
2146
+ requestType = 'fok'
2147
+ if not isMarketOrder:
2148
+ request['price'] = self.price_to_precision(symbol, price)
2149
+ request['type'] = requestType
2082
2150
  if swap:
2151
+ request['market_type'] = 'FUTURES'
2083
2152
  if stopLossPrice or takeProfitPrice:
2084
- request['stop_type'] = self.safe_integer(params, 'stop_type', 1) # 1: triggered by the latest transaction, 2: mark price, 3: index price
2085
- if positionId is None:
2086
- raise ArgumentsRequired(self.id + ' createOrder() requires a position_id parameter for stop loss and take profit orders')
2087
- request['position_id'] = positionId
2088
2153
  if stopLossPrice:
2089
2154
  request['stop_loss_price'] = self.price_to_precision(symbol, stopLossPrice)
2155
+ request['stop_loss_type'] = self.safe_string(params, 'stop_type', 'latest_price')
2090
2156
  elif takeProfitPrice:
2091
2157
  request['take_profit_price'] = self.price_to_precision(symbol, takeProfitPrice)
2158
+ request['take_profit_type'] = self.safe_string(params, 'stop_type', 'latest_price')
2092
2159
  else:
2093
- requestSide = 2 if (side == 'buy') else 1
2160
+ request['amount'] = self.amount_to_precision(symbol, amount)
2094
2161
  if stopPrice is not None:
2095
- request['stop_price'] = self.price_to_precision(symbol, stopPrice)
2096
- request['stop_type'] = self.safe_integer(params, 'stop_type', 1) # 1: triggered by the latest transaction, 2: mark price, 3: index price
2097
- request['amount'] = self.amount_to_precision(symbol, amount)
2098
- request['side'] = requestSide
2099
- if type == 'limit':
2100
- request['price'] = self.price_to_precision(symbol, price)
2101
- request['amount'] = self.amount_to_precision(symbol, amount)
2102
- timeInForce = None
2103
- if (type != 'market') or (stopPrice is not None):
2104
- if postOnly:
2105
- request['option'] = 1
2106
- elif timeInForceRaw is not None:
2107
- if timeInForceRaw == 'IOC':
2108
- timeInForce = 2
2109
- elif timeInForceRaw == 'FOK':
2110
- timeInForce = 3
2111
- else:
2112
- timeInForce = 1
2113
- request['effect_type'] = timeInForce # exchange takes 'IOC' and 'FOK'
2114
- if type == 'limit' and stopPrice is None:
2115
- if reduceOnly:
2116
- request['position_id'] = positionId
2117
- else:
2118
- request['side'] = requestSide
2119
- request['price'] = self.price_to_precision(symbol, price)
2120
- request['amount'] = self.amount_to_precision(symbol, amount)
2121
- elif type == 'market' and stopPrice is None:
2122
- if reduceOnly:
2123
- request['position_id'] = positionId
2124
- else:
2125
- request['side'] = requestSide
2126
- request['amount'] = self.amount_to_precision(symbol, amount)
2162
+ request['trigger_price'] = self.price_to_precision(symbol, stopPrice)
2163
+ request['trigger_price_type'] = self.safe_string(params, 'stop_type', 'latest_price')
2127
2164
  else:
2128
- request['type'] = side
2165
+ marginMode = None
2166
+ marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
2167
+ if marginMode is not None:
2168
+ request['market_type'] = 'MARGIN'
2169
+ else:
2170
+ request['market_type'] = 'SPOT'
2129
2171
  if (type == 'market') and (side == 'buy'):
2130
2172
  createMarketBuyOrderRequiresPrice = True
2131
2173
  createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
@@ -2144,44 +2186,21 @@ class coinex(Exchange, ImplicitAPI):
2144
2186
  request['amount'] = self.cost_to_precision(symbol, amount)
2145
2187
  else:
2146
2188
  request['amount'] = self.amount_to_precision(symbol, amount)
2147
- if (type == 'limit') or (type == 'ioc'):
2148
- request['price'] = self.price_to_precision(symbol, price)
2149
2189
  if stopPrice is not None:
2150
- request['stop_price'] = self.price_to_precision(symbol, stopPrice)
2151
- if (type != 'market') or (stopPrice is not None):
2152
- # following options cannot be applied to vanilla market orders(but can be applied to stop-market orders)
2153
- if (timeInForceRaw is not None) or postOnly:
2154
- if (postOnly or (timeInForceRaw != 'IOC')) and ((type == 'limit') and (stopPrice is not None)):
2155
- raise InvalidOrder(self.id + ' createOrder() only supports the IOC option for stop-limit orders')
2156
- if postOnly:
2157
- request['option'] = 'MAKER_ONLY'
2158
- else:
2159
- if timeInForceRaw is not None:
2160
- request['option'] = timeInForceRaw # exchange takes 'IOC' and 'FOK'
2161
- accountId = self.safe_integer(params, 'account_id')
2162
- marginMode = None
2163
- marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
2164
- if marginMode is not None:
2165
- if accountId is None:
2166
- raise BadRequest(self.id + ' createOrder() requires an account_id parameter for margin orders')
2167
- request['account_id'] = accountId
2168
- params = self.omit(params, ['reduceOnly', 'positionId', 'timeInForce', 'postOnly', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice'])
2190
+ request['trigger_price'] = self.price_to_precision(symbol, stopPrice)
2191
+ params = self.omit(params, ['reduceOnly', 'timeInForce', 'postOnly', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice'])
2169
2192
  return self.extend(request, params)
2170
2193
 
2171
2194
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2172
2195
  """
2173
2196
  create a trade order
2174
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade001_limit_order
2175
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade003_market_order
2176
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade004_IOC_order
2177
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade005_stop_limit_order
2178
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade006_stop_market_order
2179
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http017_put_limit
2180
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http018_put_market
2181
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http019_put_limit_stop
2182
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http020_put_market_stop
2183
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http031_market_close
2184
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http030_limit_close
2197
+ :see: https://docs.coinex.com/api/v2/spot/order/http/put-order
2198
+ :see: https://docs.coinex.com/api/v2/spot/order/http/put-stop-order
2199
+ :see: https://docs.coinex.com/api/v2/futures/order/http/put-order
2200
+ :see: https://docs.coinex.com/api/v2/futures/order/http/put-stop-order
2201
+ :see: https://docs.coinex.com/api/v2/futures/position/http/close-position
2202
+ :see: https://docs.coinex.com/api/v2/futures/position/http/set-position-stop-loss
2203
+ :see: https://docs.coinex.com/api/v2/futures/position/http/set-position-take-profit
2185
2204
  :param str symbol: unified symbol of the market to create an order in
2186
2205
  :param str type: 'market' or 'limit'
2187
2206
  :param str side: 'buy' or 'sell'
@@ -2194,15 +2213,14 @@ class coinex(Exchange, ImplicitAPI):
2194
2213
  :param str [params.timeInForce]: 'GTC', 'IOC', 'FOK', 'PO'
2195
2214
  :param boolean [params.postOnly]: set to True if you wish to make a post only order
2196
2215
  :param boolean [params.reduceOnly]: *contract only* indicates if self order is to reduce the size of a position
2197
- :param int [params.position_id]: *required for reduce only orders* the position id to reduce
2198
2216
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2199
2217
  """
2200
2218
  self.load_markets()
2201
2219
  market = self.market(symbol)
2202
- reduceOnly = self.safe_value(params, 'reduceOnly')
2203
- triggerPrice = self.safe_number_2(params, 'stopPrice', 'triggerPrice')
2204
- stopLossTriggerPrice = self.safe_number(params, 'stopLossPrice')
2205
- takeProfitTriggerPrice = self.safe_number(params, 'takeProfitPrice')
2220
+ reduceOnly = self.safe_bool(params, 'reduceOnly')
2221
+ triggerPrice = self.safe_string_2(params, 'stopPrice', 'triggerPrice')
2222
+ stopLossTriggerPrice = self.safe_string(params, 'stopLossPrice')
2223
+ takeProfitTriggerPrice = self.safe_string(params, 'takeProfitPrice')
2206
2224
  isTriggerOrder = triggerPrice is not None
2207
2225
  isStopLossTriggerOrder = stopLossTriggerPrice is not None
2208
2226
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
@@ -2211,121 +2229,211 @@ class coinex(Exchange, ImplicitAPI):
2211
2229
  response = None
2212
2230
  if market['spot']:
2213
2231
  if isTriggerOrder:
2214
- if type == 'limit':
2215
- response = self.v1PrivatePostOrderStopLimit(request)
2216
- else:
2217
- response = self.v1PrivatePostOrderStopMarket(request)
2232
+ response = self.v2PrivatePostSpotStopOrder(request)
2233
+ #
2234
+ # {
2235
+ # "code": 0,
2236
+ # "data": {
2237
+ # "stop_id": 117180138153
2238
+ # },
2239
+ # "message": "OK"
2240
+ # }
2241
+ #
2218
2242
  else:
2219
- if type == 'limit':
2220
- response = self.v1PrivatePostOrderLimit(request)
2221
- else:
2222
- response = self.v1PrivatePostOrderMarket(request)
2243
+ response = self.v2PrivatePostSpotOrder(request)
2244
+ #
2245
+ # {
2246
+ # "code": 0,
2247
+ # "data": {
2248
+ # "amount": "0.0001",
2249
+ # "base_fee": "0",
2250
+ # "ccy": "BTC",
2251
+ # "client_id": "x-167673045-a0a3c6461459a801",
2252
+ # "created_at": 1714114386250,
2253
+ # "discount_fee": "0",
2254
+ # "filled_amount": "0",
2255
+ # "filled_value": "0",
2256
+ # "last_fill_amount": "0",
2257
+ # "last_fill_price": "0",
2258
+ # "maker_fee_rate": "0.002",
2259
+ # "market": "BTCUSDT",
2260
+ # "market_type": "SPOT",
2261
+ # "order_id": 117178743547,
2262
+ # "price": "61000",
2263
+ # "quote_fee": "0",
2264
+ # "side": "buy",
2265
+ # "taker_fee_rate": "0.002",
2266
+ # "type": "limit",
2267
+ # "unfilled_amount": "0.0001",
2268
+ # "updated_at": 1714114386250
2269
+ # },
2270
+ # "message": "OK"
2271
+ # }
2272
+ #
2223
2273
  else:
2224
2274
  if isTriggerOrder:
2225
- if type == 'limit':
2226
- response = self.v1PerpetualPrivatePostOrderPutStopLimit(request)
2227
- else:
2228
- response = self.v1PerpetualPrivatePostOrderPutStopMarket(request)
2275
+ response = self.v2PrivatePostFuturesStopOrder(request)
2276
+ #
2277
+ # {
2278
+ # "code": 0,
2279
+ # "data": {
2280
+ # "stop_id": 136915460994
2281
+ # },
2282
+ # "message": "OK"
2283
+ # }
2284
+ #
2229
2285
  elif isStopLossOrTakeProfitTrigger:
2230
2286
  if isStopLossTriggerOrder:
2231
- response = self.v1PerpetualPrivatePostPositionStopLoss(request)
2287
+ response = self.v2PrivatePostFuturesSetPositionStopLoss(request)
2288
+ #
2289
+ # {
2290
+ # "code": 0,
2291
+ # "data": {
2292
+ # "adl_level": 1,
2293
+ # "ath_margin_size": "2.14586666",
2294
+ # "ath_position_amount": "0.0001",
2295
+ # "avg_entry_price": "64376",
2296
+ # "bkr_price": "0",
2297
+ # "close_avbl": "0.0001",
2298
+ # "cml_position_value": "6.4376",
2299
+ # "created_at": 1714119054558,
2300
+ # "leverage": "3",
2301
+ # "liq_price": "0",
2302
+ # "maintenance_margin_rate": "0.005",
2303
+ # "maintenance_margin_value": "0.03218632",
2304
+ # "margin_avbl": "2.14586666",
2305
+ # "margin_mode": "cross",
2306
+ # "market": "BTCUSDT",
2307
+ # "market_type": "FUTURES",
2308
+ # "max_position_value": "6.4376",
2309
+ # "open_interest": "0.0001",
2310
+ # "position_id": 303884204,
2311
+ # "position_margin_rate": "3.10624785634397912265",
2312
+ # "realized_pnl": "-0.0032188",
2313
+ # "settle_price": "64376",
2314
+ # "settle_value": "6.4376",
2315
+ # "side": "long",
2316
+ # "stop_loss_price": "62000",
2317
+ # "stop_loss_type": "latest_price",
2318
+ # "take_profit_price": "0",
2319
+ # "take_profit_type": "",
2320
+ # "unrealized_pnl": "0",
2321
+ # "updated_at": 1714119054559
2322
+ # },
2323
+ # "message": "OK"
2324
+ # }
2325
+ #
2232
2326
  elif isTakeProfitTriggerOrder:
2233
- response = self.v1PerpetualPrivatePostPositionTakeProfit(request)
2327
+ response = self.v2PrivatePostFuturesSetPositionTakeProfit(request)
2328
+ #
2329
+ # {
2330
+ # "code": 0,
2331
+ # "data": {
2332
+ # "adl_level": 1,
2333
+ # "ath_margin_size": "2.14586666",
2334
+ # "ath_position_amount": "0.0001",
2335
+ # "avg_entry_price": "64376",
2336
+ # "bkr_price": "0",
2337
+ # "close_avbl": "0.0001",
2338
+ # "cml_position_value": "6.4376",
2339
+ # "created_at": 1714119054558,
2340
+ # "leverage": "3",
2341
+ # "liq_price": "0",
2342
+ # "maintenance_margin_rate": "0.005",
2343
+ # "maintenance_margin_value": "0.03218632",
2344
+ # "margin_avbl": "2.14586666",
2345
+ # "margin_mode": "cross",
2346
+ # "market": "BTCUSDT",
2347
+ # "market_type": "FUTURES",
2348
+ # "max_position_value": "6.4376",
2349
+ # "open_interest": "0.0001",
2350
+ # "position_id": 303884204,
2351
+ # "position_margin_rate": "3.10624785634397912265",
2352
+ # "realized_pnl": "-0.0032188",
2353
+ # "settle_price": "64376",
2354
+ # "settle_value": "6.4376",
2355
+ # "side": "long",
2356
+ # "stop_loss_price": "62000",
2357
+ # "stop_loss_type": "latest_price",
2358
+ # "take_profit_price": "70000",
2359
+ # "take_profit_type": "latest_price",
2360
+ # "unrealized_pnl": "0",
2361
+ # "updated_at": 1714119054559
2362
+ # },
2363
+ # "message": "OK"
2364
+ # }
2365
+ #
2234
2366
  else:
2235
2367
  if reduceOnly:
2236
- if type == 'limit':
2237
- response = self.v1PerpetualPrivatePostOrderCloseLimit(request)
2238
- else:
2239
- response = self.v1PerpetualPrivatePostOrderCloseMarket(request)
2368
+ response = self.v2PrivatePostFuturesClosePosition(request)
2369
+ #
2370
+ # {
2371
+ # "code": 0,
2372
+ # "data": {
2373
+ # "amount": "0.0001",
2374
+ # "client_id": "x-167673045-4f264600c432ac06",
2375
+ # "created_at": 1714119323764,
2376
+ # "fee": "0.003221",
2377
+ # "fee_ccy": "USDT",
2378
+ # "filled_amount": "0.0001",
2379
+ # "filled_value": "6.442017",
2380
+ # "last_filled_amount": "0.0001",
2381
+ # "last_filled_price": "64420.17",
2382
+ # "maker_fee_rate": "0",
2383
+ # "market": "BTCUSDT",
2384
+ # "market_type": "FUTURES",
2385
+ # "order_id": 136915813578,
2386
+ # "price": "0",
2387
+ # "realized_pnl": "0.004417",
2388
+ # "side": "sell",
2389
+ # "taker_fee_rate": "0.0005",
2390
+ # "type": "market",
2391
+ # "unfilled_amount": "0",
2392
+ # "updated_at": 1714119323764
2393
+ # },
2394
+ # "message": "OK"
2395
+ # }
2396
+ #
2240
2397
  else:
2241
- if type == 'limit':
2242
- response = self.v1PerpetualPrivatePostOrderPutLimit(request)
2243
- else:
2244
- response = self.v1PerpetualPrivatePostOrderPutMarket(request)
2245
- #
2246
- # Spot and Margin
2247
- #
2248
- # {
2249
- # "code": 0,
2250
- # "data": {
2251
- # "amount": "0.0005",
2252
- # "asset_fee": "0",
2253
- # "avg_price": "0.00",
2254
- # "client_id": "",
2255
- # "create_time": 1650951627,
2256
- # "deal_amount": "0",
2257
- # "deal_fee": "0",
2258
- # "deal_money": "0",
2259
- # "fee_asset": null,
2260
- # "fee_discount": "1",
2261
- # "finished_time": null,
2262
- # "id": 74510932594,
2263
- # "left": "0.0005",
2264
- # "maker_fee_rate": "0.002",
2265
- # "market": "BTCUSDT",
2266
- # "money_fee": "0",
2267
- # "order_type": "limit",
2268
- # "price": "30000",
2269
- # "status": "not_deal",
2270
- # "stock_fee": "0",
2271
- # "taker_fee_rate": "0.002",
2272
- # "type": "buy"
2273
- # },
2274
- # "message": "Success"
2275
- # }
2276
- #
2277
- # Swap
2278
- #
2279
- # {
2280
- # "code": 0,
2281
- # "data": {
2282
- # "amount": "0.0005",
2283
- # "client_id": "",
2284
- # "create_time": 1651004578.618224,
2285
- # "deal_asset_fee": "0.00000000000000000000",
2286
- # "deal_fee": "0.00000000000000000000",
2287
- # "deal_profit": "0.00000000000000000000",
2288
- # "deal_stock": "0.00000000000000000000",
2289
- # "effect_type": 1,
2290
- # "fee_asset": "",
2291
- # "fee_discount": "0.00000000000000000000",
2292
- # "last_deal_amount": "0.00000000000000000000",
2293
- # "last_deal_id": 0,
2294
- # "last_deal_price": "0.00000000000000000000",
2295
- # "last_deal_role": 0,
2296
- # "last_deal_time": 0,
2297
- # "last_deal_type": 0,
2298
- # "left": "0.0005",
2299
- # "leverage": "3",
2300
- # "maker_fee": "0.00030",
2301
- # "market": "BTCUSDT",
2302
- # "order_id": 18221659097,
2303
- # "position_id": 0,
2304
- # "position_type": 1,
2305
- # "price": "30000.00",
2306
- # "side": 2,
2307
- # "source": "api.v1",
2308
- # "stop_id": 0,
2309
- # "taker_fee": "0.00050",
2310
- # "target": 0,
2311
- # "type": 1,
2312
- # "update_time": 1651004578.618224,
2313
- # "user_id": 3620173
2314
- # },
2315
- # "message": "OK"
2316
- # }
2317
- #
2318
- # Stop Order
2319
- #
2320
- # {"code":0,"data":{"status":"success"},"message":"OK"}
2321
- #
2398
+ response = self.v2PrivatePostFuturesOrder(request)
2399
+ #
2400
+ # {
2401
+ # "code": 0,
2402
+ # "data": {
2403
+ # "amount": "0.0001",
2404
+ # "client_id": "x-167673045-1471b81d747080a0",
2405
+ # "created_at": 1714116769986,
2406
+ # "fee": "0",
2407
+ # "fee_ccy": "USDT",
2408
+ # "filled_amount": "0",
2409
+ # "filled_value": "0",
2410
+ # "last_filled_amount": "0",
2411
+ # "last_filled_price": "0",
2412
+ # "maker_fee_rate": "0.0003",
2413
+ # "market": "BTCUSDT",
2414
+ # "market_type": "FUTURES",
2415
+ # "order_id": 136913377780,
2416
+ # "price": "61000.42",
2417
+ # "realized_pnl": "0",
2418
+ # "side": "buy",
2419
+ # "taker_fee_rate": "0.0005",
2420
+ # "type": "limit",
2421
+ # "unfilled_amount": "0.0001",
2422
+ # "updated_at": 1714116769986
2423
+ # },
2424
+ # "message": "OK"
2425
+ # }
2426
+ #
2322
2427
  data = self.safe_dict(response, 'data', {})
2323
2428
  return self.parse_order(data, market)
2324
2429
 
2325
2430
  def create_orders(self, orders: List[OrderRequest], params={}) -> List[Order]:
2326
2431
  """
2327
2432
  create a list of trade orders(all orders should be of the same symbol)
2328
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot003_trade002_batch_limit_orders
2433
+ :see: https://docs.coinex.com/api/v2/spot/order/http/put-multi-order
2434
+ :see: https://docs.coinex.com/api/v2/spot/order/http/put-multi-stop-order
2435
+ :see: https://docs.coinex.com/api/v2/futures/order/http/put-multi-order
2436
+ :see: https://docs.coinex.com/api/v2/futures/order/http/put-multi-stop-order
2329
2437
  :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
2330
2438
  :param dict [params]: extra parameters specific to the api endpoint
2331
2439
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
@@ -2333,6 +2441,9 @@ class coinex(Exchange, ImplicitAPI):
2333
2441
  self.load_markets()
2334
2442
  ordersRequests = []
2335
2443
  symbol = None
2444
+ reduceOnly = False
2445
+ isTriggerOrder = False
2446
+ isStopLossOrTakeProfitTrigger = False
2336
2447
  for i in range(0, len(orders)):
2337
2448
  rawOrder = orders[i]
2338
2449
  marketId = self.safe_string(rawOrder, 'symbol')
@@ -2348,54 +2459,138 @@ class coinex(Exchange, ImplicitAPI):
2348
2459
  orderParams = self.safe_value(rawOrder, 'params', {})
2349
2460
  if type != 'limit':
2350
2461
  raise NotSupported(self.id + ' createOrders() does not support ' + type + ' orders, only limit orders are accepted')
2462
+ reduceOnly = self.safe_value(orderParams, 'reduceOnly')
2463
+ triggerPrice = self.safe_number_2(orderParams, 'stopPrice', 'triggerPrice')
2464
+ stopLossTriggerPrice = self.safe_number(orderParams, 'stopLossPrice')
2465
+ takeProfitTriggerPrice = self.safe_number(orderParams, 'takeProfitPrice')
2466
+ isTriggerOrder = triggerPrice is not None
2467
+ isStopLossTriggerOrder = stopLossTriggerPrice is not None
2468
+ isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
2469
+ isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder or isTakeProfitTriggerOrder
2351
2470
  orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
2352
2471
  ordersRequests.append(orderRequest)
2353
2472
  market = self.market(symbol)
2354
- if not market['spot']:
2355
- raise NotSupported(self.id + ' createOrders() does not support ' + market['type'] + ' orders, only spot orders are accepted')
2356
2473
  request = {
2357
2474
  'market': market['id'],
2358
- 'batch_orders': self.json(ordersRequests),
2475
+ 'orders': ordersRequests,
2359
2476
  }
2360
- response = self.v1PrivatePostOrderLimitBatch(request)
2361
- #
2362
- # {
2363
- # "code": 0,
2364
- # "data": [
2365
- # {
2366
- # "code": 0,
2367
- # "data": {
2368
- # "amount": "0.0005",
2369
- # "asset_fee": "0",
2370
- # "avg_price": "0.00",
2371
- # "client_id": "x-167673045-d34bfb41242d8fd1",
2372
- # "create_time": 1701229157,
2373
- # "deal_amount": "0",
2374
- # "deal_fee": "0",
2375
- # "deal_money": "0",
2376
- # "fee_asset": null,
2377
- # "fee_discount": "1",
2378
- # "finished_time": null,
2379
- # "id": 107745856676,
2380
- # "left": "0.0005",
2381
- # "maker_fee_rate": "0.002",
2382
- # "market": "BTCUSDT",
2383
- # "money_fee": "0",
2384
- # "order_type": "limit",
2385
- # "price": "23000",
2386
- # "source_id": "",
2387
- # "status": "not_deal",
2388
- # "stock_fee": "0",
2389
- # "taker_fee_rate": "0.002",
2390
- # "type": "buy"
2391
- # },
2392
- # "message": "OK"
2393
- # },
2394
- # ],
2395
- # "message": "Success"
2396
- # }
2397
- #
2398
- data = self.safe_value(response, 'data', [])
2477
+ response = None
2478
+ if market['spot']:
2479
+ if isTriggerOrder:
2480
+ response = self.v2PrivatePostSpotBatchStopOrder(request)
2481
+ #
2482
+ # {
2483
+ # "code": 0,
2484
+ # "data": [
2485
+ # {
2486
+ # "code": 0,
2487
+ # "data": {
2488
+ # "stop_id": 117186257510
2489
+ # },
2490
+ # "message": "OK"
2491
+ # },
2492
+ # ],
2493
+ # "message": "OK"
2494
+ # }
2495
+ #
2496
+ else:
2497
+ response = self.v2PrivatePostSpotBatchOrder(request)
2498
+ #
2499
+ # {
2500
+ # "code": 0,
2501
+ # "data": [
2502
+ # {
2503
+ # "amount": "0.0001",
2504
+ # "base_fee": "0",
2505
+ # "ccy": "BTC",
2506
+ # "client_id": "x-167673045-f3651372049dab0d",
2507
+ # "created_at": 1714121403450,
2508
+ # "discount_fee": "0",
2509
+ # "filled_amount": "0",
2510
+ # "filled_value": "0",
2511
+ # "last_fill_amount": "0",
2512
+ # "last_fill_price": "0",
2513
+ # "maker_fee_rate": "0.002",
2514
+ # "market": "BTCUSDT",
2515
+ # "market_type": "SPOT",
2516
+ # "order_id": 117185362233,
2517
+ # "price": "61000",
2518
+ # "quote_fee": "0",
2519
+ # "side": "buy",
2520
+ # "taker_fee_rate": "0.002",
2521
+ # "type": "limit",
2522
+ # "unfilled_amount": "0.0001",
2523
+ # "updated_at": 1714121403450
2524
+ # },
2525
+ # {
2526
+ # "code": 3109,
2527
+ # "data": null,
2528
+ # "message": "balance not enough"
2529
+ # }
2530
+ # ],
2531
+ # "message": "OK"
2532
+ # }
2533
+ #
2534
+ else:
2535
+ if isTriggerOrder:
2536
+ response = self.v2PrivatePostFuturesBatchStopOrder(request)
2537
+ #
2538
+ # {
2539
+ # "code": 0,
2540
+ # "data": [
2541
+ # {
2542
+ # "code": 0,
2543
+ # "data": {
2544
+ # "stop_id": 136919625994
2545
+ # },
2546
+ # "message": "OK"
2547
+ # },
2548
+ # ],
2549
+ # "message": "OK"
2550
+ # }
2551
+ #
2552
+ elif isStopLossOrTakeProfitTrigger:
2553
+ raise NotSupported(self.id + ' createOrders() does not support stopLossPrice or takeProfitPrice orders')
2554
+ else:
2555
+ if reduceOnly:
2556
+ raise NotSupported(self.id + ' createOrders() does not support reduceOnly orders')
2557
+ else:
2558
+ response = self.v2PrivatePostFuturesBatchOrder(request)
2559
+ #
2560
+ # {
2561
+ # "code": 0,
2562
+ # "data": [
2563
+ # {
2564
+ # "code": 0,
2565
+ # "data": {
2566
+ # "amount": "0.0001",
2567
+ # "client_id": "x-167673045-2cb7436f3462a654",
2568
+ # "created_at": 1714122832493,
2569
+ # "fee": "0",
2570
+ # "fee_ccy": "USDT",
2571
+ # "filled_amount": "0",
2572
+ # "filled_value": "0",
2573
+ # "last_filled_amount": "0",
2574
+ # "last_filled_price": "0",
2575
+ # "maker_fee_rate": "0.0003",
2576
+ # "market": "BTCUSDT",
2577
+ # "market_type": "FUTURES",
2578
+ # "order_id": 136918835063,
2579
+ # "price": "61000",
2580
+ # "realized_pnl": "0",
2581
+ # "side": "buy",
2582
+ # "taker_fee_rate": "0.0005",
2583
+ # "type": "limit",
2584
+ # "unfilled_amount": "0.0001",
2585
+ # "updated_at": 1714122832493
2586
+ # },
2587
+ # "message": "OK"
2588
+ # },
2589
+ # ],
2590
+ # "message": "OK"
2591
+ # }
2592
+ #
2593
+ data = self.safe_list(response, 'data', [])
2399
2594
  results = []
2400
2595
  for i in range(0, len(data)):
2401
2596
  entry = data[i]
@@ -2406,9 +2601,14 @@ class coinex(Exchange, ImplicitAPI):
2406
2601
  status = 'rejected'
2407
2602
  else:
2408
2603
  status = 'open'
2409
- item = self.safe_value(entry, 'data', {})
2410
- item['status'] = status
2411
- order = self.parse_order(item, market)
2604
+ innerData = self.safe_dict(entry, 'data', {})
2605
+ order = None
2606
+ if market['spot'] and not isTriggerOrder:
2607
+ entry['status'] = status
2608
+ order = self.parse_order(entry, market)
2609
+ else:
2610
+ innerData['status'] = status
2611
+ order = self.parse_order(innerData, market)
2412
2612
  results.append(order)
2413
2613
  return results
2414
2614
 
@@ -5447,17 +5647,22 @@ class coinex(Exchange, ImplicitAPI):
5447
5647
  self.check_required_credentials()
5448
5648
  query = self.keysort(query)
5449
5649
  urlencoded = self.rawencode(query)
5450
- preparedString = method + '/' + version + '/' + path + '?' + urlencoded + nonce + self.secret
5650
+ preparedString = method + '/' + version + '/' + path
5651
+ if method == 'POST':
5652
+ body = self.json(query)
5653
+ preparedString += body
5654
+ elif urlencoded:
5655
+ preparedString += '?' + urlencoded
5656
+ preparedString += nonce + self.secret
5451
5657
  signature = self.hash(self.encode(preparedString), 'sha256')
5452
5658
  headers = {
5453
5659
  'X-COINEX-KEY': self.apiKey,
5454
5660
  'X-COINEX-SIGN': signature,
5455
5661
  'X-COINEX-TIMESTAMP': nonce,
5456
5662
  }
5457
- if (method == 'GET') or (method == 'DELETE') or (method == 'PUT'):
5458
- url += '?' + urlencoded
5459
- else:
5460
- body = self.json(query)
5663
+ if method != 'POST':
5664
+ if urlencoded:
5665
+ url += '?' + urlencoded
5461
5666
  return {'url': url, 'method': method, 'body': body, 'headers': headers}
5462
5667
 
5463
5668
  def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):