@jalmonter/ccxt
Version:
1,160 lines (1,158 loc) • 115 kB
JavaScript
'use strict';
var woo$1 = require('./abstract/woo.js');
var errors = require('./base/errors.js');
var Precise = require('./base/Precise.js');
var number = require('./base/functions/number.js');
var sha256 = require('./static_dependencies/noble-hashes/sha256.js');
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
/**
* @class woo
* @augments Exchange
*/
class woo extends woo$1 {
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,
'cancelAllOrders': true,
'cancelOrder': true,
'cancelWithdraw': false,
'closeAllPositions': false,
'closePosition': false,
'createDepositAddress': false,
'createMarketBuyOrderWithCost': true,
'createMarketOrder': false,
'createMarketOrderWithCost': false,
'createMarketSellOrderWithCost': 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': 'emulated',
'fetchTransfers': true,
'fetchWithdrawals': true,
'reduceMargin': false,
'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': {
'url': 'https://x.woo.org/register?ref=YWOWC96B',
'discount': 0.35,
},
},
'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,
'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': {
'public': {
'get': {
'insuranceFund': 3,
},
},
'private': {
'get': {
'algo/order/{oid}': 1,
'algo/orders': 1,
'balances': 1,
'accountinfo': 60,
'positions': 3.33,
'buypower': 1,
'referrals': 60,
'referral_rewards': 60,
'convert/exchangeInfo': 1,
'convert/assetInfo': 1,
'convert/rfq': 60,
'convert/trade': 1,
'convert/trades': 1,
},
'post': {
'algo/order': 5,
'convert/rft': 60,
},
'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': {
'sandboxMode': false,
'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': 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 data = this.safeValue(response, 'rows', []);
return this.parseMarkets(data);
}
parseMarket(market) {
const marketId = this.safeString(market, 'symbol');
const parts = marketId.split('_');
const first = this.safeString(parts, 0);
let marketType;
let spot = false;
let swap = false;
if (first === 'SPOT') {
spot = true;
marketType = 'spot';
}
else if (first === 'PERP') {
swap = true;
marketType = 'swap';
}
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 = swap;
if (contract) {
margin = false;
settleId = this.safeString(parts, 2);
settle = this.safeCurrencyCode(settleId);
symbol = base + '/' + quote + ':' + settle;
contractSize = this.parseNumber('1');
linear = true;
}
return {
'id': marketId,
'symbol': symbol,
'base': base,
'quote': quote,
'settle': settle,
'baseId': baseId,
'quoteId': quoteId,
'settleId': settleId,
'type': marketType,
'spot': spot,
'margin': margin,
'swap': swap,
'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,
},
},
'created': this.safeTimestamp(market, 'created_time'),
'info': market,
};
}
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} [since] timestamp in ms of the earliest trade to fetch
* @param {int} [limit] the maximum amount of trades to fetch
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
*/
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 exchange 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 exchange 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 createMarketBuyOrderWithCost(symbol, cost, params = {}) {
/**
* @method
* @name woo#createMarketBuyOrderWithCost
* @description create a market buy order by providing the symbol and cost
* @see https://docs.woo.org/#send-order
* @param {string} symbol unified symbol of the market to create an order in
* @param {float} cost how much you want to trade in units of the quote currency
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
await this.loadMarkets();
const market = this.market(symbol);
if (!market['spot']) {
throw new errors.NotSupported(this.id + ' createMarketBuyOrderWithCost() supports spot orders only');
}
params['createMarketBuyOrderRequiresPrice'] = false;
return await this.createOrder(symbol, 'market', 'buy', cost, undefined, params);
}
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} [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 exchange API endpoint
* @param {float} [params.triggerPrice] The price a trigger order is triggered at
* @param {object} [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} [params.takeProfit.triggerPrice] take profit trigger price
* @param {object} [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} [params.stopLoss.triggerPrice] stop loss trigger price
* @param {float} [params.algoType] 'STOP'or 'TRAILING_STOP' or 'OCO' or 'CLOSE_POSITION'
* @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
const reduceOnly = this.safeValue2(params, 'reduceOnly', 'reduce_only');
params = this.omit(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') {
let quoteAmount = undefined;
let createMarketBuyOrderRequiresPrice = true;
[createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
const cost = this.safeNumber2(params, 'cost', 'order_amount');
params = this.omit(params, ['cost', 'order_amount']);
if (cost !== undefined) {
quoteAmount = this.costToPrecision(symbol, cost);
}
else if (createMarketBuyOrderRequiresPrice) {
if (price === undefined) {
throw new errors.InvalidOrder(this.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to false and pass the cost to spend (quote quantity) in the amount argument');
}
else {
const amountString = this.numberToString(amount);
const priceString = this.numberToString(price);
const costRequest = Precise["default"].stringMul(amountString, priceString);
quoteAmount = this.costToPrecision(symbol, costRequest);
}
}
else {
quoteAmount = this.costToPrecision(symbol, amount);
}
request['order_amount'] = quoteAmount;
}
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);
}
const order = this.parseOrder(response, market);
order['type'] = type;
return order;
}
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} [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 exchange API endpoint
* @param {float} [params.triggerPrice] The price a trigger order is triggered at
* @param {float} [params.stopLossPrice] price to trigger stop-loss orders
* @param {float} [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);
}
params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id', 'stopPrice', 'triggerPrice', 'takeProfitPrice', 'stopLossPrice']);
const isStop = (stopPrice !== undefined) || (this.safeValue(params, 'childOrders') !== undefined);
let response = undefined;
if (isByClientOrder) {
request['client_order_id'] = clientOrderIdExchangeSpecific;
if (isStop) {
response = await this.v3PrivatePutAlgoOrderClientClientOrderId(this.extend(request, params));
}
else {
response = await this.v3PrivatePutOrderClientClientOrderId(this.extend(request, params));
}
}
else {
request['oid'] = id;
if (isStop) {
response = await this.v3PrivatePutAlgoOrderOid(this.extend(request, params));
}
else {
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
* @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 exchange API endpoint
* @param {boolean} [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 && (symbol === undefined)) {
throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
}
await this.loadMarkets();
let market = undefined;
if (symbol !== undefined) {
market = this.market(symbol);
}
const request = {};
const clientOrderIdUnified = this.safeString2(params, 'clOrdID', 'clientOrderId');
const clientOrderIdExchangeSpecific = this.safeString(params, 'client_order_id', clientOrderIdUnified);
const isByClientOrder = clientOrderIdExchangeSpecific !== undefined;
let response = undefined;
if (stop) {
request['order_id'] = id;
response = await this.v3PrivateDeleteAlgoOrderOrderId(this.extend(request, params));
}
else {
request['symbol'] = market['id'];
if (isByClientOrder) {
request['client_order_id'] = clientOrderIdExchangeSpecific;
params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
response = await this.v1PrivateDeleteClientOrder(this.extend(request, params));
}
else {
request['order_id'] = id;
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
* @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} symbol unified market symbol
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {boolean} [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);
}
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' cancelOrders() requires a symbol argument');
}
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} symbol unified symbol of the market the order was made in
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {boolean} [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 response = undefined;
if (stop) {
request['oid'] = id;
response = await this.v3PrivateGetAlgoOrderOid(this.extend(request, params));
}
else if (clientOrderId) {
request['client_order_id'] = clientOrderId;
response = await this.v1PrivateGetClientOrderClientOrderId(this.extend(request, params));
}
else {
request['oid'] = id;
response = await this.v1PrivateGetOrderOid(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