UNPKG

@proton/ccxt

Version:

A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges

1,165 lines (1,162 loc) 110 kB
// ---------------------------------------------------------------------------- // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN: // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code // EDIT THE CORRESPONDENT .ts FILE INSTEAD // --------------------------------------------------------------------------- import Exchange from './abstract/woo.js'; import { ArgumentsRequired, AuthenticationError, RateLimitExceeded, BadRequest, ExchangeError, InvalidOrder } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { TICK_SIZE } from './base/functions/number.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; // --------------------------------------------------------------------------- export default class woo extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'woo', 'name': 'WOO X', 'countries': ['KY'], 'rateLimit': 100, 'version': 'v1', 'certified': true, '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, 'fetchDepositsWithdrawals': 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, 'orderbook/{symbol}': 1, 'kline': 1, }, }, 'private': { 'get': { 'client/token': 1, 'order/{oid}': 1, 'client/order/{client_order_id}': 1, 'orders': 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, 'client/transaction_history': 60, }, '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/{client_order_id}': 2, 'algo/order/{oid}': 2, 'algo/order/client/{client_order_id}': 2, }, 'delete': { 'algo/order/{order_id}': 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, }, 'brokerId': 'bc830de7-50f3-460b-9ee0-f430f83f9dad', }, 'commonCurrencies': {}, 'exceptions': { 'exact': { '-1000': ExchangeError, '-1001': AuthenticationError, '-1002': AuthenticationError, '-1003': RateLimitExceeded, '-1004': BadRequest, '-1005': BadRequest, '-1006': BadRequest, '-1007': BadRequest, '-1008': InvalidOrder, '-1009': BadRequest, '-1011': ExchangeError, '-1012': BadRequest, '-1101': InvalidOrder, '-1102': InvalidOrder, '-1103': InvalidOrder, '-1104': InvalidOrder, '-1105': InvalidOrder, // { "code": -1105, "message": "Price is X% too high or X% too low from the mid price." } }, 'broad': { 'symbol must not be blank': BadRequest, 'The token is not supported': BadRequest, 'Your order and symbol are not valid or already canceled': BadRequest, 'Insufficient WOO. Please enable margin trading for leverage trading': BadRequest, // when selling insufficent token [-1012] }, }, 'precisionMode': 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; let margin = true; const contract = isSwap; if (contract) { margin = false; 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': margin, 'swap': isSwap, 'future': false, 'option': false, 'active': undefined, 'contract': contract, '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 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.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.stringDiv(maker, '10000')), 'taker': this.parseNumber(Precise.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.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 * @see https://docs.woo.org/#send-order * @see https://docs.woo.org/#send-algo-order * @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 * @param {float} params.triggerPrice The price a trigger order is triggered at * @param {object|undefined} params.takeProfit *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered (perpetual swap markets only) * @param {float|undefined} params.takeProfit.triggerPrice take profit trigger price * @param {object|undefined} params.stopLoss *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered (perpetual swap markets only) * @param {float|undefined} params.stopLoss.triggerPrice stop loss trigger price * @param {float|undefined} params.algoType 'STOP'or 'TRAILING_STOP' or 'OCO' or 'CLOSE_POSITION' * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ const reduceOnly = this.safeValue2(params, 'reduceOnly', 'reduce_only'); const orderType = type.toUpperCase(); await this.loadMarkets(); const market = this.market(symbol); const orderSide = side.toUpperCase(); const request = { 'symbol': market['id'], 'side': orderSide, }; const stopPrice = this.safeNumber2(params, 'triggerPrice', 'stopPrice'); const stopLoss = this.safeValue(params, 'stopLoss'); const takeProfit = this.safeValue(params, 'takeProfit'); const algoType = this.safeString(params, 'algoType'); const isStop = stopPrice !== undefined || stopLoss !== undefined || takeProfit !== undefined || (this.safeValue(params, 'childOrders') !== undefined); const isMarket = orderType === 'MARKET'; const timeInForce = this.safeStringLower(params, 'timeInForce'); const postOnly = this.isPostOnly(isMarket, undefined, params); const reduceOnlyKey = isStop ? 'reduceOnly' : 'reduce_only'; const clientOrderIdKey = isStop ? 'clientOrderId' : 'client_order_id'; const orderQtyKey = isStop ? 'quantity' : 'order_quantity'; const priceKey = isStop ? 'price' : 'order_price'; const typeKey = isStop ? 'type' : 'order_type'; request[typeKey] = orderType; // LIMIT/MARKET/IOC/FOK/POST_ONLY/ASK/BID if (!isStop) { 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[reduceOnlyKey] = reduceOnly; } if (price !== undefined) { request[priceKey] = this.priceToPrecision(symbol, price); } if (isMarket && !isStop) { // 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 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.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 if (algoType !== 'POSITIONAL_TP_SL') { request[orderQtyKey] = this.amountToPrecision(symbol, amount); } const clientOrderId = this.safeStringN(params, ['clOrdID', 'clientOrderId', 'client_order_id']); if (clientOrderId !== undefined) { request[clientOrderIdKey] = clientOrderId; } if (stopPrice !== undefined) { if (algoType !== 'TRAILING_STOP') { request['triggerPrice'] = this.priceToPrecision(symbol, stopPrice); request['algoType'] = 'STOP'; } } else if ((stopLoss !== undefined) || (takeProfit !== undefined)) { request['algoType'] = 'BRACKET'; const outterOrder = { 'symbol': market['id'], 'reduceOnly': false, 'algoType': 'POSITIONAL_TP_SL', 'childOrders': [], }; const closeSide = (orderSide === 'BUY') ? 'SELL' : 'BUY'; if (stopLoss !== undefined) { const stopLossPrice = this.safeNumber2(stopLoss, 'triggerPrice', 'price', stopLoss); const stopLossOrder = { 'side': closeSide, 'algoType': 'STOP_LOSS', 'triggerPrice': this.priceToPrecision(symbol, stopLossPrice), 'type': 'CLOSE_POSITION', 'reduceOnly': true, }; outterOrder['childOrders'].push(stopLossOrder); } if (takeProfit !== undefined) { const takeProfitPrice = this.safeNumber2(takeProfit, 'triggerPrice', 'price', takeProfit); const takeProfitOrder = { 'side': closeSide, 'algoType': 'TAKE_PROFIT', 'triggerPrice': this.priceToPrecision(symbol, takeProfitPrice), 'type': 'CLOSE_POSITION', 'reduceOnly': true, }; outterOrder['childOrders'].push(takeProfitOrder); } request['childOrders'] = [outterOrder]; } params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id', 'postOnly', 'timeInForce', 'stopPrice', 'triggerPrice', 'stopLoss', 'takeProfit']); let response = undefined; if (isStop) { response = await this.v3PrivatePostAlgoOrder(this.extend(request, params)); } else { 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' // } // stop orders // { // success: true, // data: { // rows: [ // { // orderId: '1578938', // clientOrderId: '0', // algoType: 'STOP_LOSS', // quantity: '0.1' // } // ] // }, // timestamp: '1686149372216' // } const data = this.safeValue(response, 'data'); if (data !== undefined) { const rows = this.safeValue(data, 'rows', []); return this.parseOrder(rows[0], market); } return this.extend(this.parseOrder(response, market), { 'type': type }); } async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) { /** * @method * @name woo#editOrder * @see https://docs.woo.org/#edit-order * @see https://docs.woo.org/#edit-order-by-client_order_id * @see https://docs.woo.org/#edit-algo-order * @see https://docs.woo.org/#edit-algo-order-by-client_order_id * @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 * @param {float} params.triggerPrice The price a trigger order is triggered at * @param {float|undefined} params.stopLossPrice price to trigger stop-loss orders * @param {float|undefined} params.takeProfitPrice price to trigger take-profit orders * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const market = this.market(symbol); const request = { // '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 clientOrderIdUnified = this.safeString2(params, 'clOrdID', 'clientOrderId'); const clientOrderIdExchangeSpecific = this.safeString(params, 'client_order_id', clientOrderIdUnified); const isByClientOrder = clientOrderIdExchangeSpecific !== undefined; const stopPrice = this.safeNumberN(params, ['triggerPrice', 'stopPrice', 'takeProfitPrice', 'stopLossPrice']); if (stopPrice !== undefined) { request['triggerPrice'] = this.priceToPrecision(symbol, stopPrice); } const isStop = (stopPrice !== undefined) || (this.safeValue(params, 'childOrders') !== undefined); let method = undefined; if (isByClientOrder) { if (isStop) { method = 'v3PrivatePutAlgoOrderClientClientOrderId'; request['oid'] = id; } else { method = 'v3PrivatePutOrderClientClientOrderId'; request['client_order_id'] = clientOrderIdExchangeSpecific; } } else { if (isStop) { method = 'v3PrivatePutAlgoOrderOid'; } else { method = 'v3PrivatePutOrderOid'; } request['oid'] = id; } params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id', 'stopPrice', 'triggerPrice', 'takeProfitPrice', 'stopLossPrice']); const response = await this[method](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 * @see https://docs.woo.org/#cancel-algo-order * @see https://docs.woo.org/#cancel-order * @see https://docs.woo.org/#cancel-order-by-client_order_id * @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 * @param {boolean|undefined} params.stop whether the order is a stop/algo order * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ const stop = this.safeValue(params, 'stop', false); params = this.omit(params, 'stop'); if (!stop) { this.checkRequiredSymbol('cancelOrder', symbol); } await this.loadMarkets(); const request = {}; const clientOrderIdUnified = this.safeString2(params, 'clOrdID', 'clientOrderId'); const clientOrderIdExchangeSpecific = this.safeString(params, 'client_order_id', clientOrderIdUnified); const isByClientOrder = clientOrderIdExchangeSpecific !== undefined; let method = undefined; if (stop) { method = 'v3PrivateDeleteAlgoOrderOrderId'; request['order_id'] = id; } else if (isByClientOrder) { method = 'v1PrivateDeleteClientOrder'; request['client_order_id'] = clientOrderIdExchangeSpecific; params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']); } else { method = 'v1PrivateDeleteOrder'; request['order_id'] = id; } let market = undefined; if (symbol !== undefined) { market = this.market(symbol); } if (!stop) { request['symbol'] = market['id']; } const response = await this[method](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 * @see https://docs.woo.org/#cancel-all-pending-orders * @see https://docs.woo.org/#cancel-orders * @see https://docs.woo.org/#cancel-all-pending-algo-orders * @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 * @param {boolean|undefined} params.stop whether the order is a stop/algo order * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const stop = this.safeValue(params, 'stop'); params = this.omit(params, 'stop'); if (stop) { return await this.v3PrivateDeleteAlgoOrdersPending(params); } this.checkRequiredSymbol('cancelOrders', symbol); 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 * @see https://docs.woo.org/#get-algo-order * @see https://docs.woo.org/#get-order * @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 * @param {boolean|undefined} params.stop whether the order is a stop/algo order * @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 stop = this.safeValue(params, 'stop'); params = this.omit(params, 'stop'); const request = {}; const clientOrderId = this.safeString2(params, 'clOrdID', 'clientOrderId'); let method = undefined; if (stop) { method = 'v3PrivateGetAlgoOrderOid'; request['oid'] = id; } else if (clientOrderId) { method = 'v1PrivateGetClientOrderClientOrderId'; request['client_order_id'] = clientOrderId; } else { method = 'v1PrivateGetOrderOid'; request['oid'] = id; } const response = await this[method](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' // } // ] // } // const orders = this.safeValue(response, 'data', response); return this.parseOrder(orders, market); } async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name woo#fetchOrders * @see https://docs.woo.org/#get-orders * @see https://docs.woo.org/#get-algo-orders * @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 * @param {boolean|undefined} params.stop whether the order is a stop/algo order * @param {boolean|undefined} params.isTriggered whether the order has been triggered (false by default) * @param {string|undefined} params.side 'buy' or 'sell' * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const request = {}; let market = undefined; const stop = this.safeValue(params, 'stop'); params = this.omit(params, 'stop'); if (symbol !== undefined) { market = this.market(symbol); request['symbol'] = market['id']; } if (since !== undefined) { if (stop) { request['createdTimeStart'] = since; } else {