@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
JavaScript
// ----------------------------------------------------------------------------
// 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 {