sfccxt
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges
1,200 lines (1,173 loc) • 81.4 kB
JavaScript
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ArgumentsRequired, ExchangeError, ExchangeNotAvailable, RequestTimeout, AuthenticationError, PermissionDenied, RateLimitExceeded, InsufficientFunds, OrderNotFound, InvalidOrder, AccountSuspended, CancelPending, InvalidNonce, OnMaintenance, BadSymbol } = require ('./base/errors');
const { TICK_SIZE } = require ('./base/functions/number');
const Precise = require ('./base/Precise');
// ---------------------------------------------------------------------------
module.exports = class poloniex extends Exchange {
describe () {
return this.deepExtend (super.describe (), {
'id': 'poloniex',
'name': 'Poloniex',
'countries': [ 'US' ],
// 200 requests per second for some unauthenticated market endpoints => 1000ms / 200 = 5ms between requests
'rateLimit': 5,
'certified': false,
'pro': false,
'has': {
'CORS': undefined,
'spot': true,
'margin': undefined, // has but not fully implemented
'swap': undefined, // has but not fully implemented
'future': undefined, // has but not fully implemented
'option': undefined,
'cancelAllOrders': true,
'cancelOrder': true,
'createDepositAddress': true,
'createMarketOrder': undefined,
'createOrder': true,
'editOrder': false,
'fetchBalance': true,
'fetchClosedOrder': false,
'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
'fetchMarginMode': false,
'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenInterestHistory': false,
'fetchOpenOrder': false,
'fetchOpenOrders': true, // true endpoint for open orders
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrderBooks': false,
'fetchOrderTrades': true, // true endpoint for trades of a single open or closed order
'fetchPosition': false,
'fetchPositionMode': false,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingFee': false,
'fetchTradingFees': true,
'fetchTransactions': true,
'fetchTransfer': false,
'fetchTransfers': false,
'fetchWithdrawals': true,
'transfer': true,
'withdraw': true,
},
'timeframes': {
'1m': 'MINUTE_1',
'5m': 'MINUTE_5',
'10m': 'MINUTE_10',
'15m': 'MINUTE_15',
'30m': 'MINUTE_30',
'1h': 'HOUR_1',
'2h': 'HOUR_2',
'4h': 'HOUR_4',
'6h': 'HOUR_6',
'12h': 'HOUR_12',
'1d': 'DAY_1',
'3d': 'DAY_3',
'1w': 'WEEK_1',
'1M': 'MONTH_1',
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27766817-e9456312-5ee6-11e7-9b3c-b628ca5626a5.jpg',
'api': 'https://api.poloniex.com',
'test': 'https://sand-spot-api-gateway.poloniex.com',
'www': 'https://www.poloniex.com',
'doc': 'https://docs.poloniex.com',
'fees': 'https://poloniex.com/fees',
'referral': 'https://poloniex.com/signup?c=UBFZJRPJ',
},
'api': {
'public': {
'get': {
'markets': 20,
'markets/{symbol}': 1,
'currencies': 20,
'currencies/{currency}': 20,
'timestamp': 1,
'markets/price': 1,
'markets/{symbol}/price': 1,
'markets/{symbol}/orderBook': 1,
'markets/{symbol}/candles': 1,
'markets/{symbol}/trades': 20,
'markets/ticker24h': 20,
'markets/{symbol}/ticker24h': 20,
},
},
'private': {
'get': {
'accounts': 4,
'accounts/activity': 4,
'accounts/balances': 4,
'accounts/{id}/balances': 4,
'accounts/transfer': 20,
'accounts/transfer/{id}': 4,
'feeinfo': 20,
'wallets/addresses': 20,
'wallets/activity': 20,
'wallets/addresses/{currency}': 20,
'orders': 20,
'orders/{id}': 4,
'orders/history': 20,
'orders/killSwitchStatus': 4,
'smartorders': 20,
'smartorders/{id}': 4,
'smartorders/history': 20,
'trades': 20,
'orders/{id}/trades': 4,
},
'post': {
'accounts/transfer': 4,
'wallets/address': 20,
'wallets/withdraw': 20,
'orders': 4,
'orders/killSwitch': 4,
'orders/batch': 20,
'smartorders': 4,
},
'delete': {
'orders/{id}': 4,
'orders/cancelByIds': 20,
'orders': 20,
'smartorders/{id}': 4,
'smartorders/cancelByIds': 20,
'smartorders': 20,
},
},
},
'fees': {
'trading': {
'feeSide': 'get',
// starting from Jan 8 2020
'maker': this.parseNumber ('0.0009'),
'taker': this.parseNumber ('0.0009'),
},
'funding': {},
},
'commonCurrencies': {
'AIR': 'AirCoin',
'APH': 'AphroditeCoin',
'BCC': 'BTCtalkcoin',
'BCHABC': 'BCHABC',
'BDG': 'Badgercoin',
'BTM': 'Bitmark',
'CON': 'Coino',
'GOLD': 'GoldEagles',
'GPUC': 'GPU',
'HOT': 'Hotcoin',
'ITC': 'Information Coin',
'KEY': 'KEYCoin',
'MASK': 'NFTX Hashmasks Index', // conflict with Mask Network
'MEME': 'Degenerator Meme', // Degenerator Meme migrated to Meme Inu, this exchange still has the old price
'PLX': 'ParallaxCoin',
'REPV2': 'REP',
'STR': 'XLM',
'SOC': 'SOCC',
'TRADE': 'Unitrade',
'XAP': 'API Coin',
// this is not documented in the API docs for Poloniex
// https://github.com/ccxt/ccxt/issues/7084
// when the user calls withdraw ('USDT', amount, address, tag, params)
// with params = { 'currencyToWithdrawAs': 'USDTTRON' }
// or params = { 'currencyToWithdrawAs': 'USDTETH' }
// fetchWithdrawals ('USDT') returns the corresponding withdrawals
// with a USDTTRON or a USDTETH currency id, respectfully
// therefore we have map them back to the original code USDT
// otherwise the returned withdrawals are filtered out
'USDTTRON': 'USDT',
'USDTETH': 'USDT',
'UST': 'USTC',
},
'options': {
'networks': {
'BEP20': 'BSC',
'ERC20': 'ETH',
'TRX': 'TRON',
'TRC20': 'TRON',
},
'limits': {
'cost': {
'min': {
'BTC': 0.0001,
'ETH': 0.0001,
'USDT': 1.0,
'TRX': 100,
'BNB': 0.06,
'USDC': 1.0,
'USDJ': 1.0,
'TUSD': 0.0001,
'DAI': 1.0,
'PAX': 1.0,
'BUSD': 1.0,
},
},
},
'accountsByType': {
'spot': 'spot',
'future': 'futures',
},
'accountsById': {
'exchange': 'spot',
'futures': 'future',
},
},
'precisionMode': TICK_SIZE,
'exceptions': {
'exact': {
'You may only place orders that reduce your position.': InvalidOrder,
'Invalid order number, or you are not the person who placed the order.': OrderNotFound,
'Permission denied': PermissionDenied,
'Permission denied.': PermissionDenied,
'Connection timed out. Please try again.': RequestTimeout,
'Internal error. Please try again.': ExchangeNotAvailable,
'Currently in maintenance mode.': OnMaintenance,
'Order not found, or you are not the person who placed it.': OrderNotFound,
'Invalid API key/secret pair.': AuthenticationError,
'Please do not make more than 8 API calls per second.': RateLimitExceeded,
'This IP has been temporarily throttled. Please ensure your requests are valid and try again in one minute.': RateLimitExceeded,
'Rate must be greater than zero.': InvalidOrder, // {"error":"Rate must be greater than zero."}
'Invalid currency pair.': BadSymbol, // {"error":"Invalid currency pair."}
'Invalid currencyPair parameter.': BadSymbol, // {"error":"Invalid currencyPair parameter."}
'Trading is disabled in this market.': BadSymbol, // {"error":"Trading is disabled in this market."}
'Invalid orderNumber parameter.': OrderNotFound,
'Order is beyond acceptable bounds.': InvalidOrder, // {"error":"Order is beyond acceptable bounds.","fee":"0.00155000","currencyPair":"USDT_BOBA"}
'This account is closed.': AccountSuspended, // {"error":"This account is closed."}
},
'broad': {
'Total must be at least': InvalidOrder, // {"error":"Total must be at least 0.0001."}
'This account is frozen': AccountSuspended, // {"error":"This account is frozen for trading."} || {"error":"This account is frozen."}
'This account is locked.': AccountSuspended, // {"error":"This account is locked."}
'Not enough': InsufficientFunds,
'Nonce must be greater': InvalidNonce,
'You have already called cancelOrder': CancelPending, // {"error":"You have already called cancelOrder, moveOrder, or cancelReplace on this order. Please wait for that call's response."}
'Amount must be at least': InvalidOrder, // {"error":"Amount must be at least 0.000001."}
'is either completed or does not exist': OrderNotFound, // {"error":"Order 587957810791 is either completed or does not exist."}
'Error pulling ': ExchangeError, // {"error":"Error pulling order book"}
},
},
});
}
parseOHLCV (ohlcv, market = undefined) {
//
// [
// [
// "22814.01",
// "22937.42",
// "22832.57",
// "22937.42",
// "3916.58764051",
// "0.171199",
// "2982.64647063",
// "0.130295",
// 33,
// 0,
// "22877.449915304470460711",
// "MINUTE_5",
// 1659664800000,
// 1659665099999
// ]
// ]
//
return [
this.safeInteger (ohlcv, 12),
this.safeNumber (ohlcv, 2),
this.safeNumber (ohlcv, 1),
this.safeNumber (ohlcv, 0),
this.safeNumber (ohlcv, 3),
this.safeNumber (ohlcv, 5),
];
}
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name poloniex#fetchOHLCV
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
* @param {string} timeframe the length of time each candle represents
* @param {int|undefined} since timestamp in ms of the earliest candle to fetch
* @param {int|undefined} limit the maximum amount of candles to fetch
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume
*/
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
'interval': this.timeframes[timeframe],
};
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
// limit should in between 100 and 500
request['limit'] = limit;
}
const response = await this.publicGetMarketsSymbolCandles (this.extend (request, params));
//
// [
// [
// "22814.01",
// "22937.42",
// "22832.57",
// "22937.42",
// "3916.58764051",
// "0.171199",
// "2982.64647063",
// "0.130295",
// 33,
// 0,
// "22877.449915304470460711",
// "MINUTE_5",
// 1659664800000,
// 1659665099999
// ]
// ]
//
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
async loadMarkets (reload = false, params = {}) {
const markets = await super.loadMarkets (reload, params);
const currenciesByNumericId = this.safeValue (this.options, 'currenciesByNumericId');
if ((currenciesByNumericId === undefined) || reload) {
this.options['currenciesByNumericId'] = this.indexBy (this.currencies, 'numericId');
}
return markets;
}
async fetchMarkets (params = {}) {
/**
* @method
* @name poloniex#fetchMarkets
* @description retrieves data on all markets for poloniex
* @param {object} params extra parameters specific to the exchange api endpoint
* @returns {[object]} an array of objects representing market data
*/
const markets = await this.publicGetMarkets (params);
//
// [
// {
// "symbol" : "BTS_BTC",
// "baseCurrencyName" : "BTS",
// "quoteCurrencyName" : "BTC",
// "displayName" : "BTS/BTC",
// "state" : "NORMAL",
// "visibleStartTime" : 1659018816626,
// "tradableStartTime" : 1659018816626,
// "symbolTradeLimit" : {
// "symbol" : "BTS_BTC",
// "priceScale" : 10,
// "quantityScale" : 0,
// "amountScale" : 8,
// "minQuantity" : "100",
// "minAmount" : "0.00001",
// "highestBid" : "0",
// "lowestAsk" : "0"
// }
// }
// ]
//
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = this.safeValue (markets, i);
const id = this.safeString (market, 'symbol');
const baseId = this.safeString (market, 'baseCurrencyName');
const quoteId = this.safeString (market, 'quoteCurrencyName');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const state = this.safeString (market, 'state');
const active = state === 'NORMAL';
const symbolTradeLimit = this.safeValue (market, 'symbolTradeLimit');
// these are known defaults
result.push ({
'id': id,
'symbol': base + '/' + quote,
'base': base,
'quote': quote,
'settle': undefined,
'baseId': baseId,
'quoteId': quoteId,
'settleId': undefined,
'type': 'spot',
'spot': true,
'margin': false,
'swap': false,
'future': false,
'option': false,
'active': active,
'contract': false,
'linear': undefined,
'inverse': undefined,
'contractSize': undefined,
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': this.parseNumber (this.parsePrecision (this.safeString (symbolTradeLimit, 'quantityScale'))),
'price': this.parseNumber (this.parsePrecision (this.safeString (symbolTradeLimit, 'priceScale'))),
},
'limits': {
'amount': {
'min': this.safeNumber (symbolTradeLimit, 'minQuantity'),
'max': undefined,
},
'price': {
'min': undefined,
'max': undefined,
},
'cost': {
'min': this.safeNumber (symbolTradeLimit, 'minAmount'),
'max': undefined,
},
},
'info': market,
});
}
return result;
}
async fetchTime (params = {}) {
/**
* @method
* @name poloniex#fetchTime
* @description fetches the current integer timestamp in milliseconds from the exchange server
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {int} the current integer timestamp in milliseconds from the exchange server
*/
const response = await this.publicGetTimestamp (params);
return this.safeInteger (response, 'serverTime');
}
parseTicker (ticker, market = undefined) {
//
// {
// "symbol" : "BTC_USDT",
// "open" : "22814.93",
// "low" : "22441.90",
// "high" : "23413.00",
// "close" : "23148.66",
// "quantity" : "71.743706",
// "amount" : "1638994.52683452",
// "tradeCount" : 3893,
// "startTime" : 1659605760000,
// "closeTime" : 1659692161077,
// "displayName" : "BTC/USDT",
// "dailyChange" : "0.0152",
// "ts" : 1659692169838
// }
//
const timestamp = this.safeInteger (ticker, 'ts');
const marketId = this.safeString (ticker, 'symbol');
market = this.safeMarket (marketId);
const close = this.safeString (ticker, 'close');
const relativeChange = this.safeString (ticker, 'percentChange');
const percentage = Precise.stringMul (relativeChange, '100');
return this.safeTicker ({
'id': marketId,
'symbol': market['symbol'],
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'high': this.safeString (ticker, 'high'),
'low': this.safeString (ticker, 'low'),
'bid': undefined,
'bidVolume': undefined,
'ask': undefined,
'askVolume': undefined,
'vwap': undefined,
'open': this.safeString (ticker, 'open'),
'close': close,
'last': close,
'previousClose': undefined,
'change': undefined,
'percentage': percentage,
'average': undefined,
'baseVolume': this.safeString (ticker, 'quantity'),
'quoteVolume': this.safeString (ticker, 'amount'),
'info': ticker,
}, market);
}
async fetchTickers (symbols = undefined, params = {}) {
/**
* @method
* @name poloniex#fetchTickers
* @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
* @param {[string]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
*/
await this.loadMarkets ();
symbols = this.marketSymbols (symbols);
const response = await this.publicGetMarketsTicker24h (params);
//
// [
// {
// "symbol" : "KUB_USDD",
// "open" : "0",
// "low" : "0",
// "high" : "0",
// "close" : "0",
// "quantity" : "0",
// "amount" : "0",
// "tradeCount" : 0,
// "startTime" : 1659606240000,
// "closeTime" : 1659692648742,
// "displayName" : "KUB/USDD",
// "dailyChange" : "0.00",
// "ts" : 1659692648742
// }
// ]
//
return this.parseTickers (response, symbols);
}
async fetchCurrencies (params = {}) {
/**
* @method
* @name poloniex#fetchCurrencies
* @description fetches all available currencies on an exchange
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {object} an associative dictionary of currencies
*/
const response = await this.publicGetCurrencies (params);
//
// [
// {
// "1CR": {
// "id": 1,
// "name": "1CRedit",
// "description": "BTC Clone",
// "type": "address",
// "withdrawalFee": "0.01000000",
// "minConf": 10000,
// "depositAddress": null,
// "blockchain": "1CR",
// "delisted": false,
// "tradingState": "NORMAL",
// "walletState": "DISABLED",
// "parentChain": null,
// "isMultiChain": false,
// "isChildChain": false,
// "childChains": []
// }
// }
// ]
//
const result = {};
for (let i = 0; i < response.length; i++) {
const item = this.safeValue (response, i);
const ids = Object.keys (item);
const id = this.safeValue (ids, 0);
const currency = this.safeValue (item, id);
const code = this.safeCurrencyCode (id);
const delisted = this.safeValue (currency, 'delisted');
const walletState = this.safeString (currency, 'walletState');
const enabled = walletState === 'ENABLED';
const listed = !delisted;
const active = listed && enabled;
const numericId = this.safeInteger (currency, 'id');
const fee = this.safeNumber (currency, 'withdrawalFee');
result[code] = {
'id': id,
'numericId': numericId,
'code': code,
'info': currency,
'name': currency['name'],
'active': active,
'deposit': undefined,
'withdraw': undefined,
'fee': fee,
'precision': undefined,
'limits': {
'amount': {
'min': undefined,
'max': undefined,
},
'withdraw': {
'min': fee,
'max': undefined,
},
},
};
}
return result;
}
async fetchTicker (symbol, params = {}) {
/**
* @method
* @name poloniex#fetchTicker
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
*/
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
const response = await this.publicGetMarketsSymbolTicker24h (this.extend (request, params));
//
// {
// "symbol" : "BTC_USDT",
// "open" : "22814.93",
// "low" : "22441.90",
// "high" : "23413.00",
// "close" : "23148.66",
// "quantity" : "71.743706",
// "amount" : "1638994.52683452",
// "tradeCount" : 3893,
// "startTime" : 1659605760000,
// "closeTime" : 1659692161077,
// "displayName" : "BTC/USDT",
// "dailyChange" : "0.0152",
// "ts" : 1659692169838
// }
//
return this.parseTicker (response, market);
}
parseTrade (trade, market = undefined) {
//
// fetchTrades
//
// {
// "id" : "60014521",
// "price" : "23162.94",
// "quantity" : "0.00009",
// "amount" : "2.0846646",
// "takerSide" : "SELL",
// "ts" : 1659684602042,
// "createTime" : 1659684602036
// }
//
// fetchMyTrades
//
// {
// "id": "32164924331503616",
// "symbol": "LINK_USDT",
// "accountType": "SPOT",
// "orderId": "32164923987566592",
// "side": "SELL",
// "type": "MARKET",
// "matchRole": "TAKER",
// "createTime": 1648635115525,
// "price": "11",
// "quantity": "0.5",
// "amount": "5.5",
// "feeCurrency": "USDT",
// "feeAmount": "0.007975",
// "pageId": "32164924331503616",
// "clientOrderId": "myOwnId-321"
// }
//
// fetchOrderTrades (taker trades)
//
// {
// "id": "30341456333942784",
// "symbol": "LINK_USDT",
// "accountType": "SPOT",
// "orderId": "30249408733945856",
// "side": "BUY",
// "type": "LIMIT",
// "matchRole": "MAKER",
// "createTime": 1648200366864,
// "price": "3.1",
// "quantity": "1",
// "amount": "3.1",
// "feeCurrency": "LINK",
// "feeAmount": "0.00145",
// "pageId": "30341456333942784",
// "clientOrderId": ""
// }
//
//
const id = this.safeString2 (trade, 'id', 'tradeID');
const orderId = this.safeString (trade, 'orderId');
const timestamp = this.safeInteger2 (trade, 'ts', 'createTime');
const marketId = this.safeString (trade, 'symbol');
market = this.safeMarket (marketId, market, '_');
const symbol = market['symbol'];
const side = this.safeStringLower (trade, 'side');
let fee = undefined;
const priceString = this.safeString (trade, 'price');
const amountString = this.safeString (trade, 'quantity');
const costString = this.safeString (trade, 'amount');
const feeCurrencyId = this.safeString (trade, 'feeCurrency');
const feeCostString = this.safeString (trade, 'feeAmount');
if (feeCostString !== undefined) {
const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
fee = {
'cost': feeCostString,
'currency': feeCurrencyCode,
};
}
return this.safeTrade ({
'id': id,
'info': trade,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'symbol': symbol,
'order': orderId,
'type': this.safeStringLower (trade, 'type'),
'side': side,
'takerOrMaker': this.safeStringLower (trade, 'matchRole'),
'price': priceString,
'amount': amountString,
'cost': costString,
'fee': fee,
}, market);
}
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name poloniex#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 poloniex api endpoint
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
*/
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
if (limit !== undefined) {
request['limit'] = limit;
}
const trades = await this.publicGetMarketsSymbolTrades (this.extend (request, params));
//
// [
// {
// "id" : "60014521",
// "price" : "23162.94",
// "quantity" : "0.00009",
// "amount" : "2.0846646",
// "takerSide" : "SELL",
// "ts" : 1659684602042,
// "createTime" : 1659684602036
// }
// ]
//
return this.parseTrades (trades, market, since, limit);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name poloniex#fetchMyTrades
* @description fetch all trades made by the user
* @param {string|undefined} symbol unified market symbol
* @param {int|undefined} since the earliest time in ms to fetch trades for
* @param {int|undefined} limit the maximum number of trades structures to retrieve
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html#trade-structure}
*/
await this.loadMarkets ();
let market = undefined;
if (symbol !== undefined) {
market = this.market (symbol);
}
const request = {
// 'from': 12345678, // A 'trade Id'. The query begins at ‘from'.
// 'direction': 'PRE', // PRE, NEXT The direction before or after ‘from'.
};
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = parseInt (limit);
}
const response = await this.privateGetTrades (this.extend (request, params));
//
// [
// {
// "id": "32164924331503616",
// "symbol": "LINK_USDT",
// "accountType": "SPOT",
// "orderId": "32164923987566592",
// "side": "SELL",
// "type": "MARKET",
// "matchRole": "TAKER",
// "createTime": 1648635115525,
// "price": "11",
// "quantity": "0.5",
// "amount": "5.5",
// "feeCurrency": "USDT",
// "feeAmount": "0.007975",
// "pageId": "32164924331503616",
// "clientOrderId": "myOwnId-321"
// }
// ]
//
const result = this.parseTrades (response, market);
return this.filterBySinceLimit (result, since, limit);
}
parseOrderStatus (status) {
const statuses = {
'NEW': 'open',
'PARTIALLY_FILLED': 'open',
'FILLED': 'closed',
'PENDING_CANCEL': 'canceled',
'PARTIALLY_CANCELED': 'canceled',
'CANCELED': 'canceled',
'FAILED': 'canceled',
};
return this.safeString (statuses, status, status);
}
parseOrder (order, market = undefined) {
//
// fetchOpenOrder
//
// {
// "id" : "7xxxxxxxxxxxxxxx6",
// "clientOrderId" : "",
// "symbol" : "ETH_USDT",
// "state" : "NEW",
// "accountType" : "SPOT",
// "side" : "BUY",
// "type" : "LIMIT",
// "timeInForce" : "GTC",
// "quantity" : "0.001",
// "price" : "1600",
// "avgPrice" : "0",
// "amount" : "0",
// "filledQuantity" : "0",
// "filledAmount" : "0",
// "createTime" : 16xxxxxxxxx26,
// "updateTime" : 16xxxxxxxxx36
// }
//
// fetchOpenOrders
//
// {
// "id": "24993088082542592",
// "clientOrderId": "",
// "symbol": "ELON_USDC",
// "state": "NEW",
// "accountType": "SPOT",
// "side": "SELL",
// "type": "MARKET",
// "timeInForce": "GTC",
// "quantity": "1.00",
// "price": "0.00",
// "avgPrice": "0.00",
// "amount": "0.00",
// "filledQuantity": "0.00",
// "filledAmount": "0.00",
// "createTime": 1646925216548,
// "updateTime": 1646925216548
// }
//
// createOrder
//
// {
// "id": "29772698821328896",
// "clientOrderId": "1234Abc"
// }
//
let timestamp = this.safeInteger2 (order, 'timestamp', 'createTime');
if (timestamp === undefined) {
timestamp = this.parse8601 (this.safeString (order, 'date'));
}
const marketId = this.safeString (order, 'symbol');
market = this.safeMarket (marketId, market, '_');
const symbol = market['symbol'];
let resultingTrades = this.safeValue (order, 'resultingTrades');
if (!Array.isArray (resultingTrades)) {
resultingTrades = this.safeValue (resultingTrades, this.safeString (market, 'id', marketId));
}
const price = this.safeString2 (order, 'price', 'rate');
const amount = this.safeString (order, 'quantity');
const filled = this.safeString (order, 'filledQuantity');
const status = this.parseOrderStatus (this.safeString (order, 'state'));
const side = this.safeStringLower (order, 'side');
const rawType = this.safeString (order, 'type');
const type = this.parseOrderType (rawType);
const id = this.safeString2 (order, 'orderNumber', 'id');
let fee = undefined;
const feeCurrency = this.safeString (order, 'tokenFeeCurrency');
let feeCost = undefined;
let feeCurrencyCode = undefined;
const rate = this.safeString (order, 'fee');
if (feeCurrency === undefined) {
feeCurrencyCode = (side === 'buy') ? market['base'] : market['quote'];
} else {
// poloniex accepts a 30% discount to pay fees in TRX
feeCurrencyCode = this.safeCurrencyCode (feeCurrency);
feeCost = this.safeString (order, 'tokenFee');
}
if (feeCost !== undefined) {
fee = {
'rate': rate,
'cost': feeCost,
'currency': feeCurrencyCode,
};
}
const clientOrderId = this.safeString (order, 'clientOrderId');
return this.safeOrder ({
'info': order,
'id': id,
'clientOrderId': clientOrderId,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': this.safeInteger (order, 'updateTime'),
'status': status,
'symbol': symbol,
'type': type,
'timeInForce': this.safeString (order, 'timeInForce'),
'postOnly': undefined,
'side': side,
'price': price,
'stopPrice': undefined,
'cost': undefined,
'average': this.safeString (order, 'avgPrice'),
'amount': amount,
'filled': filled,
'remaining': undefined,
'trades': resultingTrades,
'fee': fee,
}, market);
}
parseOrderType (status) {
const statuses = {
'MARKET': 'market',
'LIMIT': 'limit',
'STOP-LIMIT': 'limit',
'STOP-MARKET': 'market',
};
return this.safeString (statuses, status, status);
}
parseOpenOrders (orders, market, result) {
for (let i = 0; i < orders.length; i++) {
const order = orders[i];
const extended = this.extend (order, {
'status': 'open',
'type': 'limit',
'side': order['type'],
'price': order['rate'],
});
result.push (this.parseOrder (extended, market));
}
return result;
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name poloniex#fetchOpenOrders
* @description fetch all unfilled currently open orders
* @param {string|undefined} symbol unified market symbol
* @param {int|undefined} since the earliest time in ms to fetch open orders for
* @param {int|undefined} limit the maximum number of open orders structures to retrieve
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
await this.loadMarkets ();
let market = undefined;
const request = {};
if (symbol !== undefined) {
market = this.market (symbol);
request['symbol'] = market['id'];
}
if (limit !== undefined) {
request['limit'] = limit;
}
const response = await this.privateGetOrders (this.extend (request, params));
//
// [
// {
// "id" : "7xxxxxxxxxxxxxxx6",
// "clientOrderId" : "",
// "symbol" : "ETH_USDT",
// "state" : "NEW",
// "accountType" : "SPOT",
// "side" : "BUY",
// "type" : "LIMIT",
// "timeInForce" : "GTC",
// "quantity" : "0.001",
// "price" : "1600",
// "avgPrice" : "0",
// "amount" : "0",
// "filledQuantity" : "0",
// "filledAmount" : "0",
// "createTime" : 16xxxxxxxxx26,
// "updateTime" : 16xxxxxxxxx36
// }
// ]
//
const extension = { 'status': 'open' };
return this.parseOrders (response, market, since, limit, extension);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
/**
* @method
* @name poloniex#createOrder
* @description create a trade order
* @param {string} symbol unified symbol of the market to create an order in
* @param {string} type 'market' or 'limit'
* @param {string} side 'buy' or 'sell'
* @param {float} amount how much of currency you want to trade in units of base currency
* @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {object} an [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
// if (type === 'market') {
// throw new ExchangeError (this.id + ' createOrder() does not accept market orders');
// }
await this.loadMarkets ();
const market = this.market (symbol);
let upperCaseType = type.toUpperCase ();
const isMarket = upperCaseType === 'MARKET';
const isPostOnly = this.isPostOnly (isMarket, upperCaseType === 'LIMIT_MAKER', params);
if (isPostOnly) {
upperCaseType = 'LIMIT_MAKER';
params = this.omit (params, 'postOnly');
}
const request = {
'symbol': market['id'],
'side': side,
'type': upperCaseType,
// 'timeInForce': timeInForce,
// 'accountType': 'SPOT',
// 'amount': amount,
};
if (isMarket) {
if (side === 'buy') {
request['amount'] = this.currencyToPrecision (market['quote'], amount);
} else {
request['quantity'] = this.amountToPrecision (symbol, amount);
}
} else {
request['quantity'] = this.amountToPrecision (symbol, amount);
request['price'] = this.priceToPrecision (symbol, price);
}
const clientOrderId = this.safeString (params, 'clientOrderId');
if (clientOrderId !== undefined) {
request['clientOrderId'] = clientOrderId;
params = this.omit (params, 'clientOrderId');
}
// remember the timestamp before issuing the request
let response = await this.privatePostOrders (this.extend (request, params));
//
// {
// "id" : "78923648051920896",
// "clientOrderId" : ""
// }
//
response = this.extend (response, {
'type': side,
});
return this.parseOrder (response, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
/**
* @method
* @name poloniex#cancelOrder
* @description cancels an open order
* @param {string} id order id
* @param {string|undefined} symbol unified symbol of the market the order was made in
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {object} An [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
await this.loadMarkets ();
const request = {};
const clientOrderId = this.safeValue (params, 'clientOrderId');
if (clientOrderId !== undefined) {
id = clientOrderId;
}
request['id'] = id;
params = this.omit (params, 'clientOrderId');
return await this.privateDeleteOrdersId (this.extend (request, params));
}
async cancelAllOrders (symbol = undefined, params = {}) {
/**
* @method
* @name poloniex#cancelAllOrders
* @description cancel all open orders
* @param {string|undefined} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
await this.loadMarkets ();
const request = {
// 'accountTypes': 'SPOT',
};
let market = undefined;
if (symbol !== undefined) {
market = this.market (symbol);
request['symbols'] = [
market['id'],
];
}
const response = await this.privateDeleteOrders (this.extend (request, params));
//
// [
// {
// "orderId" : "78xxxxxxxx80",
// "clientOrderId" : "",
// "state" : "NEW",
// "code" : 200,
// "message" : ""
// }, {
// "orderId" : "78xxxxxxxxx80",
// "clientOrderId" : "",
// "state" : "NEW",
// "code" : 200,
// "message" : ""
// }
// ]
//
return response;
}
async fetchOrder (id, symbol = undefined, params = {}) {
/**
* @method
* @name poloniex#fetchOrder
* @description fetch an order by it's id
* @param {string} id order id
* @param {string|undefined} symbol unified market symbol, default is undefined
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {object} an [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
await this.loadMarkets ();
id = id.toString ();
const request = {
'id': id,
};
const response = await this.privateGetOrdersId (this.extend (request, params));
//
// {
// "id": "21934611974062080",
// "clientOrderId": "123",
// "symbol": "TRX_USDC",
// "state": "NEW",
// "accountType": "SPOT",
// "side": "SELL",
// "type": "LIMIT",
// "timeInForce": "GTC",
// "quantity": "1.00",
// "price": "10.00",
// "avgPrice": "0.00",
// "amount": "0.00",
// "filledQuantity": "0.00",
// "filledAmount": "0.00",
// "createTime": 1646196019020,
// "updateTime": 1646196019020
// }
//
return this.extend (this.parseOrder (response), {
'id': id,
});
}
async fetchOrderStatus (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const orders = await this.fetchOpenOrders (symbol, undefined, undefined, params);
const indexed = this.indexBy (orders, 'id');
return (id in indexed) ? 'open' : 'closed';
}
async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name po