UNPKG

remsed

Version:

A JavaScript cryptocurrency trading library with support for fairdesk.com

1,203 lines (1,201 loc) 97.8 kB
'use strict'; var Exchange = require('./base/Exchange.js'); var errors = require('./base/errors.js'); var Precise = require('./base/Precise.js'); var number = require('./base/functions/number.js'); // ---------------------------------------------------------------------------- // --------------------------------------------------------------------------- class woo extends Exchange["default"] { describe() { return this.deepExtend(super.describe(), { 'id': 'woo', 'name': 'WOO X', 'countries': ['KY'], 'rateLimit': 100, 'version': 'v1', 'certified': false, 'pro': true, 'hostname': 'woo.org', 'has': { 'CORS': undefined, 'spot': true, 'margin': true, 'swap': true, 'future': false, 'option': false, 'addMargin': false, 'borrowMargin': false, 'cancelAllOrders': true, 'cancelOrder': true, 'cancelWithdraw': false, 'createDepositAddress': false, 'createMarketOrder': false, 'createOrder': true, 'createReduceOnlyOrder': true, 'createStopLimitOrder': false, 'createStopMarketOrder': false, 'createStopOrder': false, 'fetchAccounts': true, 'fetchBalance': true, 'fetchCanceledOrders': false, 'fetchClosedOrder': false, 'fetchClosedOrders': false, 'fetchCurrencies': true, 'fetchDepositAddress': false, 'fetchDeposits': true, 'fetchFundingHistory': true, 'fetchFundingRate': true, 'fetchFundingRateHistory': true, 'fetchFundingRates': true, 'fetchIndexOHLCV': false, 'fetchLedger': true, 'fetchLeverage': true, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrder': false, 'fetchOpenOrders': false, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPosition': true, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': false, 'fetchTicker': false, 'fetchTickers': false, 'fetchTime': false, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': true, 'fetchTransactions': true, 'fetchTransfers': true, 'fetchWithdrawals': true, 'reduceMargin': false, 'repayMargin': true, 'setLeverage': true, 'setMargin': false, 'transfer': true, 'withdraw': true, // exchange have that endpoint disabled atm, but was once implemented in ccxt per old docs: https://kronosresearch.github.io/wootrade-documents/#token-withdraw }, 'timeframes': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '4h': '4h', '12h': '12h', '1d': '1d', '1w': '1w', '1M': '1mon', '1y': '1y', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/150730761-1a00e5e0-d28c-480f-9e65-089ce3e6ef3b.jpg', 'api': { 'pub': 'https://api-pub.woo.org', 'public': 'https://api.{hostname}', 'private': 'https://api.{hostname}', }, 'test': { 'pub': 'https://api-pub.staging.woo.org', 'public': 'https://api.staging.woo.org', 'private': 'https://api.staging.woo.org', }, 'www': 'https://woo.org/', 'doc': [ 'https://docs.woo.org/', ], 'fees': [ 'https://support.woo.org/hc/en-001/articles/4404611795353--Trading-Fees', ], 'referral': 'https://referral.woo.org/BAJS6oNmZb3vi3RGA', }, 'api': { 'v1': { 'pub': { 'get': { 'hist/kline': 10, 'hist/trades': 1, }, }, 'public': { 'get': { 'info': 1, 'info/{symbol}': 1, 'system_info': 1, 'market_trades': 1, 'token': 1, 'token_network': 1, 'funding_rates': 1, 'funding_rate/{symbol}': 1, 'funding_rate_history': 1, 'futures': 1, 'futures/{symbol}': 1, }, }, 'private': { 'get': { 'client/token': 1, 'order/{oid}': 1, 'client/order/{client_order_id}': 1, 'orders': 1, 'orderbook/{symbol}': 1, 'kline': 1, 'client/trade/{tid}': 1, 'order/{oid}/trades': 1, 'client/trades': 1, 'client/info': 60, 'asset/deposit': 10, 'asset/history': 60, 'sub_account/all': 60, 'sub_account/assets': 60, 'token_interest': 60, 'token_interest/{token}': 60, 'interest/history': 60, 'interest/repay': 60, 'funding_fee/history': 30, 'positions': 3.33, 'position/{symbol}': 3.33, }, 'post': { 'order': 5, 'asset/main_sub_transfer': 30, 'asset/withdraw': 30, 'interest/repay': 60, 'client/account_mode': 120, 'client/leverage': 120, }, 'delete': { 'order': 1, 'client/order': 1, 'orders': 1, 'asset/withdraw': 120, // implemented in ccxt, disabled on the exchange side https://kronosresearch.github.io/wootrade-documents/#cancel-withdraw-request }, }, }, 'v2': { 'private': { 'get': { 'client/holding': 1, }, }, }, 'v3': { 'private': { 'get': { 'algo/order/{oid}': 1, 'algo/orders': 1, 'balances': 1, 'accountinfo': 60, 'positions': 3.33, 'buypower': 1, }, 'post': { 'algo/order': 5, }, 'put': { 'order/{oid}': 2, 'order/client/{oid}': 2, 'algo/order/{oid}': 2, 'algo/order/client/{oid}': 2, }, 'delete': { 'algo/order/{oid}': 1, 'algo/orders/pending': 1, 'algo/orders/pending/{symbol}': 1, 'orders/pending': 1, }, }, }, }, 'fees': { 'trading': { 'tierBased': true, 'percentage': true, 'maker': this.parseNumber('0.0002'), 'taker': this.parseNumber('0.0005'), }, }, 'options': { 'createMarketBuyOrderRequiresPrice': true, // these network aliases require manual mapping here 'network-aliases-for-tokens': { 'HT': 'ERC20', 'OMG': 'ERC20', 'UATOM': 'ATOM', 'ZRX': 'ZRX', }, 'networks': { 'TRX': 'TRON', 'TRC20': 'TRON', 'ERC20': 'ETH', 'BEP20': 'BSC', }, // override defaultNetworkCodePriorities for a specific currency 'defaultNetworkCodeForCurrencies': { // 'USDT': 'TRC20', // 'BTC': 'BTC', }, 'transfer': { 'fillResponseFromRequest': true, }, }, 'commonCurrencies': {}, 'exceptions': { 'exact': { '-1000': errors.ExchangeError, '-1001': errors.AuthenticationError, '-1002': errors.AuthenticationError, '-1003': errors.RateLimitExceeded, '-1004': errors.BadRequest, '-1005': errors.BadRequest, '-1006': errors.BadRequest, '-1007': errors.BadRequest, '-1008': errors.InvalidOrder, '-1009': errors.BadRequest, '-1011': errors.ExchangeError, '-1012': errors.BadRequest, '-1101': errors.InvalidOrder, '-1102': errors.InvalidOrder, '-1103': errors.InvalidOrder, '-1104': errors.InvalidOrder, '-1105': errors.InvalidOrder, // { "code": -1105, "message": "Price is X% too high or X% too low from the mid price." } }, 'broad': { 'symbol must not be blank': errors.BadRequest, 'The token is not supported': errors.BadRequest, 'Your order and symbol are not valid or already canceled': errors.BadRequest, 'Insufficient WOO. Please enable margin trading for leverage trading': errors.BadRequest, // when selling insufficent token [-1012] }, }, 'precisionMode': number.TICK_SIZE, }); } async fetchMarkets(params = {}) { /** * @method * @name woo#fetchMarkets * @description retrieves data on all markets for woo * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const response = await this.v1PublicGetInfo(params); // // { // rows: [ // { // symbol: "SPOT_AAVE_USDT", // quote_min: 0, // quote_max: 100000, // quote_tick: 0.01, // base_min: 0.01, // base_max: 7284, // base_tick: 0.0001, // min_notional: 10, // price_range: 0.1, // created_time: "0", // updated_time: "1639107647.988", // is_stable: 0 // }, // ... // success: true // } // const result = []; const data = this.safeValue(response, 'rows', []); for (let i = 0; i < data.length; i++) { const market = data[i]; const marketId = this.safeString(market, 'symbol'); const parts = marketId.split('_'); let marketType = this.safeStringLower(parts, 0); const isSpot = marketType === 'spot'; const isSwap = marketType === 'perp'; const baseId = this.safeString(parts, 1); const quoteId = this.safeString(parts, 2); const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); let settleId = undefined; let settle = undefined; let symbol = base + '/' + quote; let contractSize = undefined; let linear = undefined; if (isSwap) { settleId = this.safeString(parts, 2); settle = this.safeCurrencyCode(settleId); symbol = base + '/' + quote + ':' + settle; contractSize = this.parseNumber('1'); marketType = 'swap'; linear = true; } result.push({ 'id': marketId, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': marketType, 'spot': isSpot, 'margin': true, 'swap': isSwap, 'future': false, 'option': false, 'active': undefined, 'contract': isSwap, 'linear': linear, 'inverse': undefined, 'contractSize': contractSize, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.safeNumber(market, 'base_tick'), 'price': this.safeNumber(market, 'quote_tick'), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber(market, 'base_min'), 'max': this.safeNumber(market, 'base_max'), }, 'price': { 'min': this.safeNumber(market, 'quote_min'), 'max': this.safeNumber(market, 'quote_max'), }, 'cost': { 'min': this.safeNumber(market, 'min_notional'), 'max': undefined, }, }, 'info': market, }); } return result; } async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name woo#fetchTrades * @description get the list of most recent trades for a particular symbol * @param {string} symbol unified symbol of the market to fetch trades for * @param {int|undefined} since timestamp in ms of the earliest trade to fetch * @param {int|undefined} limit the maximum amount of trades to fetch * @param {object} params extra parameters specific to the woo api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades} */ if (symbol === undefined) { throw new errors.ArgumentsRequired(this.id + ' fetchTrades() requires a symbol argument'); } await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { request['limit'] = limit; } const response = await this.v1PublicGetMarketTrades(this.extend(request, params)); // // { // success: true, // rows: [ // { // symbol: "SPOT_BTC_USDT", // side: "SELL", // executed_price: 46222.35, // executed_quantity: 0.0012, // executed_timestamp: "1641241162.329" // }, // { // symbol: "SPOT_BTC_USDT", // side: "SELL", // executed_price: 46222.35, // executed_quantity: 0.0012, // executed_timestamp: "1641241162.329" // }, // { // symbol: "SPOT_BTC_USDT", // side: "BUY", // executed_price: 46224.32, // executed_quantity: 0.00039, // executed_timestamp: "1641241162.287" // }, // ... // ] // } // const resultResponse = this.safeValue(response, 'rows', {}); return this.parseTrades(resultResponse, market, since, limit); } parseTrade(trade, market = undefined) { // // public/market_trades // // { // symbol: "SPOT_BTC_USDT", // side: "SELL", // executed_price: 46222.35, // executed_quantity: 0.0012, // executed_timestamp: "1641241162.329" // } // // fetchOrderTrades, fetchOrder // // { // id: '99119876', // symbol: 'SPOT_WOO_USDT', // fee: '0.0024', // side: 'BUY', // executed_timestamp: '1641481113.084', // order_id: '87001234', // order_tag: 'default', <-- this param only in "fetchOrderTrades" // executed_price: '1', // executed_quantity: '12', // fee_asset: 'WOO', // is_maker: '1' // } // const isFromFetchOrder = ('id' in trade); const timestamp = this.safeTimestamp(trade, 'executed_timestamp'); const marketId = this.safeString(trade, 'symbol'); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const price = this.safeString(trade, 'executed_price'); const amount = this.safeString(trade, 'executed_quantity'); const order_id = this.safeString(trade, 'order_id'); const fee = this.parseTokenAndFeeTemp(trade, 'fee_asset', 'fee'); const cost = Precise["default"].stringMul(price, amount); const side = this.safeStringLower(trade, 'side'); const id = this.safeString(trade, 'id'); let takerOrMaker = undefined; if (isFromFetchOrder) { const isMaker = this.safeString(trade, 'is_maker') === '1'; takerOrMaker = isMaker ? 'maker' : 'taker'; } return this.safeTrade({ 'id': id, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': symbol, 'side': side, 'price': price, 'amount': amount, 'cost': cost, 'order': order_id, 'takerOrMaker': takerOrMaker, 'type': undefined, 'fee': fee, 'info': trade, }, market); } parseTokenAndFeeTemp(item, feeTokenKey, feeAmountKey) { const feeCost = this.safeString(item, feeAmountKey); let fee = undefined; if (feeCost !== undefined) { const feeCurrencyId = this.safeString(item, feeTokenKey); const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId); fee = { 'cost': feeCost, 'currency': feeCurrencyCode, }; } return fee; } async fetchTradingFees(params = {}) { /** * @method * @name woo#fetchTradingFees * @description fetch the trading fees for multiple markets * @see https://docs.woo.org/#get-account-information-new * @param {object} params extra parameters specific to the woo api endpoint * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols */ await this.loadMarkets(); const response = await this.v3PrivateGetAccountinfo(params); // // { // "success": true, // "data": { // "applicationId": "dsa", // "account": "dsa", // "alias": "haha", // "accountMode": "MARGIN", // "leverage": 1, // "takerFeeRate": 1, // "makerFeeRate": 1, // "interestRate": 1, // "futuresTakerFeeRate": 1, // "futuresMakerFeeRate": 1, // "otpauth": true, // "marginRatio": 1, // "openMarginRatio": 1, // "initialMarginRatio": 1, // "maintenanceMarginRatio": 1, // "totalCollateral": 1, // "freeCollateral": 1, // "totalAccountValue": 1, // "totalVaultValue": 1, // "totalStakingValue": 1 // }, // "timestamp": 1673323685109 // } // const data = this.safeValue(response, 'data', {}); const maker = this.safeString(data, 'makerFeeRate'); const taker = this.safeString(data, 'takerFeeRate'); const result = {}; for (let i = 0; i < this.symbols.length; i++) { const symbol = this.symbols[i]; result[symbol] = { 'info': response, 'symbol': symbol, 'maker': this.parseNumber(Precise["default"].stringDiv(maker, '10000')), 'taker': this.parseNumber(Precise["default"].stringDiv(taker, '10000')), 'percentage': true, 'tierBased': true, }; } return result; } async fetchCurrencies(params = {}) { /** * @method * @name woo#fetchCurrencies * @description fetches all available currencies on an exchange * @param {object} params extra parameters specific to the woo api endpoint * @returns {object} an associative dictionary of currencies */ const result = {}; const tokenResponse = await this.v1PublicGetToken(params); // // { // rows: [ // { // token: "ETH_USDT", // fullname: "Tether", // decimals: 6, // balance_token: "USDT", // created_time: "0", // updated_time: "0" // }, // { // token: "BSC_USDT", // fullname: "Tether", // decimals: 18, // balance_token: "USDT", // created_time: "0", // updated_time: "0" // }, // { // token: "ZEC", // fullname: "ZCash", // decimals: 8, // balance_token: "ZEC", // created_time: "0", // updated_time: "0" // }, // ... // ], // success: true // } // // only make one request for currrencies... // const tokenNetworkResponse = await this.v1PublicGetTokenNetwork (params); // // { // rows: [ // { // protocol: "ERC20", // token: "USDT", // name: "Ethereum", // minimum_withdrawal: 30, // withdrawal_fee: 25, // allow_deposit: 1, // allow_withdraw: 1 // }, // { // protocol: "TRC20", // token: "USDT", // name: "Tron", // minimum_withdrawal: 30, // withdrawal_fee: 1, // allow_deposit: 1, // allow_withdraw: 1 // }, // ... // ], // success: true // } // const tokenRows = this.safeValue(tokenResponse, 'rows', []); const networksByCurrencyId = this.groupBy(tokenRows, 'balance_token'); const currencyIds = Object.keys(networksByCurrencyId); for (let i = 0; i < currencyIds.length; i++) { const currencyId = currencyIds[i]; const networks = networksByCurrencyId[currencyId]; const code = this.safeCurrencyCode(currencyId); let name = undefined; let minPrecision = undefined; const resultingNetworks = {}; for (let j = 0; j < networks.length; j++) { const network = networks[j]; name = this.safeString(network, 'fullname'); const networkId = this.safeString(network, 'token'); const splitted = networkId.split('_'); const unifiedNetwork = splitted[0]; const precision = this.parsePrecision(this.safeString(network, 'decimals')); if (precision !== undefined) { minPrecision = (minPrecision === undefined) ? precision : Precise["default"].stringMin(precision, minPrecision); } resultingNetworks[unifiedNetwork] = { 'id': networkId, 'network': unifiedNetwork, 'limits': { 'withdraw': { 'min': undefined, 'max': undefined, }, 'deposit': { 'min': undefined, 'max': undefined, }, }, 'active': undefined, 'deposit': undefined, 'withdraw': undefined, 'fee': undefined, 'precision': this.parseNumber(precision), 'info': network, }; } result[code] = { 'id': currencyId, 'name': name, 'code': code, 'precision': this.parseNumber(minPrecision), 'active': undefined, 'fee': undefined, 'networks': resultingNetworks, 'deposit': undefined, 'withdraw': undefined, 'limits': { 'deposit': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': undefined, 'max': undefined, }, }, 'info': networks, }; } return result; } async createOrder(symbol, type, side, amount, price = undefined, params = {}) { /** * @method * @name woo#createOrder * @description create a trade order * @param {string} symbol unified symbol of the market to create an order in * @param {string} type 'market' or 'limit' * @param {string} side 'buy' or 'sell' * @param {float} amount how much of currency you want to trade in units of base currency * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders * @param {object} params extra parameters specific to the woo api endpoint * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ const reduceOnly = this.safeValue(params, 'reduceOnly'); const orderType = type.toUpperCase(); if (reduceOnly !== undefined) { if (orderType !== 'LIMIT') { throw new errors.InvalidOrder(this.id + ' createOrder() only support reduceOnly for limit orders'); } } await this.loadMarkets(); const market = this.market(symbol); const orderSide = side.toUpperCase(); const request = { 'symbol': market['id'], 'order_type': orderType, 'side': orderSide, }; const isMarket = orderType === 'MARKET'; const timeInForce = this.safeStringLower(params, 'timeInForce'); const postOnly = this.isPostOnly(isMarket, undefined, params); if (postOnly) { request['order_type'] = 'POST_ONLY'; } else if (timeInForce === 'fok') { request['order_type'] = 'FOK'; } else if (timeInForce === 'ioc') { request['order_type'] = 'IOC'; } if (reduceOnly) { request['reduce_only'] = reduceOnly; } if (price !== undefined) { request['order_price'] = this.priceToPrecision(symbol, price); } if (isMarket) { // for market buy it requires the amount of quote currency to spend if (market['spot'] && orderSide === 'BUY') { const cost = this.safeNumber(params, 'cost'); if (this.safeValue(this.options, 'createMarketBuyOrderRequiresPrice', true)) { if (cost === undefined) { if (price === undefined) { throw new errors.InvalidOrder(this.id + " createOrder() requires the price argument for market buy orders to calculate total order cost. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or alternatively, supply the total cost value in the 'order_amount' in exchange-specific parameters"); } else { const amountString = this.numberToString(amount); const priceString = this.numberToString(price); const orderAmount = Precise["default"].stringMul(amountString, priceString); request['order_amount'] = this.costToPrecision(symbol, orderAmount); } } else { request['order_amount'] = this.costToPrecision(symbol, cost); } } else { request['order_amount'] = this.costToPrecision(symbol, amount); } } else { request['order_quantity'] = this.amountToPrecision(symbol, amount); } } else { request['order_quantity'] = this.amountToPrecision(symbol, amount); } const clientOrderId = this.safeString2(params, 'clOrdID', 'clientOrderId'); if (clientOrderId !== undefined) { request['client_order_id'] = clientOrderId; } params = this.omit(params, ['clOrdID', 'clientOrderId', 'postOnly', 'timeInForce']); const response = await this.v1PrivatePostOrder(this.extend(request, params)); // { // success: true, // timestamp: '1641383206.489', // order_id: '86980774', // order_type: 'LIMIT', // order_price: '1', // null for 'MARKET' order // order_quantity: '12', // null for 'MARKET' order // order_amount: null, // NOT-null for 'MARKET' order // client_order_id: '0' // } return this.extend(this.parseOrder(response, market), { 'type': type }); } async editOrder(id, symbol, type, side, amount, price = undefined, params = {}) { /** * @method * @name woo#editOrder * @description edit a trade order * @param {string} id order id * @param {string} symbol unified symbol of the market to create an order in * @param {string} type 'market' or 'limit' * @param {string} side 'buy' or 'sell' * @param {float} amount how much of currency you want to trade in units of base currency * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders * @param {object} params extra parameters specific to the woo api endpoint * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'oid': id, // 'quantity': this.amountToPrecision (symbol, amount), // 'price': this.priceToPrecision (symbol, price), }; if (price !== undefined) { request['price'] = this.priceToPrecision(symbol, price); } if (amount !== undefined) { request['quantity'] = this.amountToPrecision(symbol, amount); } const response = await this.v3PrivatePutOrderOid(this.extend(request, params)); // // { // "code": 0, // "data": { // "status": "string", // "success": true // }, // "message": "string", // "success": true, // "timestamp": 0 // } // const data = this.safeValue(response, 'data', {}); return this.parseOrder(data, market); } async cancelOrder(id, symbol = undefined, params = {}) { /** * @method * @name woo#cancelOrder * @description cancels an open order * @param {string} id order id * @param {string} symbol unified symbol of the market the order was made in * @param {object} params extra parameters specific to the woo api endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ if (symbol === undefined) { throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument'); } await this.loadMarkets(); const request = {}; const clientOrderIdUnified = this.safeString2(params, 'clOrdID', 'clientOrderId'); const clientOrderIdExchangeSpecific = this.safeString2(params, 'client_order_id', clientOrderIdUnified); const isByClientOrder = clientOrderIdExchangeSpecific !== undefined; if (isByClientOrder) { request['client_order_id'] = clientOrderIdExchangeSpecific; params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']); } else { request['order_id'] = id; } let market = undefined; if (symbol !== undefined) { market = this.market(symbol); } request['symbol'] = market['id']; const response = await this.v1PrivateDeleteOrder(this.extend(request, params)); // // { success: true, status: 'CANCEL_SENT' } // const extendParams = { 'symbol': symbol }; if (isByClientOrder) { extendParams['client_order_id'] = clientOrderIdExchangeSpecific; } else { extendParams['id'] = id; } return this.extend(this.parseOrder(response), extendParams); } async cancelAllOrders(symbol = undefined, params = {}) { /** * @method * @name woo#cancelAllOrders * @description cancel all open orders in a market * @param {string|undefined} symbol unified market symbol * @param {object} params extra parameters specific to the woo api endpoint * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ if (symbol === undefined) { throw new errors.ArgumentsRequired(this.id + ' canelOrders() requires a symbol argument'); } await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; const response = await this.v1PrivateDeleteOrders(this.extend(request, params)); // // { // "success":true, // "status":"CANCEL_ALL_SENT" // } // return response; } async fetchOrder(id, symbol = undefined, params = {}) { /** * @method * @name woo#fetchOrder * @description fetches information on an order made by the user * @param {string|undefined} symbol unified symbol of the market the order was made in * @param {object} params extra parameters specific to the woo api endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const market = (symbol !== undefined) ? this.market(symbol) : undefined; const request = {}; const clientOrderId = this.safeString2(params, 'clOrdID', 'clientOrderId'); let chosenSpotMethod = undefined; if (clientOrderId) { chosenSpotMethod = 'v1PrivateGetClientOrderClientOrderId'; request['client_order_id'] = clientOrderId; } else { chosenSpotMethod = 'v1PrivateGetOrderOid'; request['oid'] = id; } const response = await this[chosenSpotMethod](this.extend(request, params)); // // { // success: true, // symbol: 'SPOT_WOO_USDT', // status: 'FILLED', // FILLED, NEW // side: 'BUY', // created_time: '1641480933.000', // order_id: '87541111', // order_tag: 'default', // price: '1', // type: 'LIMIT', // quantity: '12', // amount: null, // visible: '12', // executed: '12', // or any partial amount // total_fee: '0.0024', // fee_asset: 'WOO', // client_order_id: null, // average_executed_price: '1', // Transactions: [ // { // id: '99111647', // symbol: 'SPOT_WOO_USDT', // fee: '0.0024', // side: 'BUY', // executed_timestamp: '1641482113.084', // order_id: '87541111', // executed_price: '1', // executed_quantity: '12', // fee_asset: 'WOO', // is_maker: '1' // } // ] // } // return this.parseOrder(response, market); } async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name woo#fetchOrders * @description fetches information on multiple orders made by the user * @param {string|undefined} symbol unified market symbol of the market orders were made in * @param {int|undefined} since the earliest time in ms to fetch orders for * @param {int|undefined} limit the maximum number of orde structures to retrieve * @param {object} params extra parameters specific to the woo api endpoint * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const request = {}; let market = undefined; if (symbol !== undefined) { market = this.market(symbol); request['symbol'] = market['id']; } if (since !== undefined) { request['start_t'] = since; } const response = await this.v1PrivateGetOrders(this.extend(request, params)); // // { // "success":true, // "meta":{ // "total":1, // "records_per_page":100, // "current_page":1 // }, // "rows":[ // { // "symbol":"PERP_BTC_USDT", // "status":"FILLED", // "side":"SELL", // "created_time":"1611617776.000", // "updated_time":"1611617776.000", // "order_id":52121167, // "order_tag":"default", // "price":null, // "type":"MARKET", // "quantity":0.002, // "amount":null, // "visible":0, // "executed":0.002, // "total_fee":0.01732885, // "fee_asset":"USDT", // "client_order_id":null, // "average_executed_price":28881.41 // } // ] // } // const data = this.safeValue(response, 'rows'); return this.parseOrders(data, market, since, limit, params); } parseTimeInForce(timeInForce) { const timeInForces = { 'ioc': 'IOC', 'fok': 'FOK', 'post_only': 'PO', }; return this.safeString(timeInForces, timeInForce, undefined); } parseOrder(order, market = undefined) { // // Possible input functions: // * createOrder // * cancelOrder // * fetchOrder // * fetchOrders // const isFromFetchOrder = ('order_tag' in order); TO_DO const timestamp = this.safeTimestamp2(order, 'timestamp', 'created_time'); const orderId = this.safeString(order, 'order_id'); const clientOrderId = this.safeString(order, 'client_order_id'); // Somehow, this always returns 0 for limit order const marketId = this.safeString(order, 'symbol'); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const price = this.safeString2(order, 'order_price', 'price'); const amount = this.safeString2(order, 'order_quantity', 'quantity'); // This is base amount const cost = this.safeString2(order, 'order_amount', 'amount'); // This is quote amount const orderType = this.safeStringLower2(order, 'order_type', 'type'); const status = this.safeValue(order, 'status'); const side = this.safeStringLower(order, 'side'); const filled = this.safeValue(order, 'executed'); const average = this.safeString(order, 'average_executed_price'); const remaining = Precise["default"].stringSub(cost, filled); const fee = this.safeValue(order, 'total_fee'); const feeCurrency = this.safeString(order, 'fee_asset'); const transactions = this.safeValue(order, 'Transactions'); return this.safeOrder({ 'id': orderId, 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'lastTradeTimestamp': undefined, 'status': this.parseOrderStatus(status), 'symbol': symbol, 'type': orderType, 'timeInForce': this.parseTimeInForce(orderType), 'postOnly': undefined, 'reduceOnly': this.safeValue(order, 'reduce_only'), 'side': side, 'price': price, 'stopPrice': undefined, 'triggerPrice': undefined, 'average': average, 'amount': amount, 'filled': filled, 'remaining': remaining, 'cost': cost, 'trades': transactions, 'fee': { 'cost': fee, 'currency': feeCurrency, }, 'info': order, }, market); } parseOrderStatus(status) { if (status !== undefined) { const statuses = { 'NEW': 'open', 'FILLED': 'closed', 'CANCEL_SENT': 'canceled', 'CANCEL_ALL_SENT': 'canceled', 'CANCELLED': 'canceled', 'PARTIAL_FILLED': 'open', 'REJECTED': 'rejected', 'INCOMPLETE': 'open', 'COMPLETED': 'closed', }; return this.safeString(statuses, status, status); } return status; } async fetchOrderBook(symbol, limit = undefined, params = {}) { /** * @method * @name woo#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @param {string} symbol unified symbol of the market to fetch the order book for * @param {int|undefined} limit the maximum amount of order book entries to return * @param {object} params extra parameters specific to the woo api endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { limit = Math.min(limit, 1000); request['max_level'] = limit; } const response = await this.v1PrivateGetOrderbookSymbol(this.extend(request, params)); // // { // success: true, // timestamp: '1641562961192', // asks: [ // { price: '0.921', quantity: '76.01' }, // { price: '0.933', quantity: '477.10' }, // ... // ], // bids: [ // { price: '0.940', quantity: '13502.47' }, // { price: '0.932', quantity: '43.91' }, // ... // ] // } // const timestamp = this.safeInteger(response, 'timestamp'); return this.parseOrderBook(response, symbol, timestamp, 'bids', 'asks', 'price', 'quantity'); } async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { /** * @method * @name woo#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @param {string} symbol unified symbol of the market to fetch OHLCV data for * @param {string} timeframe the length of time each candle represents * @param {int|undefined} since timestamp in ms of the earliest candle to fetch * @param {int|undefined} limit the maximum amount of candles to fetch * @param {object} params extra parameters specific to the woo api endpoint * @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], 'type': this.safeString(this.timeframes, timeframe, timeframe), }; if (limit !== undefined) { request['limit'] = Math.min(limit, 1000); } const response = await this.v1PrivateGetKline(this.extend(request, params)); // { // success: true, // rows: [ // { // open: '0.94238', // close: '0.94271', // low: '0.94238', // high: '0.94296', // volume: '73.55', // amount: '69.32040520', // symbol: 'SPOT_WOO_USDT', // type: '1m', // start_timestamp: '1641584700000', // end_timestamp: '1641584760000' // }, // { // open: '0.94186', // close: '0.94186', // low: '0.94186', // high: '0.94186', // volume: '64.00', // amount: '60.27904000', // symbol: 'SPOT_WOO_USDT', // type: '1m', // start_timestamp: '1641584640000', // end_timestamp: '1641584700000' // }, // ... /