UNPKG

remsed

Version:

A JavaScript cryptocurrency trading library with support for fairdesk.com

1,130 lines (1,095 loc) 63.1 kB
'use strict'; var Exchange = require('./base/Exchange.js'); var errors = require('./base/errors.js'); var number = require('./base/functions/number.js'); // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- class fairdesk extends Exchange["default"] { describe () { return this.deepExtend (super.describe (), { 'id': 'fairdesk', 'name': 'Fairdesk', 'countries': [ 'Singapore' ], // Singapore 'rateLimit': 100, 'version': 'v1', 'certified': false, 'pro': true, 'hostname': 'api.fairdesk.com', 'has': { 'CORS': undefined, 'spot': false, 'margin': false, 'swap': undefined, // has but not fully implemented 'future': false, 'option': false, 'cancelAllOrders': true, 'cancelOrder': true, 'createOrder': true, 'editOrder': false, 'fetchBalance': true, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchBorrowRatesPerSymbol': false, 'fetchClosedOrders': true, 'fetchCurrencies': false, 'fetchDepositAddress': true, 'fetchDeposits': true, 'fetchIndexOHLCV': false, 'fetchLeverageTiers': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchPositions': true, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': false, 'fetchWithdrawals': false, 'setLeverage': true, 'transfer': false, 'withdraw': false, }, 'urls': { 'logo': 'https://static.fairdesk.com/font/fairdesklogo.png', 'test': { 'public': 'https://api-testnet.fairdesk.com/api/v1/public', 'private': 'https://api-testnet.fairdesk.com/api/v1/private', }, 'api': { 'public': 'https://{hostname}/api/v1/public', 'private': 'https://{hostname}/api/v1/private', }, 'www': 'https://www.fairdesk.com', 'doc': 'https://github.com/fairdesk/fairdesk-api-docs', 'fees': 'https://www.fairdesk.com/fees', 'referral': 'https://www.fairdesk.com/signup?ref=URIJD5NI', }, 'timeframes': { '1m': '60', '3m': '180', '5m': '300', '15m': '900', '30m': '1800', '1h': '3600', '2h': '7200', '3h': '10800', '4h': '14400', '6h': '21600', '12h': '43200', '1d': '86400', '1w': '604800', '1M': '2592000', }, 'api': { 'public': { 'get': [ 'products', // contracts only 'md/orderbook', // ?symbol=BTCUSDT 'md/ticker24h', // ?symbol=BTCUSDT 'md/trade-recent', // ?symbol=BTCUSDT 'md/trade-history', // ?symbol=BTCUSDT&from=1651382628000 'md/kline', // ?symbol=BTCUSDT&interval=5m&from=1651382628000&to=1651469028000 ], }, 'private': { 'get': [ // swap 'account/order-detail', // orderId=571643709 'account/order-histories', // ?symbol=&type=&pageIndex=1&pageSize=1000 'account/balance', 'account/symbol-config', 'account/open-orders', 'account/positions', 'account/current-positions', 'account/trade-histories', // wallet 'wallet/deposit-address', // ?currency=ETH 'wallet/deposit-records', // ?startTime=0&currency=USDT&pageIndex=1&pageSize=20 ], 'post': [ // swap 'trade/place-order', 'trade/cancel-all-order', ], 'put': [ // swap 'account/config/adjust-leverage', ], 'delete': [ // swap 'trade/cancel-order', ], }, }, 'precisionMode': number.TICK_SIZE, 'fees': { 'trading': { 'tierBased': true, 'percentage': true, 'taker': this.parseNumber ('0.001'), 'maker': this.parseNumber ('0.001'), }, }, 'requiredCredentials': { 'apiKey': true, 'secret': true, }, 'exceptions': { 'exact': { "1000" : errors["default"].AccountNotEnabled, // no such account. "1002" : errors["default"].InsufficientFunds, // account settled currency do not match. "1004" : errors["default"].BadRequest, // leverage is too small "1005" : errors["default"].BadRequest, // leverage is too large. "1006" : errors["default"].BadRequest, // leverage is equal old leverage. "1007" : errors["default"].InsufficientFunds, // margin not enough. "1008" : errors["default"].InsufficientFunds, // balance insufficient. "1009" : errors["default"].BadRequest, // the amount of recharge is illegal. "1010" : errors["default"].BaseError, // the amount of balance change is illegal. "1011" : errors["default"].BaseError, // invalid margin change amount. "1012" : errors["default"].ExchangeError, // leverage reduction is not supported in Isolated Margin Mode with open positions. "1013" : errors["default"].ExchangeError, // balance version not equal. "2000" : errors["default"].ExchangeError, // invalid symbol id. "2004" : errors["default"].ExchangeError, // duplicated asset name "2005" : errors["default"].ExchangeError, // duplicated asset id "2006" : errors["default"].ExchangeError, // invalid asset id. "4000" : errors["default"].InvalidOrder, // no such order. "4001" : errors["default"].ArgumentsRequired, // price is missing. "4002" : errors["default"].ArgumentsRequired, // qty is missing. "4003" : errors["default"].ArgumentsRequired, // qty is invalid. "4004" : errors["default"].ArgumentsRequired, // invalid currency id. "4005" : errors["default"].OrderNotFillable, // unable to fill. "4006" : errors["default"].OrderImmediatelyFillable, // order would immediately trigger. "4007" : errors["default"].ExchangeError, // reduce only reject. "4008" : errors["default"].BadRequest, // position is not sufficient. "4009" : errors["default"].BadRequest, // reduce only rejected, position more than 0 while buy. "4010" : errors["default"].BadRequest, // reduce only rejected, position less than 0 while sell. "4011" : errors["default"].BadRequest, // max open order limit. "4012" : errors["default"].BadRequest, // max conditional order limit. "4013" : errors["default"].BadRequest, // conditional order is invalid. "4014" : errors["default"].DuplicateOrderId, // clientOrderId duplicated. "4015" : errors["default"].NotSupported, // reduce only reject, order type not supported. "4020" : errors["default"].CancelPending, // unknown order sent. "4021" : errors["default"].BadRequest, // unknown update type. "4030" : errors["default"].OrderNotFound, // reduceOnly order Failed. please check your existing position and open orders. "4040" : errors["default"].OrderNotFound, // unable to parse order. "4050" : errors["default"].InvalidOrder, // the counter party's best price does not meet the PERCENT_PRICE filter limit. "4051" : errors["default"].BadRequest, // order price not in the proper range. "4060" : errors["default"].BadRequest, // trigger price is missing. "4070" : errors["default"].OrderNotFound, // no open orders to close "4071" : errors["default"].DuplicateOrderId, // order id duplicated. "5000" : errors["default"].BadRequest, // positionSide is not valid. "5001" : errors["default"].BadRequest, // positionSide does not match with userSetting. "5002" : errors["default"].BadRequest, // isolated position quantity should more than 0 when add margin. "5003" : errors["default"].InsufficientFunds, // No balance for add position margin. "5004" : errors["default"].BadRequest, // Position margin can not decrease. "100" : errors["default"].RequestTimeout, // Request time out. "200" : errors["default"].BadRequest, // Price less than 0. "201" : errors["default"].BadRequest, // Price less than min price. "202" : errors["default"].BadRequest, // Price greater than max price. "203" : errors["default"].BadRequest, // Price not increased by tick size. "204" : errors["default"].BadRequest, // Quantity less than zero. "205" : errors["default"].BadRequest, // Quantity greater than max quantity. "206" : errors["default"].BadRequest, // Quantity less than min quantity. "207" : errors["default"].BadRequest, // Qty not increased by step size. "208" : errors["default"].BadRequest, // Trigger price less than zero. "209" : errors["default"].BadRequest, // Trigger price greater than max price. "210" : errors["default"].BadRequest, // Price trigger type is null or illegal. "211" : errors["default"].BadRequest, // not support order type. "212" : errors["default"].BadRequest, // client order length is not valid. "213" : errors["default"].BadRequest, // client order id is not valid. "214" : errors["default"].BadRequest, // Illegal characters found in a parameter. "216" : errors["default"].BadRequest, // Mandatory parameter {%s} was not sent, was empty/null, or malformed. "217" : errors["default"].BadRequest, // Parameter '%s' not required. "218" : errors["default"].BadRequest, // Invalid side. "219" : errors["default"].BadRequest, // Combination of optional parameters '%s' invalid. "220" : errors["default"].BadRequest, // price range not valid "221" : errors["default"].BadRequest, // Qty too large. "250" : errors["default"].BadRequest, // invalid currency. "300" : errors["default"].BadRequest, // invalid symbol. "301" : errors["default"].ExchangeError, // symbol can not trading now. "302" : errors["default"].ExchangeError, // symbol order can not cancel now. "400" : errors["default"].AccountNotEnabled, // invalid account. "401" : errors["default"].AccountNotEnabled, // account could not trade. "402" : errors["default"].BadRequest, // invalid leverage. "403" : errors["default"].BadRequest, // invalid user id. "405" : errors["default"].BadRequest, // invalid withdraw balance. "408" : errors["default"].InsufficientFunds, // account margin not enough. "501" : errors["default"].InsufficientFunds // wallet insufficient balance }, 'broad': { '401 Insufficient privilege': errors.PermissionDenied, // {"code": "401","msg": "401 Insufficient privilege."} '401 Request IP mismatch': errors.PermissionDenied, // {"code": "401","msg": "401 Request IP mismatch."} 'Failed to find api-key': errors.AuthenticationError, // {"msg":"Failed to find api-key 1c5ec63fd-660d-43ea-847a-0d3ba69e106e","code":10500} 'Missing required parameter': errors.BadRequest, // {"msg":"Missing required parameter","code":10500} 'API Signature verification failed': errors.AuthenticationError, // {"msg":"API Signature verification failed.","code":10500} 'Api key not found': errors.AuthenticationError, // {"msg":"Api key not found 698dc9e3-6faa-4910-9476-12857e79e198","code":"10500"} }, }, 'options': { 'x-fairdesk-request-expiry': 60, // in seconds 'createOrderByQuoteRequiresPrice': true, 'networks': { 'ERC20': 'ETH', 'TRC20': 'TRX', }, 'defaultNetworks': { 'USDT': 'ETH', }, 'defaultSubType': 'linear', 'accountsByType': { 'future': 'future', }, }, }); } parseSafeNumber (value = undefined) { if (value === undefined) { return value; } let parts = value.split (','); value = parts.join (''); parts = value.split (' '); return this.safeNumber (parts, 0); } parseSwapMarket (market) { const id = this.safeString (market, 'symbol'); const baseId = this.safeString (market, 'baseCurrency'); const quoteId = this.safeString (market, 'quoteCurrency'); const settleId = this.safeString (market, 'settleCurrency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const settle = this.safeCurrencyCode (settleId); const maxLevel = this.safeString (market, 'maxLeverage'); return { 'id': id, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': 'swap', 'spot': false, 'margin': false, 'swap': true, 'future': false, 'option': false, 'active': true, 'contract': false, 'linear': true, 'inverse': false, 'taker': this.parseNumber (this.safeString (market, 'takerFeeRate')), 'maker': this.parseNumber (this.safeString (market, 'makerFeeRate')), 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.safeNumber (market, 'stepSize'), 'price': this.safeNumber (market, 'tickSize'), }, 'limits': { 'leverage': { 'min': this.parseNumber ('1'), 'max': this.parseNumber (maxLevel), }, 'amount': { 'min': this.parseNumber (this.safeString (market, 'minOrderQty')), 'max': this.parseNumber (this.safeString (market, 'maxOrderQty')), }, 'price': { 'min': this.parseNumber (this.safeString (market, 'minPrice')), 'max': this.parseNumber (this.safeString (market, 'maxPrice')), }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'info': market, }; } async fetchMarkets (params = {}) { const response = await this.publicGetProducts (params); // { // "status": 0, // "error": "OK", // "data": [ { // "symbolId": 1211, // "symbol": "btcusdt", // "displayName": "BTC/USDT", // "baseCurrency": "BTC", // "quoteCurrency": "USDT", // "settleCurrency": "USDT", // "productType": "Perpetual", // "tickSize": "0.500000", // "stepSize": "0.001000", // "maxPrice": "500000.000000", // "minPrice": "0.500000", // "maxOrderQty": "100.000000", // "minOrderQty": "0.000000", // "maxLeverage": 125, // "defaultLeverage": 20, // "priceDecimal": 1, // "amountDecimal": 3, // "fundingInterval": "Every 8 hours", // "makerFeeRate": "0.0001", // "takerFeeRate": "0.00015", // "marketPriceDiffRate": 0.1, // "limitPriceDiffRate": 0.1, // "strategyPriceDiffRate": 0.075, // "liquidationFeeRate": 0.01 // },] // } const products = response.data; const result = []; for (let i = 0; i < products.length; i++) { let market = products[i]; market = this.parseSwapMarket (market); result.push (market); } return result; } parseBidAsk (bidask, priceKey = 0, amountKey = 1, market = undefined) { if (market === undefined) { throw new errors.ArgumentsRequired (this.id + ' parseBidAsk() requires a market argument'); } const amount = this.safeString (bidask, amountKey); return [ this.parseNumber (this.safeString (bidask, priceKey)), this.parseNumber (amount), ]; } parseOrderBook (orderbook, symbol, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 0, amountKey = 1, market = undefined) { const result = { 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'nonce': undefined, }; const sides = [ bidsKey, asksKey ]; for (let i = 0; i < sides.length; i++) { const side = sides[i]; const orders = []; const bidasks = this.safeValue (orderbook, side); for (let k = 0; k < bidasks.length; k++) { orders.push (this.parseBidAsk (bidasks[k], priceKey, amountKey, market)); } result[side] = orders; } result[bidsKey] = this.sortBy (result[bidsKey], 0, true); result[asksKey] = this.sortBy (result[asksKey], 0); return result; } async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const symbolId = this.parseSymbol (symbol); const market = this.market (symbolId); const request = { 'symbol': market['id'], }; const response = await this.publicGetMdOrderbook (this.extend (request, params)); // { // "status": 0, // "error": "OK", // "data": { // "symbol": "btcusdt", // "bids": [ // [ 35886.500000, 0.314000 ], // [ 35886.000000, 0.204000 ], // ], // "asks": [ // [ 35887.500000, 0.058000 ], // [ 35888.000000, 0.038000 ], // ], // } // } const result = this.safeValue (response, 'data', {}); const timestamp = this.safeIntegerProduct (result, 'timestamp', 0.000001); return this.parseOrderBook (result, symbol, timestamp, 'bids', 'asks', 0, 1, market); } parseOHLCV (ohlcv, market = undefined) { return [ this.parseNumber (this.safeString (ohlcv, 'closeTime')), this.parseNumber (this.safeString (ohlcv, 'open')), this.parseNumber (this.safeString (ohlcv, 'high')), this.parseNumber (this.safeString (ohlcv, 'low')), this.parseNumber (this.safeString (ohlcv, 'close')), this.parseNumber (this.safeString (ohlcv, 'volume')), ]; } async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { const request = { 'interval': timeframe, }; let startTime = 0; let endTime = 0; const duration = this.parseTimeframe (timeframe); const now = this.seconds (); if (since !== undefined) { if (limit === undefined) { limit = 1000; // max 1000 } since = parseInt (since / 1000); startTime = since; // time ranges ending in the future are not accepted // https://github.com/ccxt/ccxt/issues/8050 endTime = Math.min (now, this.sum (since, duration * limit)); } else if (limit !== undefined) { limit = Math.min (limit, 1000); startTime = now - duration * this.sum (limit, 1); endTime = now; } else { throw new errors.ArgumentsRequired (this.id + ' fetchOHLCV() requires a since argument, or a limit argument, or both'); } request['from'] = startTime * 1000; request['to'] = endTime * 1000; await this.loadMarkets (); const symbolId = this.parseSymbol (symbol); const market = this.market (symbolId); request['symbol'] = market['id']; const response = await this.publicGetMdKline (this.extend (request, params)); // { // "status": 0, // "error": "OK", // "data": [ { // "openTime": 1651382700000, // "intervalId": "5m", // "closeTime": 1651382999999, // "open": 38076.000000, // "close": 38095.000000, // "high": 38098.000000, // "low": 38056.500000, // "avgPrice": 38066.500000, // "volume": 0.067000, // "quoteVolume": 2551.822500, // "symbol": "btcusdt", // "closed": true, // "numTrades": 15 // },] // } const rows = this.safeValue (response, 'data', {}); return this.parseOHLCVs (rows, market, timeframe, since, limit); } parseTicker (ticker, market = undefined) { const marketId = this.safeString (ticker, 'symbol'); market = this.safeMarket (marketId, market); const symbol = market['symbol']; const timestamp = this.parseNumber (this.safeString (ticker, 'timestamp')); const last = this.safeString (ticker, 'close'); const open = this.safeString (ticker, 'open'); return this.safeTicker ({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'high': this.safeString (ticker, 'high'), 'low': this.safeString (ticker, 'low'), 'open': open, 'close': last, 'last': last, 'bid': undefined, 'bidVolume': undefined, 'ask': undefined, 'askVolume': undefined, 'vwap': undefined, 'previousClose': undefined, // previous day close 'change': last - open, 'percentage': (last - open) / open * 100, 'average': this.safeString (ticker, 'averagePrice'), 'baseVolume': this.safeString (ticker, 'baseVolume'), 'quoteVolume': this.safeString (ticker, 'quoteVolume'), 'info': ticker, }, market, false); } parseSymbol (symbol) { const str = symbol.replace ('/', ''); return str.toLowerCase (); } async fetchTicker (symbol, params = {}) { await this.loadMarkets (); const symbolId = this.parseSymbol (symbol); const market = this.market (symbolId); const request = { 'symbol': market['id'], }; const response = await this.publicGetMdTicker24h (this.extend (request, params)); // { // "status": 0, // "error": "OK", // "data": { // "symbol": "btcusdt", // "timestamp": 1651895571086, // "open": 36439.500000, // "high": 36542.500000, // "low": 35344.500000, // "close": 35890.000000, // "indexPrice": 35891.0, // "markPrice": 35892.9, // "openInterest": 74.275366, // "fundingRate": 0.00010000, // "predicateFundingRate": 0.000100, // "baseVolume": 313.214000, // "quoteVolume": 11280153.148 // } // } const result = this.safeValue (response, 'data', {}); return this.parseTicker (result, market); } async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { const symbolId = this.parseSymbol (symbol); await this.loadMarkets (); const market = this.market (symbolId); const request = { 'symbol': market['id'], }; let method = 'publicGetMdTradeRecent'; if (since) { method = 'publicGetMdTradeHistory'; request['from'] = since; } const response = await this[method] (this.extend (request, params)); // { // "status": 0, // "error": "OK", // "data": { // "symbol": "btcusdt", // "timestamp": 1651895759240, // "trades": [{ // "tradeId": 245418671, // "orderId": 45014798997, // "qty": 38408.500000, // "price": 38408.500000, // "timestamp": 1651447203805, // "updateId": 47240871986, // "taker": true, // "buyMaker": false // },] // } // } const result = this.safeValue (response, 'data', {}); const trades = this.safeValue (result, 'trades', []); return this.parsePubTrades (trades, market, since, limit); } parsePubTrades (trades, market = undefined, since = undefined, limit = undefined, params = {}) { const result = []; for (let i = 0; i < trades.length; i++) { const item = trades[i]; result.push (this.parsePubTrade (item, market)); } return result; } parseMyTrades (trades, market = undefined, since = undefined, limit = undefined, params = {}) { const result = []; for (let i = 0; i < trades.length; i++) { const item = trades[i]; result.push (this.parseMyTrade (item, market)); } return result; } parsePubTrade (trade, market = undefined) { const symbol = market['symbol']; const timestamp = this.safeNumber (trade, 'timestamp'); return { 'info': trade, 'id': this.safeString (trade, 'tradeId'), 'symbol': symbol, 'order': this.safeString (trade, 'orderId'), 'price': this.safeString (trade, 'price'), 'amount': this.safeString (trade, 'qty'), 'takerOrMaker': 'taker', 'type': undefined, 'side': undefined, 'cost': undefined, 'fee': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp) }; } parseMyTrade (trade, market = undefined) { const symbol = market['symbol']; const timestamp = this.safeNumber (trade, 'timestamp'); const isMaker = this.safeValue (trade, 'maker'); const side = this.safeStringLower (trade, 'side'); const positionSide = this.safeStringLower (trade, 'positionSide'); return { 'info': trade, 'id': this.safeString (trade, 'tradeId'), 'symbol': symbol, 'order': this.safeString (trade, 'orderId'), 'type': undefined, 'side': side, 'positionSide': positionSide, 'takerOrMaker': isMaker ? "maker" : "taker", 'price': this.safeString (trade, 'lastPrice'), 'amount': this.safeString (trade, 'lastQty'), 'cost': undefined, 'fee': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp) }; } parseSwapBalance (response) { const data = this.safeValue (response, 'data', {}); const balance = this.safeValue (data, 'accounts', {})[0]; const free = this.safeNumber (balance, 'availBalance'); const used = this.safeNumber (balance, 'positionMargin'); const total = this.safeNumber (balance, 'accountBalance'); return { 'info': balance, 'USDT': { free, used, total, }, 'free': { 'USDT': free }, 'used': { 'USDT': used }, 'total': { 'USDT': total }, }; } async fetchBalance (params = {}) { await this.loadMarkets (); const request = {}; const response = await this.privateGetAccountBalance (this.extend (request, params)); // { // "status": "0", // "error": "OK", // "data": { // "marginBalanceUsd": "439275458.22", // "marginBalanceBtc": "12247.58222118", // "totalAccountBalance": "439275458.34", // "totalUnRealizedPnL": "-0.12", // "accounts": [ // { // "currency": "USDT", // "icon": "https://fairdesk-app2public-prod.s3.ap-southeast-1.amazonaws.com/currency/USDT.png", // "accountBalance": "439275458.34", // "availBalance": "439275440.23", // "unRealizedPnL": "-0.12", // "positionMargin": "10.84", // "bonus": "495.00", // "bonusBalance": "0.00", // "display": "Tether" // } // ] // } // } return this.parseSwapBalance (response); } parseOrderType (type) { const types = { 'LIMIT': 'limit', 'MARKET': 'market', }; return this.safeString (types, type, type); } parseTimeInForce (timeInForce) { const timeInForces = { 'GTC': 'GTC', 'POST_ONLY': 'PO', 'IOC': 'IOC', 'FOK': 'FOK', }; return this.safeString (timeInForces, timeInForce, timeInForce); } parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) { const result = []; for (let i = 0; i < orders.length; i++) { const item = orders[i]; result.push (this.parseOrder (item)); } return result; } parseOrder (order, market = undefined) { const symbol = this.safeString (order, 'symbol'); const state = () => { let value = ''; if (this.safeString (order, 'status') === 'FILLED') { value = 'closed'; } if (this.safeString (order, 'status') === 'CANCELED') { value = 'canceled'; } if (this.safeString (order, 'status') === 'EXPIRED') { value = 'expired'; } if (this.safeString (order, 'status') === 'NEW') { value = 'open'; } return value; }; const status = state (); // 'open', 'closed', 'canceled', 'expired', 'rejected' const side = this.safeStringLower (order, 'side'); const positionSide = this.safeStringLower (order, 'positionSide'); const type = this.parseOrderType (this.safeString (order, 'type')); const price = this.parseNumber (this.safeString (order, 'price') === '--' ? '' : this.safeString (order, 'price')); const amount = this.safeNumber (order, 'origQty'); const remaining = amount - this.safeNumber (order, 'executedQty'); const timestamp = this.safeNumber (order, 'transactTime'); const timeInForce = this.parseTimeInForce (this.safeString (order, 'timeInForce')); return { 'info': order, 'id': this.safeString (order, 'orderId'), 'clientOrderId': this.safeString (order, 'clientOrderId'), 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': timestamp, 'symbol': symbol, 'type': type, 'timeInForce': timeInForce, 'postOnly': (timeInForce === 'PO'), 'side': side, 'positionSide': positionSide, 'price': price, 'stopPrice': this.safeNumber (order, 'triggerPrice'), 'amount': amount, 'filled': this.safeNumber (order, 'executedQty'), 'remaining': remaining, 'cost': undefined, 'average': undefined, 'status': status, 'fee': undefined, 'trades': undefined, }; } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { if (type.toLocaleUpperCase () !== 'MARKET' && type.toLocaleUpperCase () !== 'LIMIT') { throw new errors.ArgumentsRequired (this.id + ' createOrder() only support Market or Limit type'); } await this.loadMarkets (); const symbolId = this.parseSymbol (symbol); const market = this.market (symbolId); const sideValue = side.toLocaleUpperCase (); const request = { 'symbol': market['id'], 'price': price, 'quantity': amount, 'side': sideValue, // SELL, BUY 'type': type.toLocaleUpperCase (), // MARKET, LIMIT 'clientOrderId': `CCXT_${this.uuid ()}`, 'orderRespType': 'ACK', 'positionSide': params.positionSide || (sideValue === 'BUY' ? 'LONG' : 'SHORT'), 'isolated': params.isolated || false, 'slTriggerPrice': params.slTriggerPrice || null, 'slTriggerType': params.slTriggerType || null, 'tpTriggerPrice': params.tpTriggerPrice || null, 'tpTriggerType': params.tpTriggerType || null, 'timeInForce': params.timeInForce || 'GTC', }; if (type === 'Market') { request['timeInForce'] = null; request['price'] = null; } const response = await this.privatePostTradePlaceOrder (this.extend (request, params)); // { // "status": "0", // "error": "OK", // "data": { // "orderId": "46021554552", // "clientOrderId": "CCXT_018ff2a6-82bd-46ac-ac1a-95bd2254f70f", // "symbol": "btcusdt", // "isolated": true, // "cumQty": "0.000000", // "cumQuote": "0.000000", // "executedQty": "0.000000", // "avgPrice": "0.000000", // "origQty": "0.001000", // "price": "50000.000000", // "side": "SELL", // "positionSide": "SHORT", // "timeInForce": "GTC", // "origType": "LIMIT", // "type": "LIMIT", // "activatePrice": null, // "priceRate": null, // "timestamp": 1652004521408, // "triggerPrice": "0.000000", // "triggerType": "TRIGGER_NONE", // "tpTriggerType": "MARK_PRICE", // "tpTriggerPrice": "30000.000000", // "slTriggerType": "MARK_PRICE", // "slTriggerPrice": "60000.000000", // "strategyParentId": "0", // "status": "NEW" // } // } const data = this.safeValue (response, 'data', {}); return this.parseOrder (data, market); } async cancelOrder (id, symbol = undefined, params = {}) { if (symbol === undefined) { throw new errors.ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument'); } const symbolId = this.parseSymbol (symbol); await this.loadMarkets (); const market = this.market (symbolId); const request = { 'symbol': market['id'], 'orderId': id, }; const response = await this.privateDeleteTradeCancelOrder (this.extend (request, params)); // { // "status": "0", // "error": "OK", // "data": { // "orderId": "46016822947", // "clientOrderId": "strategy_sub_46016822945_46016822947", // "symbol": "btcusdt", // "isolated": false, // "cumQty": "0.000000", // "cumQuote": "0.000000", // "executedQty": "0.000000", // "avgPrice": "0.000000", // "origQty": "0.001000", // "price": "0.000000", // "side": "SELL", // "positionSide": "LONG", // "timeInForce": "IOC", // "origType": "TAKE_PROFIT_MARKET", // "type": "TAKE_PROFIT_MARKET", // "activatePrice": null, // "priceRate": null, // "triggerPrice": "50000.000000", // "triggerType": "LAST_PRICE", // "tpTriggerType": "TRIGGER_NONE", // "tpTriggerPrice": "0.000000", // "slTriggerType": "TRIGGER_NONE", // "slTriggerPrice": "0.000000", // "strategyParentId": "46016822945", // "status": "NEW" // } // } if (response.status !== '0') { return response; } const data = this.safeValue (response, 'data', {}); return this.parseOrder (data, market); } async cancelAllOrders (symbol = undefined, params = {}) { await this.loadMarkets (); const request = { 'settleCcy': 'USDT', }; // { // data: {symbol: null} // symbol: null // error: "OK" // status: 0 // } return await this.privatePostTradeCancelAllOrder (this.extend (request, params)); } async fetchOrder (id, symbol = undefined, params = {}) { const request = { 'orderId': id, }; const response = await this.privateGetAccountOrderDetail (this.extend (request, params)); // { // "status": "0", // "error": "OK", // "data": { // "orderId": "45979094101", // "symbol": "btcusdt", // "type": "LIMIT", // "origQty": "0.001", // "executedQty": "0.000", // "avlPrice": "0.0", // "price": "50000.0", // "fee": "0.00000000", // "realizedPnl": "0.00000000", // "timeInForce": "GTC", // "isolated": false, // "side": "SELL", // "positionSide": "SHORT", // "status": "CANCELED", // "trades": [], // "transactTime": "1651908682456", // "baseCcy": "BTC", // "quoteCcy": "USDT", // "settledCcy": "USDT" // } // } const data = this.safeValue (response, 'data', {}); return this.parseOrder (data); } async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { throw new errors.ArgumentsRequired (this.id + ' fetchOrders() requires a symbol argument'); } const symbolId = this.parseSymbol (symbol); await this.loadMarkets (); const market = this.market (symbolId); const request = { 'symbol': market['id'], }; if (since !== undefined) { request['start'] = since; } if (limit !== undefined) { request['limit'] = limit; } const response = await this.privateGetAccountOrderHistories (this.extend (request, params)); // { // "status": 0, // "error": null, // "data": { // "rows": [ // { // "orderId": 45979094101, // "clientOrderId": "WEB_Ml6Zo-GV8HSq", // "symbol": "btcusdt", // "type": "LIMIT", // "origQty": "0.001", // "executedQty": "0.000", // "avlPrice": "0.0", // "price": "50000.0", // "timeInForce": "GTC", // "isolated": false, // "side": "SELL", // "positionSide": "SHORT", // "transactTime": 1651908682456, // "markPriceAtPlace": "35842.9", // "lastPriceAtPlace": "35959.0", // "status": "CANCELED", // "closePosition": false, // "triggerPrice": "0.0", // "triggerType": "TRIGGER_NONE", // "tpTriggerType": "TRIGGER_NONE", // "tpTriggerPrice": "0.0", // "slTriggerType": "TRIGGER_NONE", // "slTriggerPrice": "0.0", // "strategyParentId": 0, // "liqCounterpartyType": "L_NONE", // "baseCcy": "BTC", // "settledCcy": "USDT" // } // ], // "total": 1 // } // } const data = this.safeValue (response, 'data', {}); const rows = this.safeValue (data, 'rows', []); return this.parseOrders (rows, market, since, limit); } async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { throw new errors.ArgumentsRequired (this.id + ' fetchOpenOrders() requires a symbol argument'); } await this.loadMarkets (); const symbolId = this.parseSymbol (symbol); const market = this.market (symbolId); const request = { 'symbol': market['id'], }; const response = await this.privateGetAccountOpenOrders (this.extend (request, params)); // { // "status": "0", // "error": "OK", // "data": [ // { // "orderId": "46016469910", // "clientOrderId": "CCXT_789a8c13-96d7-4ed1-b0ff-9e5fd1ea6831", // "symbol": "btcusdt", // "type": "LIMIT", // "origQty": "0.001", // "executedQty": "0.000", // "price": "50000.0", // "timeInForce": "POST_ONLY", // "isolated": true, // "side": "SELL", // "positionSide": "SHORT", // "transactTime": "1651907590785", // "status": "NEW", // "markPriceAtPlace": "35813.2", // "lastPriceAtPlace": null, // "closePosition": false, // "triggerPrice": "0.0", // "triggerType": "TRIGGER_NONE", // "tpTriggerType": "MARK_PRICE", // "tpTriggerPrice": "30000.0", // "slTriggerType": "MARK_PRICE", // "slTriggerPrice": "60000.0", // "strategyParentId": "0" // } // ] // } const data = this.safeValue (response, 'data', {}); return this.parseOrders (data, market, since, limit); } async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { throw new errors.ArgumentsRequired (this.id + ' fetchClosedOrders() requires a symbol argument'); } const symbolId = this.parseSymbol (symbol); await this.loadMarkets (); const market = this.market (symbolId); const request = { 'symbol': market['id'], 'status': 'CANCELED', }; if (since !== undefined) { request['start'] = since; } if (limit !== undefined) { request['limit'] = limit; } const response = await this.privateGetAccountOrderHistories (this.extend (request, params)); // { // "status": 0, // "error": null, // "data": { // "rows": [ { // "orderId": 45719135140, // "clientOrderId": "liq_close_5cf4e09084b44f59a612fa78fd7bcb7c", // "symbol": "btcusdt", // "type": "LIQUIDATION", // "origQty": "0.020", // "executedQty": "0.020", // "avlPrice": "36492.0", // "price": "36210.979", // "timeInForce": "IOC", // "isolated": true, // "side": "SELL", // "positionSide": "LONG", // "transactTime": 1651775063605, // "markPriceAtPlace": "36352.5", // "lastPriceAtPlace": "36573.0", // "status": "FILLED", // "closePosition": false, // "triggerPrice": "0.0", // "triggerType": "TRIGGER_NONE", // "tpTriggerType": "TRIGGER_NONE", // "tpTriggerPrice": "0.0", // "slTriggerType": "TRIGGER_NONE", // "slTriggerPrice": "0.0", // "strategyParentId": 0, // "liqCounterpartyType": "L_ORDER_BOOK", // "baseCcy": "BTC", // "settledCcy": "USDT" // },], // "total": 430 // } // } const data = this.safeValue (response, 'data', {}); const rows = this.safeValue (data, 'rows', []); return this.parseOrders (rows, market, since, limit); } async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { throw new errors.ArgumentsRequired (this.id + ' fetchMyTrades() requires a symbol argument'); } await this.loadMarkets (); const symbolId = this.parseSymbol (symbol); const market = this.market (symbolId); const request = { 'symbol': market['id'], }; if (