remsed
Version:
A JavaScript cryptocurrency trading library with support for fairdesk.com
1,203 lines (1,201 loc) • 97.8 kB
JavaScript
'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'
// },
// ...
/